您的位置:首页 > 其它

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

2016-04-22 23:05 483 查看

零、需要使用到的命令:

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
pull <远程主机名> <远程分支名>:<本地分支名> 将版本库中的内容取回本地并和<本地分支名>合并(merge合并方式)。
git pull --rebase<远程主机名> <远程分支名>:<本地分支名> 将版本库中的内容取回本地并和<本地分支
名>合并(rebase合并方式)。

git stash 备份当前工作区的内容至git栈,再从最近的一次commit提交覆盖到当前工
作区。
git stash list 显示当前git栈所有的备份
git stash pop 从git栈中恢复一次内容至工作区,默认是恢复最近的一次
git stash clear 清空git栈。

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

先看看分支创建 -> 切换 -> 提交 -> 合并 -> 删除的基本套路吧。
使用上面的几个命令可以实现最基础的分支操作。
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分支了。





Fast forward模式:如果顺着一个分支走下去可以达到另外一个分支的话,那么git合并的时候,就只要简单的把master指针往后移。因为这种单线的操作不需要合并不同的分支,所以不会产生分歧,所以称为Fast forward模式。
普通模式:在一个commit节点发生分支,有两个不同的分支,如果想要合并这两个分支,这个时候不能室友Fast forward模式。往往需要手动修改产生冲突的文件,然后在进行一次commit。

二、合并分支的两种方式

前面使用的是git的merge合并方式,分支还有一种合并方式叫做rebase衍合。
rebase衍合与merge合并最终的结果其实是一样的,但是执行的过程却是不相同的。

merge方式(合并):



看看官方文档里面的示例图,master分支合并experiment分支,将会产生一个新的C5快照,而且只要你不删除experiment分支它就会一直存在。C5分支就像C4和C3两根绳子连在一起样子,这样C5既有了C4的内容,也有了C3的内容

rebase方式(衍合):

rebase流程

(以下图是已经rebase之后的结果图):
1.首先切换到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



rebase的优势和劣势

可以看到当使用rebase方式的时候,产生了C4'快照,这个快照和merge方式得到的快照是一样的。可是不一样的地方还有有的。
1.experiment分支从独立的分支,到和master分支相同的上游去了。
2.C4快照消失了。
乍一看没什么,可是仔细想想,如果你在C4修改了一次重要的操作,可是使用rebase方式合并之后,你的C4却丢失,那么会造成不可忽略的影响。
通过查看文档,rebase方式有优势也有劣势:

优势:

采用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



三、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。存在即为合理,两种不同的方式各有优点,就看实际情况到底如何使用了。

四、无大脑的简单问题测试

问题一: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 pull的时候合并冲突

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

1.git add * 把所有值钱工作的文件放入暂存区。

2.git stash 将文件放入git栈备份

3.git pull origin 将远程库代码拉下来(避免冲突了)

4.git stash pop 将git栈的备份文件拿出来

5.git merge 合并文件

以上是我的一些总结,如果有什么错误的地方欢迎大家指正!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: