Git分支的管理和冲突解决

使用svn,git等做代码版本控制的时候,难免遇到提交冲突。昨天提交代码到GitHub出现冲突不会解决,今天花了一些时间整理了一下Git版本控制的一些内容。

先说一下昨天的情况:

一个Rails的项目,只使用默认的master分支,最后的commit是C3,全部工作都提交到了GitHub,Air和iMac上各有一份。

  1. 之前在Air上修改file1(实际是好几个文件),做commit C4-1,并push到github
  2. iMac也再C3的基础上,修改了file1,做commitC4-2
  3. iMac上进行git push操作,就报冲突了
当时自己有两个问题:
  1. 不清楚git pull操作做了什么,以为git pull会把本地新的修改给覆盖掉
  2. 不用了解merge操作
查了一些资料,对Git有了基本了解:
1. 分支的概念
什么是分支

Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。Git 会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动。

branch

新建一个分支,Git做了什么操作

创建一个新的分支指针。比如新建一个 testing 分支,可以使用 git branch 命令:

 git branch testing

这会在当前 commit 对象上新建一个分支指针

branch-point

Git 是如何知道你当前在哪个分支上工作

它保存着一个名为 HEAD 的特别指针。在 Git 中,它是一个指向你正在工作中的本地分支的指针(译注:将 HEAD 想象为当前分支的别名。)。运行git branch 命令,仅仅是建立了一个新的分支,但不会自动切换到这个分支中去,所以在这个例子中,我们依然还在 master 分支里工作。

head

如何切换分支

要切换到其他分支,可以执行 git checkout 命令。我们现在转换到新建的 testing 分支:

 git checkout testing
2. 分支合并

把一个分支中的修改整合到另一个分支的办法有两种:merge 和 rebase

merge rebase区别
merge

最容易的整合分支的方法是 merge 命令,它会把两个分支最新的快照(C3 和 C4)以及二者最新的共同祖先(C2)进行三方合并,合并的结果是产生一个新的提交对象(C5)

before merge:

before-merge

after merge:

after-merge

rebase

原理是回到两个分支最近的共同祖先,根据当前分支(也就是要进行衍合的分支 experiment)后续的历次提交对象(这里只有一个 C3),生成一系列文件补丁,然后以基底分支(也就是主干分支 master)最后一个提交对象(C4)为新的出发点,逐个应用之前准备好的补丁文件,最后会生成一个新的合并提交对象(C3'),从而改写 experiment 的提交历史,使它成为 master 分支的直接下游

before rebase:

before-rebase

after rebase:

after-rebase

结论:

1. git pull 做了什么操作?会不会覆盖掉本地新增的代码?

不会覆盖本地代码。

git pull = git fetch + git merge

git fetch:

从远程获取最新版本到本地,不会自动merge

git merge:

操作会将代码做合并,遇到冲突会在对应的文件中标记出来冲突,解决冲突,删掉这些标记就可以做正常的commit和push了。

从安全角度出发,git fetch比git pull更安全,因为我们可以先比较本地与远程的区别后,选择性的合并。

2. git pull = git fetch + git merge,为什么执行git fetch 再执行git merge的时候,不能完成merge。

我们进行分支合并的时候git merge + 分支名,操作的是分支。那这里merge操作的对象是什么。

这里涉及到远程分支的概念。假设团队有个地址为 git.ourcompany.com 的 Git 服务器。如果你从这里克隆,Git 会自动为你将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的master 分支的指针,在本地命名为origin/master。接着,Git 建立一个属于你自己的本地 master 分支,始于origin上master分支相同的位置,你可以就此开始工作。

这里origin/master其实就是merge操作的对象。我们执行下面的步骤,就可以提交了:

  1. 先用git fetch origin命令,拉远程分支的内容到本地
  2. 用git merge origin/master命令,合并远程分支的内容到本地master(如果有冲突,解决冲突)
  3. git push提交代码
参考资料(排名分先后):

Git 分支

Whatʼs a Fast Forward Merge

git fetch, merge, pull, push需要注意的地方

Understanding Git: Merging

Neil Wang

产品经理。喜欢摄影,滑板,电影。微信公众号:NeilOnly