Git教程

Git教程

1. Git安装

sudo apt-get install git

2. Git初次配置

git config --global user.name "SHU-FLYMAN"  # 用户名
git config --global user.email "1011836423@qq.com"  # 邮箱

查看自己的信息:

git config --list
--->输出
user.name=SHU-FLYMAN
user.email=1011836423@qq.com

3. Git理论基础

3.1 Git记录的是什么?

3.1.1 SVN等版本控制系统工作原理

SVN等其他版本控制系统工作原理: 记录每一次改动

img


3.1.2 Git版本控制系统工作原理

而Linux采用另外一种方式:

如果每个版本中有任何文件发生变动,Git会将该文件整个复制并且保存起来.

img

这种设计虽然会消耗更多的空间,但在 分支管理 时却带来很多益处和便利。

位于分支 master
无文件要提交,干净的工作区3.2 三棵树-工作区域、暂存区域和Git仓库

img

1. 工作区域(Working Directory): 平时存放项目代码的地方。

2. 暂存区域(Stage): 用于临时存放改动,事实上它只是一个文件,保存即将提交的文件列表信息

3. Git仓库(Repository): 安全存放数据的位置,这里有你提交的 所有版本的数据,其中 HEAD指针 指向 最新放入仓库版本

3.2 工作流程

  1. 在工作目录中 添加、 修改 文件
  2. 将需要进行 版本管理 的文件 放入 暂存区域
  3. 暂存区域 文件 提交到 Git仓库

因此 Git仓库 文件有三种状态:

  1. 修改(modified)
  2. 暂存(staged)
  3. 提交(committed)

3.3 暂存区域作用

为何多增加一个暂存区域?

像某些厂家开发一个产品,一般他们都留有一手,不会把该产品的所有特性一次性发布。通过产品的迭代,每年秋季你就可以开开心心地买到又有一项新功能的“新产品”。

有些时候,你并不想把工作目录中所有的新功能都提交到最新版本,你可以添加一些本次需要提交的文件到暂存区域,然后从暂存区中提交它们。另外,用户在实际工作中,有点修改可以先暂存,不满意可以再修改,方便,如果直接提交到仓库,错了就比较麻烦了,造成提交历史比较混乱。

4. 实战

4.1 初始化Gitgit init

flyman@flyman:~/Desktop/Myproject$ git init
已初始化空的 Git 仓库于 /home/flyman/Desktop/Myproject/.git/

会新建一个.git的隐藏文件,用来跟踪管理版本迭代。

4.2 将文件放入暂存区域git add

在新建完文件README.md之后,

git add README.md

文件已经添加到暂存区域了。

4.3 将文件提交到Git仓库git commit

git commit -m "add a readme file"
flyman@flyman:~/Desktop/Myproject$ git init
已初始化空的 Git 仓库于 /home/flyman/Desktop/Myproject/.git/

Git 告诉你有 1 个文件被改动(README.md),插入了 1 行内容。

  • commit 是提交的意思,-m 选项后边跟着的是本次提交的说明,就是大概描述这一版本做了哪些改动,以便今后可以迅速查看。
  • 对于这个提交的说明,Git 是强制要求你必须写的。如果没有使用 -m 选项,Git 会自动打开一个编辑器,要求你在其中输入提交说明,输入完毕后保存退出即可(操作命令与 vim 编辑器一致)

4.4 总结

总结一下,将工作目录的文件放到 Git 仓库只需要两步:

  1. Step One -> git add 文件名
  2. Step Two -> git commit -m "你干了啥"

4.5 Github克隆仓库git clone http...

除了在空文件夹中初始Git,Git还允许你克隆一个现有的仓库,直接输入git clone 目标命令即可:

git clone https://github.com/n0tr00t/Sreg

源码将会全部拷贝在当前路径的文件夹中。

5. 工作区域新增或修改文件

5.1 查看状态git status

一个项目有百把十个文件,怎么知道那些文件是新添加的,那些文件已经加入到了暂存区域呢?

git status
---
位于分支 master
无文件要提交,干净的工作区

因为在上次commit之前,工作目录没有发生改动。

在工作区发生修改之后,例如添加了一个LICENCE.md文件,再次执行命令

