分支
什么是分支
分支是为了将修改记录的整体流程分叉保存。分叉后的分支不受其他分支的影响,所以在同一个数据库里可以同时进行多个修改。
master分支
在数据库进行最初的提交后, Git会创建一个名为master的分支。因此之后的提交,在切换分支之前都会添加到master分支里。
分支的运用
merge分支
Merge分支是为了可以随时发布release而创建的分支,它还能作为Topic分支的源分支使用。保持分支稳定的状态是很重要的。如果要进行更改,通常先创建Topic分支,而针对该分支,可以使用Jenkins之类的CI工具进行自动化编译以及测试。
通常,大家会将master分支当作Merge分支使用。
Topic分支
Topic分支是为了开发新功能或修复Bug等任务而建立的分支。若要同时进行多个的任务,请创建多个的Topic分支。
Topic分支是从稳定的Merge分支创建的。完成作业后,要把Topic分支合并回Merge分支。
分支的切换
若要切换作业的分支,就要进行checkout操作。进行checkout时,git会从工作树还原向目标分支提交的修改内容。checkout之后的提交记录将被追加到目标分支
HEAD
HEAD指向的是现在使用中的分支的最后一次更新。通常默认指向master分支的最后一次更新。通过移动HEAD,就可以变更使用的分支。
NOTE:提交时使用~(tilde)和^(caret)就可以指定某个提交的相对位置。最常用的就是相对于HEAD的位置。HEAD后面加上~(tilde)可以指定HEAD之前的提交记录。合并分支会有多个根节点,您可以用^(caret) 来指定使用哪个为根节点。
stash
stash是临时保存文件修改内容的区域。stash可以暂时保存工作树和索引里还没提交的修改内容,您可以事后再取出暂存的修改,应用到原先的分支或其他的分支上。
分支的合并
合并分支有2种方法:使用merge或rebase。使用这2种方法,合并后分支的历史记录会有很大的差别。
merge
合并 bugfix分支到master分支时,如果master分支的状态没有被更改过,把master分支的位置移动到bugfix的最新分支上,Git 就会合并。这样的合并被称为fast-forward(快进)合并。HEAD还在原位。
master分支的历史记录有可能在bugfix分支分叉出去后有新的更新。这种情况下,要把master分支的修改内容和bugfix分支的修改内容汇合起来。合并两个修改会生成一个提交。这时,master分支的HEAD会移动到该提交上。
NOTE:执行合并时,如果设定了non fast-forward选项,即使在能够fast-forward合并的情况下也会生成新的提交并合并。
一个圆圈代表一个提交
rebase
topic分支和merge分支的运用实例
分支操作示例
建立分支
$ git branch < branchname>
不指定参数直接执行branch命令的话,可以显示分支列表。 前面有*的就是现在的分支。
$ git branch
issue1
*master
切换分支
执行checkout命令以退出分支。
$ git checkout < branch>
NOTE:在checkout命令指定 -b选项执行,可以创建分支并进行切换。
$ git checkout -b < branch>
合并分支
执行merge命令以合并分支。
$ git merge < commit>
该命令将指定分支导入到HEAD指定的分支。如当HEAD指向issue1时,先切换到master分支,然后把issue1分支导入到master分支。
$ git checkout master
$ git merge issue1
删除分支
在branch命令指定-d选项执行,以删除分支。
$ git branch -d < branchname>
用rebase合并
切换到issue3分支后,对master执行rebase。
$ git checkout issue3
$ git rebase master
rebase的时候,修改冲突后的提交不是使用commit命令,而是执行rebase命令指定 –continue选项。若要取消rebase,指定 –abort选项。
$ git add myfile.txt
$ git rebase –continue
这样,在master分支的issue3分支就可以fast-forward合并了。切换到master分支后执行合并.看来rebase是将issue3分支消失而生成一个新的提交,就像fast-forward的情形一样。
切换到master分支后执行合并。
$ git checkout master
$ git merge issue3
上图为rebase图
上图为merge图
Merge和rebase都是合并历史记录,但是各自的特征不同。
merge
保持修改内容的历史记录,但是历史记录会很复杂。
rebase
历史记录简单,是在原有提交的基础上将差异内容反映进去。
因此,可能导致原本的提交内容无法正常运行。
您可以根据开发团队的需要分别使用merge和rebase。
例如,想简化历史记录,
在topic分支中更新merge分支的最新代码,请使用rebase。
向merge分支导入topic分支的话,先使用rebase,再使用merge。
远端数据库
pull
首先确认更新的本地数据库分支没有任何的更改。这时只执行fast-forward合并。
如果本地数据库的分支有新的历史记录,就需要合并双方的修改。
执行pull就可以进行合并。这时,如果没有冲突的修改,就会自动创建合并提交。如果发生冲突的话,要先解决冲突,再手动提交。
fetch
执行pull,远程数据库的内容就会自动合并。但是,有时只是想确认本地数据库的内容而不想合并。这种情况下,请使用fetch。
执行fetch就可以取得远程数据库的最新历史记录。取得的提交会导入到没有名字的分支,这个分支可以从名为FETCH_HEAD的退出。
就相当于在本地数据库建立了一个和远程数据库一样的分支,还没合并。
合并后,历史记录会和pull相同。实际上pull的内容是fetch + merge组成的。
push
从本地数据库push到远程数据库时,要fast-forward合并push的分支。如果发生冲突,push会被拒绝的。
若要共享在本地数据库创建的分支,需要明确的push。因此,没有执行push就不会给远程数据库带来影响,因而可以自由的创建自己的分支。
基本上,远程数据库共享的提交是不能修改的。如果修改的话,跟远程数据库同步的其他数据库的历史记录会变得很奇怪的。
标签
标签是为了更方便地参考提交而给它标上易懂的名称。
Git可以使用2种标签:轻标签和注解标签。打上的标签是固定的,不能像分支那样可以移动位置。
轻标签:添加名称
注解标签:添加名称 添加注解 添加签名
一般情况下,发布标签是采用注解标签来添加注解或签名的。轻标签是为了在本地暂时使用或一次性使用。
使用标签
使用tag命令来添加标签,在< tagname>执行标签的名称。
$ git tag < tagname>
在HEAD指向的提交里添加名为apple的标签,请执行以下的命令。
$ git tag apple
如果没有使用参数而执行tag,可以显示标签列表。
$ git tag
如果在log命令添加 –decorate选项执行,可以显示包含标签资料的历史记录。
$ git log –decorate
添加注解标签
若要添加注解标签,可以在tag命令指定 -a选项执行,以指定-m选项来添加注解。
$ git tag -a < tagname>
$ git tag -am “连猴子都懂的Git” banana
如果在tag命令指定-n选项执行,可以显示标签的列表和注解。
$ git tag -n
删除标签
若要删除标签,在tag命令指定 -d选项执行。
$ git tag -d < tagname>
改写提交
修改最近的提交
指定amend选项执行提交的话,可以修改同一个分支最近的提交内容和注解。
主要使用的场合:
添加最近提交时漏掉的档案
修改最近提交的注解
取消过去的提交
在revert可以取消指定的提交内容。使用后面要提到的rebase -i或reset也可以删除提交。但是,不能随便删除已经发布的提交,这时需要通过revert创建要否定的提交。
主要使用的场合:
安全地取消过去发布的提交
遗弃提交
在reset可以遗弃不再使用的提交。执行遗弃时,需要根据影响的范围而指定不同的模式,可以指定是否复原索引或工作树的内容。
除了默认的mixed模式,还有soft和hard模式。欲了解受各模式影响的部分,请参照下面的表格。
模式名称 | HEAD的位置 | 索引 | 工作树 |
---|---|---|---|
soft | 修改 | 不修改 | 不修改 |
mixed | 修改 | 修改 | 不修改 |
hard | 修改 | 修改 | 修改 |
主要使用的场合:
复原修改过的索引的状态(mixed)
彻底取消最近的提交(hard)
只取消提交(soft)
提取提交
在cherry-pick,您可以从其他分支复制指定的提交,然后导入到现在的分支。
主要使用的场合:
把弄错分支的提交移动到正确的地方
把其他分支的提交添加到现在的分支
改写提交历史记录
在rebase指定i选项,您可以改写、替换、删除或合并提交。
主要使用的场合:
在push之前,重新输入正确的提交注解
清楚地汇合内容含义相同的提交。
添加最近提交时漏掉的档案
汇合分支上的提交,然后一同合并到分支
merge的特殊选项:squash
用这个选项指定分支的合并,就可以把所有汇合的提交添加到分支上。
主要使用的场合:
汇合主题分支的提交,然后合并提交到目标分支。
改写提交训练
commit –amend
git commit –amend
revert
$ git revert HEAD
在git log中会出现–Revert “添加pull的说明”
reset
$ git reset –hard HEAD~~
在git中,我们其实可以通过^和~来定位某个具体的commit,而不用每次都去敲繁琐的hash值。
“^”代表父提交,当一个提交有多个父提交时,可以通过在”^”后面跟上一个数字,表示第几个父提交,”^”相当于”^1”.
~< n>相当于连续的< n>个”^”.
在reset之前的提交可以参照ORIG_HEAD。Reset错误的时候,在ORIG_HEAD上reset 就可以还原到reset前的状态。
$ git reset –hard ORIG_HEAD
cherry-pick
$ git checkout master
$ git cherry-pick 99daed2
如果发生冲突,修改冲突的部分之后再提交。
用rebase -i 汇合提交
若要汇合过去的提交,请用rebase -i。
$ git rebase -i HEAD~~
两个提交就合并成一个提交了。