美文网首页趣文天下AndroidDevGit
分布式版本控制系统Git------分支管理与合并(merge与

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

作者: aroundme | 来源:发表于2017-01-31 18:27 被阅读387次

    前言

    这篇文章是我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、简单介绍一下分支的基本操作。

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

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

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

    • 1.创建分支:git branch name


    • 2.查看当前所有分支:git branch


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

    • 3.切换分支:git checkout name


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

    • 4.在分支上修改文件或者添加一个新的文件,在分支上进行一个commit。


    • 5.回到master分支:git checkout master

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

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

    • 6.合并gzl分支的内容到master分支 :git merge gzl

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

    • 7.删除gzl分支:git branch -d gzl


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

    2、两种合并模式

    • Fast forward模式:
      如果顺着一个分支走下去可以达到另外一个分支的话,那么git合并的时候,就只要简单的把master指针往后移。因为这种单线的操作不需要合并不同的分支,所以不会产生分歧,所以称为Fast forward模式。

    • 普通模式:
      在一个commit节点发生分支,有两个不同的分支,如果想要合并这两个分支,这个时候不能室友Fast forward模式。往往需要手动修改产生冲突的文件,然后在进行一次commit。

    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的优劣比较:

    • 优势:
      采用rebase方式合并的快照,在主分支上看起来就像是一条平行线一样整洁干净,让人一目了然,这样管理人员就不需要花费时间去整理分 分支了。
    • 劣势:
      就像上张图那样,采用rebase方式合并之后,以前的分支的快照都会消失。引用文档的概括的一句话------
    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模式合并之后是没有分支记录的,普通模式是用分支记录的。

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/eclkittx.html