git status
---
位于分支 master
未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	LICENSE.md

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)

5.2 使用git add提交到暂存区域:

git add LICENCE.md
git status
---
位于分支 master
要提交的变更:
  (使用 "git reset HEAD <文件>..." 以取消暂存)

	新文件:   LICENSE.md

5.3 用暂存区域旧一版的文件覆盖工作区域git checkout --文件

git checkout -- <文件>

git checkout -- <文件> 丢弃工作区改动,用 暂存区域 旧一版 的 文件 覆盖 工作区域

5.4 反悔提交到暂存区域git reset HEAD 文件名

可以使用git reset HEAD <文件名>恢复暂存区域,取消提交到暂存区域。

git reset HEAD <文件>
git reset HEAD 123456.md
位于分支 feature
未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	123456.md

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)

5.5 一步到位git commit -am

git commit -am "change the license file"
  • -a Git会自动讲工作目录中所有 已跟踪 的文件 先 add 到暂存区域,然后执行 commit命令

6. 回到过去git reset

img

  • git add工作目录 的文件放入 暂存区域
  • git commit暂存区域 的文件提交到 Git仓库
  • git resetGit仓库 的文件还原到 暂存区域
  • git checkout暂存区域 的文件还原到 工作目录

6.1 查看Git仓库版本

git log
---
commit 460adf3376ca914c770913316ce60b6c1e497b8e (HEAD -> master)
Author: SHU-FLYMAN <1011836423@qq.com>
Date:   Fri Oct 19 09:18:15 2018 +0800

    add a LICENCE

commit 2a121fabd13b317303b7ba88b0e844a3ca0dc487
Author: SHU-FLYMAN <1011836423@qq.com>
Date:   Thu Oct 18 19:25:00 2018 +0800

    add a readme file

假设根据Git记录,将Git仓库可视化:

img

三颗树

img

6.2 git reset命令

6.2.1 回滚快照

快照即提交的版本,每个版本我们称之为 快照

执行git reset HEAD~

git reset HEAD~

Git仓库

img

HEAD指针指向了前一版本快照

三颗树

三棵树变成了这样:

img

  1. 首先是移动 HEAD 的指向,将其指向上一个快照(HEAD~)
  2. 然后再将该位置的快照回滚到暂存区域
  • --soft选项——只移动HEAD指向,但不会将快照回滚到 暂存区域,事实上 撤销了上一次的提交,使用git log命令将无法看到已经撤销了的那个提交

    git reset --soft HEAD~
    
  • --hard选项——还会将 暂存区域 的文件 还原到 工作目录

6.2.2 回滚指定快照git reset 00c2929

如果快照比较多,你又懒得去数有多少个“上”,那么你可以通过指定具体的快照 ID 来回滚该快照。

git reset 00c2929  # 没有必要将全部 ID 号都给输入进去,一般只要输入前几位

6.2.3 回滚个别文件git reset 快照号 文件名

reset不仅可以回滚指定快照,还可以回滚个别文件:

git reset 快照 文件名/路径
  • 它会忽略HEAD的指向这一步(因为你只是回滚快照的部分内容,并不是整个快照,索引HEAD的指向不应该发生变化),
  • 直接将指定快照的 指定文件 回滚到 暂存区域

6.2.4 往前回滚git reset ID

往前回滚的唯一前提:知道指定快照的 ID 号

通过git reflog查看每一次操作记录,前面即有id号

git reflog
---
2a121fa (HEAD -> master) HEAD@{0}: reset: moving to HEAD~
460adf3 HEAD@{1}: commit: add a LICENCE
2a121fa (HEAD -> master) HEAD@{2}: commit (initial): add a readme file

然后

git reset 00c2929

7. 版本对比

  1. 创建 README.mdgame.py 文件,并将其添加到暂存区域,接着执行git commit -m “猜数字游戏” 提交项目的第一个快照

    git add README.md game.py
    git commit -m "猜数字游戏"
    
  2. 修改代码

7.1 比较暂存区域与工作目录git diff

7.1.1 窗口内容解读

git diff 比较 暂存区域工作目录 的文件内容。

git diff

