分支基本操作
指令 | 解释 |
---|---|
git branch | 查看本地分支 |
git branch -a | 可以查看本地和远程仓库的分支 |
git branch -vv | 将所有的本地分支列出来并且包含更多的信息,如每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后或是都有。一般需要先git fetch --all 更新远程数据 |
git branch <name> | 创建分支 |
git checkout
<name> git switch<name> |
切换到已有的分支 |
git checkout -b
<name> git switch -c <name> |
创建并切换分支 |
git merge <name> | 将某个分支合并到当前的分支 |
git branch -d <name> | 删除分支 |
git branch -D <name> | 强制删除分支(如果删除一个没有被合并的分支,只能用该指令而不能用-d) |
git checkout -b <本地分支名> origin/<远程分支名> | 在本地创建一个和远程仓库origin中某分支相关联的分支(名字最好是一样的) |
git branch --set-upstream <本地分支名> origin/<远程分支名> | 将本地已经存在的某分支和远程库的某分支建立关联 |
分支合并——merge
我们可以通过git merge <name>
进行两个分支的合并,其效果是将名为<name>
的分支里的内容合并到当前所在的分支上。当我们进行分支合并时,有的时候需要解决冲突,举下面三个例子——
Position 1
如果我们在master分支上新建了一个dev分支,并在dev上修改了一个文件并提交,这样dev分支就比master分支提前一步,如下图所示
此时我们切换到master
分支,并使用指令git merge dev
,此时git就直接将master的指针移动到了dev上,如图
这种模式被称作 快进模式(Fast-forward
),仅仅通过移动指针即可完成,不需要我们进行冲突合并。Position 2
接上例,如果禁用Faster-forward
模式会怎样? 答:Git会自动在master上生成一个新的提交,该提交是两者合并后的结果,然后master指向该次提交,如下图所示
如何禁用Faster-forward
模式呢?我们只需要在当前分支切换到master
后,使用。因为这种合并方式需要在master
上创建一个新的提交,所以需要输入提交描述信息。Position 3
我们再换一个例子。假设master
分支上有一个空文件readme.txt
(已经提交到版本库), 然后我们在master
分支上新建一个dev
分支,这样两个分支都有空文件readme.txt
了- 之后我们切换到在
dev
分支上,在readme.txt
的第一行添加了一句 “dev modify it!”, 保存之后commit到本地仓库。 - 然后我们在切换到
master
分支上,此时readme.txt
还是一个空文件。我们在readme.txt
的第一行添加了一句 “master modify it!”, 保存之后也commit到本地仓库
此时,
master
和dev
两个分支是真的分道扬镳了!如下图所示——
这种情况下,如果在
master
分支中使用指令git merge dev
,则可能产生冲突。因为我们在两个分支上同时对readme.txt
加了一行,但是内容不同,Git并不知道该保存哪个。此时使用merge
命令后,Git会提示我们 “Automatic merge failed; fix conflicts and then commit the result.” 也就是说自动给合并失败了,需要我们手动结局冲突后再次提交。我们打开
readme.txt
,会发现内容变成了
<<<<<<< HEAD master modify it! ======= dev modify it! >>>>>>> dev
此时我们手动修改之后再commit
即可。- 之后我们切换到在
此外,如果在手动合并时出现了失误,我们可以通过git merge --abort
回到合并前的状态。
分支变基——rebase
命令格式
变基命令的一般格式为——
git rebase <basebranch> <topicbranch>
其中
basebranch
是作为新基底的分支,topicbranch
是待变基的分支。当然,如果你想让当前所在的分支作为topicbranch
,可以直接使用git rebase <basebranch>
。
用法解释
git rebase
的官方解释是——"当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。"我们用下面的例子来分析
此时master
指向的是C4
,dev
指向的是C6
,它们的公共祖先是C2
。此时我们在dev
分支上调用命令git rebase master
,Git就会比较C5
、C6
和C2
之间的区别,然后将C5
、C6
较C2
的修改应用在C4
上(即C4
作为新的基底),形成新的提交C5'
和C6'
,最后再将原先的C5
和C6
删掉。其效果相当于将dev
上的两个提交记录(C5
和C6
)拿下来,安到master的最新提交(C4
)上。
操作结果如下图所示——
可以发现,变基实际上就是更改历史,使得提交历史成为一条直线而没有分叉。这样做的好处是能够保持提交历史的整洁性,但是缺点也很明显——丢弃了一些提交记录,如果你的同伴是基于这些记录进行开发,那就会使事情变得很麻烦。
因此,如果正在和同伴协作开发,应该尽量避免使用rebase
。如果真出现了"有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交",我们可以通过两种方法解决(具体可参见《Pro
Git》的相关章节)
-
第一种:先使用get fetch --all
获取同伴使用变基后的提交记录,然后使用get rebase origin/master
(也就是用变基解决变基)。
-
第二种:在下拉时使用git pull --rebase
,而不是使用git pull
。
分支拣选——cherry-pick
Git 中的拣选类似于对特定的某次提交的变基。 它会提取该提交的补丁,之后尝试将其重新应用到当前分支上。 这种方式在你只想引入某个分支中的某个提交,或者某个分支中只有一个提交,而你不想运行变基时很有用。假设你的项目提交历史如下图所示——
此时如果想要将提交e43a6
拉去到master
分支,我们可以先切换到master
分支,然后使用命令git cherry-pick e43a6
。这样一来,master
分支会新增一个提交,结果如下——