趣文天下AndroidDevGit

分布式版本控制系统Git------分支管理与合并(merge与

2017-01-31  本文已影响387人  aroundme

前言

这篇文章是我16年4月写的,当时发布在CSDN上。被Git知识库收录。
链接:
http://blog.csdn.net/aroundme/article/details/51223687

现在想想之前的排版(没有用MarkDown)和一些语句以及文章整体结构有点问题,所以这次就使用MarkDown重新编辑,放在简书。

0、需要使用到的命令:

        git branch                           查看当前分支。

        git branch <name>                    创建一个名为<name>的分支。

        git checkout <name>                  切换到名字为<name>的分支。

        git checkout -b <nama>               创建一个名为<name>的分支,并且切换到此分支
                                             (等于git branch <name>命令 + git checkout <name>命令)。

        git merge <name>                     把一个名为<name>的分支合并到当前分支。

        git branch -d <name>                 删除一个名为dev的分支。

        git merge   <分支名>                  把<分支名>合并到当前分支

        git rebase   <分支名>                 把<分支名>合并到当前分支(与merge不同)

        git fetch<主机名> <分支名>             将版本库中的内容取回本地

        git stash                            备份当前工作区的内容至git栈,再从最近的一次commit提交覆盖到当前工作区。
        git stash list                       显示当前git栈所有的备份
        git stash pop                        从git栈中恢复一次内容至工作区,默认是恢复最近的一次
        git stash clear                      清空git栈。
        
        git pull <远程主机名> <远程分支名>:<本地分支名> 
        将版本库中的内容取回本地并和<本地分支名>合并(merge合并方式)。
        
        git pull --rebase<远程主机名> <远程分支名>:<本地分支名>         
        将版本库中的内容取回本地并和<本地分支名>合并(rebase合并方式)。 
        
        
        

1、简单介绍一下分支的基本操作。

先看看分支创建 -> 切换 -> 提交 -> 合并 -> 删除的基本套路吧。

使用上面的几个命令可以实现最基础的分支操作。

下面是例子(截图丑翔见谅)

当前有两个分支,分别是master和gzl。

git提示当前已经切换到分支gzl。

这个时候的打开master分支的test.txt文件看看

发现test.txt文件回到了没有更改的之前的内容。这是因为我们修改是在gzl分支的,而不是master分支。
可以将分支看成一个个平行空间,你在其中修改并不会影响到其他分支的内容。

这里采用的Fast-forward合并方式,即快速合并。也就是说,只是把master指向了gzl分支。

再用git branch 命令查看,发现只剩下了master分支了。

2、两种合并模式

3、合并分支的两种方式

前面使用的是git的merge合并方式,分支还有一种合并方式叫做rebase合并。

rebase合并与merge合并最终的结果其实是一样的,但是执行的过程却是不相同的。

merge方式(合并):

看看官方文档里面的示例图,master分支合并experiment分支,将会产生一个新的C5快照,而且只要你不删除experiment分支它就会一直存在。

rebase方式(衍合):

rebase流程:

  1. Git首先切换到C4所在的experiment分支。
  2. 从C4开始向前找,直到找到和master分支最近的一个相同commit快照,C4和C4之前的所有commit快照生成patch文件。
  3. 强制转化到master分支,从C2开始,将上面生成的patch文件,从C2开始往下一个一个打上patch文件。
  4. 最后生成新的C4‘commit快照,它之前所在的分支experiment也随着它的改变指向了master的上游。最后可以使用Fast forward方式让master分支和experiment保持一致。

注意: rabase在第三步之中会发生冲突。

在这种情况下,Git会停止rebase并会让你去解决冲突,在解决完冲突后,用"git-add"命令去更新这些内容的索引(index),然后,你无需执行 git-commit,只要执行:

 git rebase --continue

这样git会继续应用(apply)余下的补丁。

在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。

git rebase --abort

4、Rebase的优势和劣势

可以看到当使用rebase方式的时候,产生了C4'快照,这个快照和merge方式得到的快照是一样的。可是不一样的地方还是有的。

  1. experiment分支从独立的分支,到和master分支相同的上游去了。
  2. C4快照消失了。乍一看没什么,可是仔细想想,如果你在C4修改了一次重要的操作,可是使用rebase方式合并之后,你的C4却丢失,那么会造成不可忽略的影响。

通过查看文档,得到rebase相对于merge的优劣比较:

Do not rebase commits that exist outside your repository.

为什么会这样,文档上的例子很生动,我大概翻译一下(粗体为翻译):

**如果你rebase一个文件,放弃了目前的修改,然后创建了一个新的看起来相同可是内容却不同的快照一 。如果你将这个快照放到网上或者其他地方,别人pull下了它,然后按照这个为基准进行工作。这个时候你又重写了它并且使用了git rebase方法把它上传到了网上称为 快照二,你的同事将会被这个新的快照搞得头昏眼花。因为他们是基于你第一次快照来进行开发的,可是你使用rebase命令之后,你的快照一将会消失,那么你同事做的事情就会白费。
**

那么如果你面临这样的情况,改怎么办呢?别担心,还是有机会挽回损失的。

如果你面临这样的困难,那么你所面临的第一个挑战就是分辨出哪些是你写的,哪些是你同事写的。
原来commit 对象除了SHA-1计算校验之外,Git还基于你引进的补丁计算了一种校验码,叫做“patch-id”。
如果你从你同事那里拉下重改的代码是基于最新的一次提交,Git也能也能够成功的解决而且申请它回到一个新的分支上。
使用git rebase teamone/master命令。
1.找到唯一工作在分支上的commit快照。
2.找到没有合并的commit快照。
3.找到没有被改写的commit快照加入目标分支。
4.应用这些commit快照在master分支和teamone分支。

但是它只工作在旧commit快照C4和新快照C4’有着差不多的补丁,否则衍合就不能够分辨C4'是C4的复制快照。这样的话就会添加一个新的C4 ''的补丁文件(这将会导致衍合失败,而且这样的话会导致一些不可预料的变化)。
你也可以用git pull --rebase命令来代替平常的git pull命令。

附上git文档里面的最后一段,关于什么时候使用rebase和merge


5、git pull 和 git pull --rebase

先说说git pull命令。
git push是把本地文件上传至远程库的命令。那么自然而然就有把远程库的文件拉下来放到本地工作区的命令,这个命令就是git fetch命令。git fetch所做的只是把远程库的文件获取到本地。

git pull = git fetch + git merge。

如果后面加上--rebase参数。

git pull --rebase命令

表示把你的本地当前分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把本地当前分支更新 为最新的"origin"分支,最后把保存的这些补丁应用到本地当前分支上。
其实

git pull --rebase = git fetch  + git rebase。

浏览了一些博客,发现大多数博主都有个提醒的地方:尽量少使用git pull或者git pull --rebase命令,多使用git fetch命令 + git pull命令或者git fetch命令 + git rebase命令。因为逐步执行可以保证文件的安全性。直接git pull会隐藏一些细节,或许这些细节就是你所需要的。

而到底是使用git pull还是使用git pull --rebase,其实也就是面临是选择git merge还是git rebase合并一样的情景。git merge可以保存所有的commit记录方便之后的使用,而git rebase是为了有一条清晰明朗的主线,避免无谓的commit。存在即为合理,两种不同的方式各有优点,就看实际情况到底如何使用了。

Tips

1. git blame 防甩锅神器

如果你要查看文件的每个部分是谁修改的, 那么 git blame 就是不二选择. 只要运行'git blame [filename]', 你就会得到整个文件的每一行的详细修改信息:包括SHA串,日期和作者:

git blame [filename]

一行命令显示文件每一行是谁修改的,一目了然,妈妈再也不用担心我被甩锅了

2. git stash 保存进度暂存区

你工作做到一半,突然有个bug要放下手上的活儿去解决bug。可是直接pull会丢失你这几天的辛辛苦苦工作。下面几个步骤搞定。

  1. git add * 把所有值钱工作的文件放入暂存区。
  2. git stash 将文件放入git栈备份
  3. git pull origin 将远程库代码拉下来(避免冲突)
  4. git stash pop 将git栈的备份文件拿出来
  5. git merge 合并文件

简单测试

其实看到前面大概就已经够了,不过我还是打算把测试放上去,一个实际的问题能够更好的消化上面的内容

问题:git merge 分支的时候,合并冲突。

情景再现:在分支修改了某个文件之后,回到master分支想要将两个分支合并。因为某个文件内容不一样,出现了


git告诉你合并失败因为有一个未合并的文件。这个时候应该在工作区打开文件,手动修改,在使用add,commit命令,最后使用git merge命令最后才能成功的合并。
盗取廖雪峰老师的图来解释一下应该会更清楚点:

1.你修改了两个不同分支相同的文件,这个文件在不同分支内容是不同的,不能使用快速合并了。


2.这个时候你手动修改了这个文件,使用git merge命令发现出现下面的提示。


解决方法:手动修改未合并的文件,再次add,commit。合并之后相当于多了一次提交。改变图如下:



结论:如果merge的时候使用的是Fast forward模式,git只是将mater的分支移到另外一个分支上。如果没有使用Fast forward模式(普通模式),Git会产生一个新的commit。Fast forward模式合并之后是没有分支记录的,普通模式是用分支记录的。

上一篇下一篇

猜你喜欢

热点阅读