熟练使用 git 分支管理

Git
观察过不少使用 git的人,只会用 add, commit, push, pull这几个命令,包括恢复版本之类的,多半也会暴力的删除整个项目,再从新 clone干净的代码。虽然说也能工做了,可是无疑没有领会到 git的精华。 这篇文章主要说明如何使用分支使咱们的开发工做更加顺滑,如何让分支成为你平常工做流不可缺失的一部分。

git branch 用法

git branch   //列出全部的分支
git branch <branch> //建立名为<branch>的分支,可是不会切换过去
git branch -d <branch>  //删除指定分支,这是一个“安全”操做,git会阻止你删除包含未合并更改的分支。
git branch -D <branch>  //强制删除分支
git branch -m <branch> //从新命名当前分支
复制代码

在平常开发中,不管是修复一个bug或者添加一个功能,咱们都应该新建一个分支来封装咱们的修改。这样能够保证咱们不稳定的代码永远不会提交到主代码分支上。git

下面咱们具体来看在执行分支有关的操做,分支的变化:算法

建立分支

分支只是指向提交的指针,理解这一点很重要,当你建立新分支,实际上只是建立了一个新的指针,仓库自己不会受到影响,一开始你的仓库只有一条分支:安全

master
而后你执行下面的命令建立一个分支,用于加一个新feature:

git branch new-feature
复制代码

new-feature
固然执行后,你只是建立了这个分支,还须要执行 git chekcout new-feature切换到 new-feature分支,而后再使用 git add, git commit

删除分支

假如你已经开发完了new-feature,而且已经commit代码了, 你就能够自由删除这个分支了。bash

git branch -d new-feature
复制代码

若是分支尚未合入master,会报下面的错误:ui

error: The branch 'new feature' is not fully merged.
If you are sure you want to delete it, run 'git branch -D crazy-experiment'.
复制代码

这时候你能够合并分支(下面会说如何合并分支),若是你真的肯定了要删除分支,能够用-D执行强制删除:this

git branch -D new-feature
复制代码

切换分支(git checkout)

git checkout 命令容许你切换到用git branch建立的分支。切换分支会更新当前工做目录中的文件,还能够用git log查看当前分支的历史。 用法spa

git checkout <existing-branch> //切换到一个已有分支上
git checkout -b <new-branch> // -b 标记 能够方便让你先建立一个新的new-branch,再直接切换过去
git checkout -b <new-branch> <existing-branch> //在已有的分支上建立分支,原来的分支使新分支的基
复制代码

git branchgit chekout 是一对好基友,你可使用git checkout在不一样的功能分支或者bug分支之间切换,而不产生相互影响。3d

关于分离的HEAD(detached HEAD) 通常咱们有时候须要恢复到之前commit的版本上查看原来的一些文件时,咱们会git checkout commit的hash码或者tag, 这时候会提醒咱们进入了detached HEAD指针

detached HEAD
拿上图举例,咱们当前的HEAD在4,而后假设 git checkout 2,咱们的代码回到2的状态了,一般git会显示下面的warning:

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 2
复制代码

若是在这种状态下开发,而后又add,commit,没有分支可让你回到以前的状态。当你不可避免的须要checkout到另一个分支,想再回来就是不可能的了,由于像图中的那个X状态,根本就不在分支上,你将不再能引用你以前添加的代码了。code

重点:永远记得在开发分支上开发,不要在分离的HEAD上开发,这能够确保你能够引用到你的新提交,若是只是checkout到之前看看无所谓,若是真的须要在之前的版本上添加什么代码,记得上面warning 中的git checkout -b new_branch_name,是本身处于一个确切的分支中。

远离detached HEAD,咱们来看实际上git分支流程是什么样子的:

git branch new-feature
git checkout new-feature
复制代码

接下来咱们作一些代码改动,提交:

git add <some file>
git commit -m "A new feature"
##你接着改代码,接着提交不少次
复制代码

当你git log会显示每一次的commit, 和master分支彻底独立,当你checkout到master分支去,再git log,会发现new-feature分支的提交都不在,这就是不影响master分支。 这时候,你能够考虑合并new-feature或者在master分支上开始别的工做。

合并(git merge)

合并是git将被fork的历史放回到一块儿的方式。 git merge 命令容许你将 git branch 建立的多条分支合并成一个。 用法

git merge <branch>  //将指定分支并入当前分支
git merge --no-ff <branch>  //将指定分支并入当前分支,但 老是 生成一个合并提交(即便是快速向前合并)。这能够用来记录仓库中发生的全部合并。
复制代码

一旦在新分支上完成开发,咱们须要把新分支的提交合并到主分支,git会根据目前分支之间的结构信息,选择不一样的算法来完成合并:

  • 快速向前合并
  • 三路合并

快速向前合并 当new-feature的分支与原有的master分支呈现线性关系时,执行快速向前合并,git将当前的HEAD指针快速移到目标分支的顶端,master分支也就具备了new-feature分支的历史了,如图:

快速向前合并

来看一个快速向前合并的实例:

# 开始新功能
git checkout -b new-feature master

# 编辑文件
git add <file>
git commit -m "开始新功能"

# 编辑文件
git add <file>
git commit -m "完成功能"

# 合并new-feature分支
git checkout master
git merge new-feature
git branch -d new-feature

复制代码

对于合做开发的人少的项目,这是一种主要的工做流,合做开发的人多的话,主master分支常常都会有新提交,若是你的new-feature耗时比较久,再提交时,master分支可能已通过去几个版本了,这时候就须要下面的三路合并了。

三路合并 可是若是master分支在new-feature分离后,又有了新的提交,即开始分叉了,git只能执行三路合并,三路合并使用一个专门的提交来合并两个分支的历史。

已经分叉的branch
所谓的三路也就是:两个分支的顶端以及他们共同的祖先。 在执行三路合并后:

三路合并后
使用三路合并产生的合并提交做为两个分支的链接标志。

解决冲突 若是两个分支对同一个文件的同一部分均有修改时,git将没法判断应该使用哪一个,这时候合并提交会中止,须要你手动解决这些冲突。你可使用git status来查看哪里存在冲突,不少时候我都会在目录下执行grep -rn HEAD来查看哪些文件里有这个标记,有这个标记的地方都是有冲突的。

当修改完全部的冲突后,git add全部的冲突文件,运行git commit生成一个合并提交,这和提交一个普通快照的流程相同。提交冲突只会存在在三路合并中,快速向前合并中不可能出现针对同一文件同一部分的不同修改。

下面实例来看看三路合并是怎么产生的:

# 开始新功能
git checkout -b new-feature master

# 编辑文件
git add <file>
git commit -m "开始新功能"

# 编辑文件
git add <file>
git commit -m "完成功能"

# 在master分支上开发
git checkout master

# 编辑文件
git add <file>
git commit -m "在master上添加了一些极其稳定的功能"

# 合并new-feature分支
git merge new-feature
git branch -d new-feature
复制代码

这时候,merge会中止,由于没法将 master 直接移动到 new-feature。因此须要你手动合并冲突后再提交。

git merge会产生合并提交,有的人会选择使用git rebase来合并以确保一个干净的提交历史。关于这两个的区别,我会另写一篇介绍。

相关文章
相关标签/搜索