git 有些指令功能相似,但其中却有着很大的区别

merge and rebase

比方说,有以下情况的git repository:

在这里,你可以用 pull 命令把 origin 分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的"合并的提交"(merge commit):

但是,如果你想让 mywork 分支历史看起来像没有经过任何合并一样,你也许可以用 `git rebase`:

1
$ git checkout mywork
$ git rebase origin

这些命令会把你的 mywork 分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到 .git/rebase 目录中),然后把 mywork 分支更新 到最新的 origin 分支,最后把保存的这些补丁应用到 mywork 分支上。

mywork 分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除. (请查看 git gc )

现在我们可以看一下用合并( merge )和用 rebase 所产生的历史的区别:

在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用 git-add 命令去更新这些内容的索引(index), 然后,你无需执行 git-commit ,只要执行:

1
$ git rebase --continue

这样git会继续应用(apply)余下的补丁。

在任何时候,你可以用 --abort 参数来终止rebase的行动,并且 mywork 分支会回到rebase开始前的状态。

1
$ git rebase --abort

fetch and pull

git fetch

一旦远程主机的版本库有了更新(Git术语叫做commit),需要将这些更新取回本地,这时就要用到 git fetch 命令。

1
$ git fetch <远程主机名>

上面命令将某个远程主机的更新,全部取回本地。

git fetch 命令通常用来查看其他人的进程,因为它取回的代码对你本地的开发代码没有影响。

默认情况下, git fetch 取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。

1
$ git fetch <远程主机名> <分支名>

比如,取回 origin 主机的 master 分支。

1
$ git fetch origin master

所取回的更新,在本地主机上要用 远程主机名/分支名 的形式读取。比如 origin 主机的 master ,就要用 origin/master 读取。

git branch 命令的 -r 选项,可以用来查看远程分支, -a 选项查看所有分支。

1
$ git branch -r
origin/master

$ git branch -a
 * master
  remotes/origin/master

上面命令表示,本地主机的当前分支是 master ,远程分支是 origin/master

取回远程主机的更新以后,可以在它的基础上,使用 git checkout 命令创建一个新的分支。

1
$ git checkout -b newBrach origin/master

上面命令表示,在 origin/master 的基础上,创建一个新分支。

此外,也可以使用 git merge 命令或者 git rebase 命令,在本地分支上合并远程分支。

1
$ git merge origin/master
# 或者 #
$ git rebase origin/master

上面命令表示在当前分支上,合并 origin/master

git pull

git pull 命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并。它的完整格式稍稍有点复杂。

1
$ git pull <远程主机名> <远程分支名>:<本地分支名>

比如,取回 origin 主机的 next 分支,与本地的 master 分支合并,需要写成下面这样。

1
$ git pull origin next:master

如果远程分支是与当前分支合并,则冒号后面的部分可以省略。

1
$ git pull origin next

上面命令表示,取回 origin/next 分支,再与当前分支合并。实质上,这等同于先做 git fetch ,再做 git merge

1
$ git fetch origin
$ git merge origin/next

在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在 git clone 的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的 master 分支自动"追踪" origin/master 分支。

Git也允许手动建立追踪关系。

1
$git branch --set-upstream master origin/next

上面命令指定 master 分支追踪 origin/next 分支。

如果当前分支与远程分支存在追踪关系, git pull 就可以省略远程分支名。

1
$ git pull origin

上面命令表示,本地的当前分支自动与对应的 origin 主机"追踪分支"(remote-tracking branch)进行合并。

如果当前分支只有一个追踪分支,连远程主机名都可以省略。

1
$ git pull

上面命令表示,当前分支自动与唯一一个追踪分支进行合并。

如果合并需要采用 rebase 模式,可以使用 --rebase 选项。

1
$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>

如果远程主机删除了某个分支,默认情况下, git pull 不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致 git pull 不知不觉删除了本地分支。

但是,你可以改变这个行为,加上参数 -p 就会在本地删除远程已经删除的分支。

1
$ git pull -p
# 等同于下面的命令 #
$ git fetch --prune origin
$ git fetch -p

Further reading