diff 是Linux系统上非常重要的工具,用于比较文件的内容。特别是比较两个版本不同的文件内容以找到 改动 的地方。

  1. 第一行 diff --git a/README.md b/README.md,表示存在 暂存区域README.md 文件和 工作目录README.md 文件

  2. 第二行:index 79668377..142a180 100644

    • 79668377——第一个文件的ID
    • 472a180——第二个文件的ID
    • 100644——指定文件的类型和权限
  3. 第三行:--- a/README.md

    • ---表示该文件是 旧文件 (存放在 暂存区域)
  4. 第四行:+++ b/README.md

    • +++表示该文件是 新文件 (存放在 工作区域)
  5. 第五行:@@ -1 +1,2 @@

    @@开头和结尾,中间的-代表旧文件,+代表新文件,后边的数字表示 开始行号,显示行数

  6. 第6-7行:

    这是将两个文件合并显示的结果:

    • 有个+绿色 的那一行说明是新文件独有的
    • 浅灰色 的 则是两个文件所共有的内容
  7. 所以+1,2表示新文件在合并显示中以第 1 行开始,显示 2 行

为什么-1后面没有显示行数,因为在合并显示的结果中,旧文件已经完全包含在新文件中了,因此旧文件没有自己“独有的内容“

  1. \Non newline at the end of file : Git提醒文件不是以换行符结束。最后空一行是编程的一个好习惯。

7.1.2 常用命令

  • 移动命令

    • j向下移动一行,k向上移动一行
    • f向下移动一页,b向上移动一页
  • 跳转命令

    • g第一行,G最后一行
    • 先按下3,再按g,则表示去第 3 行
  • 搜索命令

    输入/(从当前位置向下搜索)或者(从当前位置向下搜索),后面跟上搜索的关键字,按下回车,所有关键字均高亮显示

7.2 比较两个历史快照git diff 6e2697 ed3708c

执行git log看到Git仓库中已经有两个快照了

执行git diff 6e2697 ed3708c即可比较Git仓库中两个快照的差异

7.3 比较当前工作目录和Git仓库的快照git diff ed3808c

Git仓库:

三棵树:

如果希望比较第一份 快照ed3808c当前工作目录 的内容差异,输入git diff ed3708c命令即可:

如果希望比较 最新提交的快照当前工作目录 之间的差异,输入git diff HEAD

7.4 比较暂存区域和Git仓库快照git diff -cached

三棵树:

如果希望比较 最新快照暂存区域 的文件,只需要执行git diff --cached 命令

当然也可以指定 其他快照,就需要多写一个ID号,git diff --cached ed3708c

7.5 总结

8. 开发中常见情况

8.1 重新提交最后次提交git commit --amend

实际开发中,你可能遇到下面这两种情况:

  1. 版本刚一提交commitGit仓库,突然想到 漏掉 两个文件没有add暂存区域,这就好比你是老司机,开车开到终点站发现乘客还没有上车。
  2. 版本刚一提交commitGit仓库,突然想起来,版本说明 写得不够全面,无法彰显你本次修改的重大意义

我们可以reset回到过去,但这就好像我们打游戏打不过Boss,退回最新存档重练的感觉,会有记录。有没有一步到位的方法呢?

git commit --amendGit会用 暂存区域的文件 更正最新的一次提交


上一次修改后,三棵树的样子是这样的:

这时,我们希望将暂存区域的REMEDE.md文件进行提交,但没有必要 增加 一个 新的版本,怎么办?

  1. 如果需要 修改 提交说明 使用git commit --amend filename -m “新的提交说明”命令,Git仓库不会新增加新版本
  2. 暂存区域 的内容也提交上去了

工作原理:其实相当于重新提交最后次修改,不在Git上保留记录

8.2 删除文件git rm 文件名

  1. git rm yellow.jpgrm只删除工作目录和暂存区域的文件,即取消跟踪,下次提交不纳入版本管理
  2. git reset --soft HEAD! 将快照回滚到上一个位置

工作目录暂存目录文件不一致时,Git会提醒,可以以下处理:

  1. git rm -f test.py 将两个文件 同时删除
  2. git rm –cached 只删除 暂存区域文件

8.3 重命名文件git mv a b

git mv game.py wordgame.py,原理和Linux系统一样,通过移动来重命名。

8.4 忽略跟踪一些指定文件.gitignore

