内容简介
- 分支简介
- 创建分支
- 查看分支
- 切换分支
- 分支合并
- 删除分支
- 分支管理
- 远程分支
分支简介
为了真正理解 Git 处理分支的方式,我们需要回顾一下 Git 是如何保存数据的。
Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照。
在进行提交操作时,Git 会保存一个提交对象(commit object)。知道了 Git 保存数据的方式,我们可以很自然的想到——该提交对象会包含一个指向暂存内容快照的指针。 但不仅仅是这样,该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象。
Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master
。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master
分支。 它会在每次的提交操作中自动向前移动。
创建分支
创建分支其实就是在当前分支的提交快照中创建一个可以移动的新的指针。创建分支使用git branch [分支名]
,比如我们创建一个flowers分支。
$ git branch flowers
执行这个命令,我们就创建了一个名字为flowers的分支。如何知道我们是否已经创建了这个分支呢?
查看分支
查看分支使用如下命令:
$ git branch
结果如下:
从上图我们看出,我们看到目前有两个分支。一个是我们
git init
的时候默认的分支master
,一个是我们新创建的分支flowers
。分支名称前面的*代表我们当前所在的分支。其实关于如何辨别当前分支的方法,还有一个是查看HEAD指针的指向,执行git log --oneline --decorate
命令,结果如下:
从结果我们可以看出HEAD指针指向的是master
,说明我们当前所处的分支就在master
分支。
切换分支
我们创建了flowers
分支,但是Git并不会自动给我们切换到所创建的分支上。执行git checkout [分支名]
命令可以切换分支。
$ git checkout flowers
执行git checkout -b [分支名]
可以完成上面两步的操作,1.创建分支2.切换到该分支。
查看分叉历史
我们切换到flowers
分支,并在此分支上面做些修改并提交,然后执行下面的命令,我们可以看到:
$ git log --oneline --decorate --graph --all
从图中我们可以看出,master
分支和flowers
分支所对应的提交快照的SHA值不一样,说明它们对应的不同的提交。
现在我们再切换回master
分支,并在此分支上面做些修改并提交,然后执行上面同样的命令,结果如下图:
分支合并
分支合并的情况有两种:
- 快进式(Fast-forward),就是简单的指针向前移动。
- 递归式(recursive),就是三个快照的合并。
下面分别对这两种情况来说明。
快进式
我们在master
分支的基础上新建立一个tree
分支,然后在tree
分支上面做些修改并提交,最后回到master
分支,然后将tree
分支里面的修改合并到master
中。
$ git co -b tree
$ vi tree_test
$ git add tree_test
$ git ci -m "tree add tree_test"
$ git co master
$ git merge tree
命令git merge tree
是将目标分支tree
合并到当前分支master
。
从最后的结果(Fast-forward)我们可以看出master
指针只是向前移动了,指针移动到了tree
分支所提交的快照指针处。
递归式
递归式合并的意思就是,如果你在创建一个新分支flowers
后又回到master
分支做了修改并提交。然后,此时你想把flowers
分支合并到master分支上。因为此时,master
分支和flowers
分支它们有一个共同的祖先,所以这种合并会将两个分支的末端和它们的共同祖先一起比较,最后生成一个新的快照并提交。
由于我们之前创建的flowers
分支就是这样的操作,所以我们省去了很多步骤。从结果(recursive)我们可以看出就是这种三方合并。
删除分支
分支合并结束并确保分支已经没有必要存在的时候,就可以将分支删除了。git branch -d [分支名]
命令删除分支。
$ git branch -d tree
删除分支可能遇到分支不能删除的情况。原因一种可能就是你的分支的修改内容没有同步到master
分支,另外一种可能就是你删除的分支是在当前的分支(被删除的分支不能是当前分支)。
冲突解决
合并有时候并不是那么一帆风顺的,如果遇到冲突了怎么办。如下:
此时 Git 做了合并,但是没有自动地创建一个新的合并提交。 Git 会暂停下来,等待你去解决合并产生的冲突。 你可以在合并冲突后的任意时刻使用
git status
命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件:
从提示中我们可以看出Git给了我们两种方式。1.修复冲突文件,然后提交;2.运行git merge --abort
中止本次提交。
我们使用第一种来解决问题。首先查看一下冲突的文件:
=======
这个分隔开的上下两部分分别是当前分支HEAD(master
)和合并时的目标分支road
对应的该文件的修改。此时,我们可以手动修改这个文件的内容,然后把对应不需要的内容删除(<<<<<<< HEAD
和 >>>>>>> road
以及 =======
这三行的内容),最后保存,然后提交即可。
分支管理
git branch
参数说明
-v
如果需要查看每个分支的最后一次提交,可以运行git branch -v
--merged
这个参数可以查看哪些分支已经合并到当前分支
--no-merged
这个参数可以查看哪些分支没有合并到当前分支
远程分支
查看远程库信息
$ git remote
获取详细的远程库信息
$ git remote -v
从图中看出,我们可以抓取和推送的origin
的地址。如果没有推送权限,就看不到push的地址。
推送分支
推送分支,就是把该分支的本地提交都上传的远程库。推送时,要指定本地分支,这样,Git就好把该分支推送到远程库对应的分支上。
$ git push origin road
抓取分支
如果你是运行git clone [url]
获取到的仓库的时候,本地只有只有一个master分支。你可以运行git branch
命令查看。如果你想获取其他的分支,那么需要主动去获取远程分支到本地。
$ git co -b dog origin/dog
从图中我们看出获取失败了,这个是因为获取的远程分支不存在导致的。
从图中我们可以看出,我们获取到了远程分支road
并且从master
分支切换到了road
分支
然后我们更新该分支的某个文件内容,然后提交并推送到远程库中。
这是如果另外一人也修改了该分支的相同文件的相同代码行。此时如何这个人提交的话,那么就会出现推送失败,因为发生了冲突。
如果发生这样的情况,那么我们可以根据提示,运行git pull
命令,把远程库该分支的最新的提交给下载到本地。
此时发现,Git提示我们没有本地的road分支与远程的origin/road分支的链接,再次失败了。解决这个失败的方法有两种:1.git pull <remote> <branch>
把远程分支下载到本地,然后关联;2. git branch --set-upstream-to=origin/<branch> road
关联本地分支到远程分支。第二种情况需要再运行git pull
才可以把远程库该分支最新的内容下载到本地。所以我采用第一种方法:
此时我们发现又冲突了,这个时候就像解决分支冲突一样去解决这个冲突就可以了。