Git使用教程(下)

本文章是之前那篇教程的续篇,主要包括Git分支相关的内容。

有人把 Git 的分支模型称为它的”必杀技特性”,也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出。 为何 Git 的分支模型如此出众呢? Git 处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。

分支的基本操作

创建分支

使用git branch [branch-name]创建新分支。它会在当前所在的提交对象上创建一个指针。

可以使用git log --decorate命令查看各分支当前指向的对象。

切换分支

切换分支可以使用git checkout [branch-name]命令,如果要在创建分支的同时切换到该分支,可以使用git checkout -b [branch-name]命令来创建新分支。

注意切换分支前要将修改提交,否则强行切换会导致修改丢失。
若不想提交修改又要切换分支,可以使用git stash命令进行储藏,然后使用git stash apply命令进行复原。

合并分支

普通合并(fast-forward)

合并分支可以使用git merge命令,例如

1
2
3
4
5
6
$ git checkout master  #先切换到master分支
$ git merge hotfix #使用merge命令将hotfix分支合并到master中
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)

在合并的时候,你应该注意到了”快进(fast-forward)”这个词。 由于当前 master 分支所指向的提交是你当前提交(有关 hotfix 的提交)的直接上游,所以 Git 只是简单的将指针向前移动。 换句话说,当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。

三方合并

若合并分支并非是被合并分支的直接祖先,则Git会做一些额外的工作即三方合并。Git会使用两个分支的末端所指的快照以及这两个分支的共同祖先做一个三方合并。

1
2
3
4
5
6
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)

且合并后的分支会有多个父提交。

遇到冲突时的分支合并

若在两个不同的分支中,对同一个分支的不同部分进行了不同的修改,此时Git合并就会产生冲突。

1
2
3
4
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

使用git status命令查看包含合并冲突的文件。

1
2
3
4
5
6
7
8
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")

可以通过git mergetool来启动一个可视化合并工具。

手动将冲突修改后,可使用git addgit commit来暂存和提交分支。

删除分支

合并完分支之后,可以将分支删除,此时可以使用git branch -d [branch-name]命令将分支删除。

远程分支

拉取分支

使用git fetch [remotename]git pull命令来抓取服务器上的数据或更新本地数据库。

注意fetchpull的不同,pull命令相当于fetch命令加上merge命令,建议显式地使用fetchmerge命令。

fetch会拉取master分支并在本地建立一份拷贝,其他分支只会产生一个指针,并不会产生拷贝,需要建立一个跟踪分支。

跟踪分支

从远程仓库中拉取一个分支并在本地建立一个跟踪分支可以使用以下命令:

1
2
$ git checkout -b [branch] [remotename]/[branch]  #branch可以和远程分支名不同
$ git checkout --track [remotename]/[branch] #--track快捷方式

示例:

1
2
3
4
5
6
7
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者修改正在跟踪的上游分支,可以使用git branch -u [remotename]/[branch]git branch --set-upstream-to [remotename]/[branch]命令。

使用git branch -vv查看所有跟踪分支。

删除远程分支

使用带有--delete选项的git push命令来删除一个远程分支,例如:

1
$ git push origin --delete serverfix

变基

要整合分支,除了使用merge命令,还可以使用rebase命令进行变基操作,即将提交到某一分支上的所有修改都移至另一分支上,例如:

1
2
3
4
5
6
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
$ git checkout master #回到master分支
$ git merge experiment #进行快进合并