现在工作目录有1.temp2.temp3.temp,我们不希望后缀名为temp的文件被跟踪:

可以新建一个.gitignore文件,然后在里面添加忽略内容,.gitignore语法如下:

  • 所有 空行 或者以注释# 开头的行都会被Git忽略
  • 星号 * 匹配零个或者多个任意字符
  • [abc]匹配任何一个列在方括号中的字符
  • 问号?只匹配一个任意字符
  • [a-z]匹配所有在这两个范围内的字符
  • 匹配模式最后跟反斜杠/ 说明 要忽略的是目录
  • 匹配模式以反斜杠/开头,说明防止递归
  • 要忽略指定模式以外的文件或目录,可以在模式前加上感叹号取反

9. 创建和切换分支

9.1 分支是什么?

假如你的大项目已经上限了(有成千上百的人在用),过了一段时间你觉得应该 添加新功能,但为了 保险 起见,你肯定不能在当前项目上直接开发,这时候你就需要另起炉灶(创建分支)了。

9.2 创建分支git branche 分支名

假设Git仓库现在是这个样子,可以看到 README.md文件被 修改,并添加到 暂存区域,但还没有被提交,三棵树:

我们开始 创建分支git branch 分支名:

git branch feature  # 没有任何提示说明分支创建成功,除非创建同名分支,它才会提醒

使用git log --decorate查看:

希望精简地看,可以使用git log --decorate --online,它的意思是:

  • 目前有两个分支,一个主分支master,另一个feature分支
  • HEAD指针指向默认的master分支

目前仓库快照应该是这样的:

9.3 切换分支git checkout 分支名

现在我们需要将工作环境切换到新创建的分支feature上来,使用checkout命令:

git checkout feature

这样HEAD指针就指向了feature分支:

使用git log --dcorate –oneline查看:

我们再进行一次提交,暂存区域还有个文件修改没有提交:

现在仓库中的快照应该是这样的:

然后我们将HEAD指针切回master分支:

发现 上一次对README.md文件修改当然无存,仓库就变成这样了:

如果再对README.md进行修改,然后再次执行git commit -m “再次修改说明文件”:

仓库快照就会这样:

使用git log --oneline --decorate --graph --all命令查看:

9.4 直接创建并切换分支

其实还可以用git cheackout -b feature2 直接创建并切换分支。

10. Git实际工作流程

Git 工作流使用一个 中间仓库 作为 所有开发者 的交流地点,开发程序者在本地工作,然后将各自的 分支 推送到 中间仓库

10.1 开发分支(develop)

代替单一的master分支,上图的工作流使用了两个分支来处理 项目发布日常开发

  • master主分支通常只用于对外发布项目的版本,日常开发应该在另外条分支上完成
  • 我们把开发的分支称为devolop分支

10.2 功能分支(feature)

每个新功能都应该用单独的一个 功能分支 进行开发,功能分支 应该从 开发分支 中分离出来,功能开发完成后再合并到开发分支中。

  • 功能分支不应该跟master分支有任何交流的机会
  • 功能分支用feature-*的形式命名

10.3 预发布分支(release)

在项目正式发布之前,你可能需要一个 预发布 的版本进行 测试,于是你可以从 开发分支中分离出 预发布分支,用于内部或公开分支。

  • 预发布分支 应该同时合并到主分支和开发分支中
  • 预发布分支 可以用release-*的形式命名

10.4 维护分支(hotfix)

项目正式发布之后,难免出现bug,这时就需要创建一个分支,进行bug的修补,称为 维护分支

  • 维护分支 应该从 主分支 中分离出来,bug被修补后,再 合并主分支开发分支
  • 维护分支hotfix-*的形式命名

10.5 常设分支与临时分支

常设分支

  1. 主分支master
  2. 开发分支devolop

其余分支 属于 临时分支,用完之后应该及时删除:

  1. 功能分支feature
  2. 预发布分支release
  3. 维护分支hotfix

10.6 正式开发GIt分支管理

11. 合并和删除分支

Git仓库里,所有快照事实上都是按照提交时间排放的,我们把串联这些快照的 **时间轴 ** 称为 分支,默认情况下,Git只有一条 master 主分支。但在实际开发中,一条分支根本不够用,实际分支张这样:

