原文:http://www.eecs.harvard.edu/~cduan/technical/git/git-2.shtml
翻译:http://blog.csdn.net/yhcharles/article/details/6596816
Branching(分支)的目的
假设你正在做一篇论文。你完成了第一份草稿,并且提交评审了。然后你得到了一些新的数据,于是你着手把这些新的内容加到论文中。当你正做到一半的时候,评审委员会给你打电话,告诉你其中有些章节的标题需要进行修改,以符合格式要求。这时你会怎么做?
显然你不想把你正修改到一半的论文换上正确的标题发出去。你希望做的,是回到你当初发送出去的版本,修改好标题,然后再重新发送,同时把最近的工作安全的保存在另外某个地方。
这就是branching背后的思想,Git让这件事情变得简单。
注意术语:术语“branch”和“head”在Git中几乎是同义词。每个branch都有一个head来代表,并且每一个head代表一个branch。有时候,“branch”被用来表示一个head以及该head的所有历史commit,而“head”只表示一个commit对象,即该branch中的最近一个commit。
创建一个branch
假设你的repository是这样的:
(A) -- (B) -- (C)
|
master
|
HEAD
这里(B)是你发送给委员会的版本,(C)是你现在工作的版本。(这里没有画箭头,可以想象它们总是指向左边的)
为了跳回到commit (B)进行修改,首先你需要知道如何引用该commit。你可以用git log来查到(B)的SHA1名字,或者用HEAD^来表示。
现在,我们可以用git branch命令了:
git branch [new-head-name] [reference-to-(B)]
或者,例如:
git branch fix-headers HEAD^
这个命令会用给出的名字创建一个新的head,并且将其指向指定的commit对象。如果没有指定commit对象,那么它会指向 HEAD。
现在,我们的commit树看起来是这样的:
(A) -- (B) ------- (C)
| |
fix-headers master
|
HEAD
在branch之间切换
为了开始在这些head上开始工作,你需要把fix-headers设置成当前的head。可以用git checkout来做:
git checkout [head-name]
该命令做了这些事情:
- 将HEAD指向[head-name]表示的commit对象
- 将当前目录中的所有文件替换成新HEAD commit中的文件版本
在check out fix-headers之后,你就可以修改标题了。然后你添加并提交这些修改。得到的repository看起来是这样:
+-------------- (D)
/ |
(A) -- (B) -- (C) |
| |
master fix-headers
|
HEAD
(现在你可以看到为什么称为“branching”了:commit树新生长出了一个分支。注意(B)和(C)之间的夹角可以忽略;指针箭头不会关心它们是水平的还是斜的)
master的祖先是(C),(B),(A)。fix-headers的祖先是(D),(B),(A)。你可以用git log查看到。
相关的命令:
这里还有其它一些有用的命令:
- git brach不带参数,用来列出目前所有的head,在当前head旁用星号标出
- git diff [head1]..[head2]列出head2和head1指向的commit之间的diff
- git diff [head1]...[head2](注意是三个点)列出head2与head1、head2的共同祖先之间的diff。例如,在上面的例子中diff master...fix-headers会列出(D)和(B)的diff
- git log [head1]..[head2]列出head2和head1、head2共同祖先之间的修改日志。如果是三个点,那么会列出head1和共同祖先之间的修改日志;这个用处不大。(切换head1和head2相对来说更有用)
一种使用Git branch常用的方式是,保留一个“main”或者“trunk”分支,创建其他新的分支用来实现新的特性。通常,缺省的Git分支,master,被用来作为main分支。
因此,在上面的例子中,把master留在(B)可能更好,这个分支用来提交给评审。然后,你可以开一个新的分支用来保存为新数据做的修改。
理想情况下,用这种模式,master分支始终是可发布的状态。其它分支会包含完成到一半的工作,新的特性等等。
当有多有开发者为同一个项目工作时,这种模式尤其重要。如果所有开发者都在向同一个分支添加commit,那么新特性必须在单个commit完成添加,以免使得这个branch变成不可用状态。但是,如果每个开发者创建一个新的branch来开发新的特性,那么就可以随时进行commit,不管是否已经完成。
这就是Git用户说commit很廉价的意思。如果你工作在你自己的branch上,那你就没有必要在提交commit时慎之又慎。反正它不会对其它事情有任何影响。