一个项目根据需求会产生很多分支,但最终都会被合并回去。

11.1 有冲突的分支合并

当一个子分支的实名结束之后,它就应该回归到主分支中去。加入分支状态是这样的:

11.1.1 git merge 分支名

合并分支我们用git merge 分支名:

git merge feature # 会将该分支合并到HEAD指针指向的分支

Git提示的内容来看,我们知道这次合并并没有成功,Git说:

  1. 合并REMEAD.md文件的时候出现冲突
  2. 自动合并失败,请修改冲突的内容,并重新提交快照

意思是:

  • 你需要先解决冲突的问题,Git才能够进行合并操作。
  • 所谓冲突,就像两个分支中存在同名但内容却不同的文件,Git不知道你要舍弃哪个或者保留哪个,需要你自己来做决定。

11.1.2 解决冲突

这时执行git status命令会显示你要解决的冲突:

Git会在有冲突的文件中加入一些标记,打开README.md文件:

  • =====为界
  • 上到<<<<<<<<HEAD的内容表示当前分支
  • 下到>>>>>>>>feature的内容表示待合并的feature分支
  • 之间的内容即冲突的地方

我们将内容修改为:

《零基础入门学习Python》第004讲
课后作业:文字游戏

Power by www.FishC.com      

11.1.3 提交快照,add/commit

保存文件,然后提交快照:

git add README.md
git commit -m "解决冲突"

其实就是利用git merge feature比较两个分支差异,然后处理差异,之后将处理好的文件提交上去,形成新版本的快照。

自动合并

执行git log --decorate --all -graph --oneline命令,显示此时的分支已经 自动合并。当然如果不存在冲突,则不需要搞那么多。

11.2 没有冲突的合并

执行git checkout -b feature2,相当于执行git brance feature2git checkout feature2两步,然后新建一个文件feature2.txt,并提交快照。执行gitlog --decorate --all --graph --online命令:

我们看到,feature2分支比master分支快了一步,现在我们切换回master分支,并且将feature2分支合并进来:

git checkout maseter
git merge feature2

Git只显示了快进Fast-forward,因为;

  • feature2这个分支的 父节点master分支,所以Git只要简单地移动master指向即可

执行git log --decorate --all --graph --oneline变成了:

11.3 删除分支git branch -d 分支名

对于不需要的分支,我们将它删除比较好,否则版本管理太乱了。使用git branch -d 分支名来删除:

11.4 自动三方合并

11.4.1 Fast-forward

当 待合并的分支 位于 目标分支的直接上游,Git 只需要把目标分支的指针直接移动即可实现合并

例如下面图片:master分支位于feature2分支的直接上游

feature2分支合并到master分支,只需要移动master分支指针即可:

11.4.2 三方合并

如果待合并的两个分支不再同一条线上,那么进行合并就需要解决一个根本的问题——冲突

为什么在同一条线上就不会冲突呢?

不同命文件冲突

因为Git的快照是按时间顺序提交的,所以同一条线上两个快照,它们是有先后顺序的,尽管两者可能出现同名文件不同内容,Git会认为这是 改变 而不是 冲突

合并C3C4得到C5,但C5应该如何解决冲突呢?它会找到第三个快照,就是共同祖先,一比较,发现C3增加了test1c4增加了test2,因此C5是三种合体,因此不存在冲突。

同名文件不同更改

Git找到共同祖先C1,可以看到:

  • C4在第二行添加了1
  • C3在第4行添加了FishC
  • love第三行共同拥有

因此在每一行并没有产生冲突,所以自动合并后C5是这样的:

# test.txt
I
love
FishC

如果Git检测到同一行有不同内容,还是会报冲突让你自行决定谁去谁留

12. checkout注意事项

checkout命令有两个功能:

  1. 从历史快照(或者暂存区域)中拷贝文件到工作目录,git checkout README.md,没有指定具体的快照ID则从暂存区域恢复指定文件到工作目录
  2. 切换分支

注意

  • 恢复用reset更安全,将上一版本的快照恢复到暂存区域,再checkout回来。

  • 涉及工作区域的操作要注意,如果没有commit,Git没有操作可以恢复。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值