forked from blynn/gitmagic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
branch.txt
236 lines (150 loc) · 10.4 KB
/
branch.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
== 分支巫术 ==
即时分支合并是Git最给力的杀手锏。
*问题* :外部因素要求必须切换场景。在发布版本中突然蹦出个严重缺陷。某个特性完
成的截至日期就要来临。在项目关键部分可以提供帮助的一个开发正打算离职。所有情
况逼迫你停下所有手头工作,全力扑到到这个完全不同的任务上。
打断思维的连续性会使你的生产力大大降低,并且切换上下文也更麻烦,更大的损失。
使用中心版本控制我们必须从中心服务器下载一个新的工作拷贝。分布式系统的情况就
好多了,因为我们能够在本地克隆所需要的版本。
但是克隆仍然需要拷贝整个工作目录,还有直到给定点的整个历史记录。尽管Git使用文
件共享和硬链接减少了花费,项目文件自身还是必须在新的工作目录里重建。
*方案* :Git有一个更好的工具对付这种情况,比克隆快多了而且节省空间: *git
branch* 。
使用这个魔咒,目录里的文件突然从一个版本变到另一个。除了只是在历史记录里上跳
下窜外,这个转换还可以做更多。你的文件可以从上一个发布版变到实验版本到当前开
发版本到你朋友的版本等等。
=== 老板键 ===
曾经玩过那样的游戏吗?按一个键(“老板键”),屏幕立即显示一个电子表格或别的?
那么如果老板走进办公室,而你正在玩游戏,就可以快速将游戏藏起来。
在某个目录:
$ echo "I'm smarter than my boss" > myfile.txt
$ git init
$ git add .
$ git commit -m "Initial commit"
我们已经创建了一个Git仓库,该仓库记录一个包含特定信息的文件。现在我们键入:
$ git checkout -b boss # 之后似乎没啥变化
$ echo "My boss is smarter than me" > myfile.txt
$ git commit -a -m "Another commit"
看起来我们刚刚只是覆盖了原来的文件并提交了它。但这是个错觉。键入:
$ git checkout master # 切到文件的原先版本
嘿真快!这个文件就恢复了。并且如果老板决定窥视这个目录,键入:
$ git checkout boss # 切到适合老板看的版本
你可以在两个版本之间相切多少次就切多少次,而且每个版本都可以独立提交。
=== 肮脏的工作 ===
[[branch]]
比如你正在开发某个特性,并且由于某种原因,你需要回退三个版本,临时加进几行打
印语句来,来看看一些东西是如何工作的。那么:
$ git commit -a
$ git checkout HEAD~3
现在你可以到处加丑陋的临时代码。你甚至可以提交这些改动。当你做完的时候,
$ git checkout master
来返回到你原来的工作。看,所有未提交变更都结转了。
如果你后来想保存临时变更怎么办?简单:
$ git checkout -b dirty
只要在切换到主分支之前提交就可以了。无论你什么时候想回到脏的变更,只需键入:
$ git checkout dirty
我们在前面章节讨论加载旧状态的时候,曾经接触过这个命令。最终我们把故事说全:
文件改变成请求的状态,但我们必须离开主分支。从现在开始的任何提交都会将你的文
件提交到另一条不同的路,这个路可以之后命名。
换一个说法,在checkout一个旧状态之后,Git自动把你放到一个新的,未命名的分支,
这个分支可以使用 *git checkout -b* 来命名和保存。
=== 快速修订 ===
你正在做某件事的当间,被告知先停所有的事情,去修理一个新近发现的臭虫,这个臭
虫在提交 `1b6d...`:
$ git commit -a
$ git checkout -b fixes 1b6d
那么一旦你修正了这个臭虫:
$ git commit -a -m "Bug fixed"
$ git checkout master
并可以继续你原来的任务。你甚至可以“合并”到最新修订:
$ git merge fixes
=== 合并 ===
一些版本控制系统,创建分支很容易,但把分支合并回来很难。使用Git,合并简直是家
常便饭,以至于甚至你可能对其发生没有察觉。
我们很久之前就遇到合并了。 *pull* 命令取出提交并合并它们到你的当前分支。如果
你没有本地变更,那这个合并就是一个“快进”,相当于中心式版本控制系统里的一个
弱化的获取最新版本操作。但如有本地变更,Git将自动合并,并报告任何冲突。
通常,一个提交只有一个“父提交”,也叫前一个提交。合并分支到一起产生一个至少
有两个父的提交。这就引出了问题: `HEAD~10` 真正指哪个提交?一个提交可能有多个
父,那我们跟哪个呢?
原来这个表示每次选择第一个父。这是可取的,因为在合并时候当前分支成了第一个父;
多数情况下我们只关注我们在当前分支都改了什么,而不是从其他分支合并来的变更。
你可以用插入符号来特别指定父。比如,显示来自第二个父的日志:
$ git log HEAD^2
你可以忽略数字以指代第一个父。比如,显示与第一个父的差别:
$ git diff HEAD^
你可以结合其他类型使用这个记号。比如:
$ git checkout 1b6d^^2~10 -b ancient
开始一个新分支 ``ancient'' ,表示第一个父的第二个父的倒数第十次提交的状态。
=== 不间断工作流 ===
经常在硬件项目里,计划的第二步必须等第一步完成才能开始。待修的汽车傻等在车库
里,直到特定的零件从工厂运来。一个原型在其可以构建之前,可能苦等芯片成型。
软件项目可能也类似。新功能的第二部分不得不等待,直到第一部分发布并通过测试。
一些项目要求你的代码需要审批才能接受,因此你可能需要等待第一部分得到批准,才
能开始第二部分。
多亏了无痛分支合并,我们可以不必遵循这些规则,在第一部分正式准备好前开始第二
部分的工作。假设你已经将第一部分提交并发去审批,比如说你现在在主分支。那么分
岔:
$ git checkout -b part2
接下来,做第二部分,随时可以提交变更。只要是人就可能犯错误,经常你将回到第一
部分在修修补补。如果你非常幸运,或者超级棒,你可能不必做这几行:
$ git checkout master # 回到第一部分
$ 修复问题
$ git commit -a # 提交变更
$ git checkout part2 # 回到第二部分
$ git merge master # 合并这些改动
最终,第一部分获得批准:
$ git checkout master # 回到第一部分
$ submit files # 对世界发布
$ git merge part2 # 合并第二部分
$ git branch -d part2 # 删除分支“part2”
现在你再次处在主分支,第二部分的代码也在工作目录。
很容易扩展这个技巧,应用到任意数目的部分。它也很容易追溯分支:假如你很晚才意
识到你本应在7次提交前就创建分支。那么键入:
$ git branch -m master part2 # 重命名“master”分支为“part2”。
$ git branch master HEAD~7 # 以七次前提交建一个新的“master”。
分支 `master` 只有第一部分内容,其他内容在分支 `part2` 。 我们现在后一个分支;
我们创建了 `master` 分支还没有切换过去,因为我们想继续工作在 `part2` 。这是不
寻常的。直到现在,我们已经在创建之后切换到分支,如:
$ git checkout HEAD~7 -b master # 创建分支,并切换过去。
=== 重组杂乱 ===
或许你喜欢在同一个分支下完成工作的方方面面。你想为自己保留工作进度并希望其他
人只能看到你仔细整理过后的提交。开启一对分支:
$ git branch sanitized # 为干净提交创建分支
$ git checkout -b medley # 创建并切换分支以进去工作
接下来,做任何事情:修臭虫,加特性,加临时代码,诸如此类,经常按这种方式提交。
然后:
$ git checkout sanitized
$ git cherry-pick medley^^
应用分支 ``medley'' 的祖父提交到分支 ``sanitized'' 。通过合适的挑选(像选樱桃
那样)你可以构建一个只包含成熟代码的分支,而且相关的提交也组织在一起。
=== 管理分支 ===
列出所有分支:
$ git branch
默认你从叫 ``master'' 的分支开始。一些人主张别碰“master”分支,而是创建你自
己版本的新分支。
选项 *-d* 和 *-m* 允许你来删除和移动(重命名)分支。参见 *git help branch* 。
分支``master'' 是一个有用的惯例。其他人可能假定你的仓库有一个叫这个名字的分
支,并且该分支包含你项目的官方版本。尽管你可以重命名或抹杀 ``master'' 分支,
你最好还是尊重这个约定。
=== 临时分支 ===
很快你会发现你经常会因为一些相似的原因创建短期的分支:每个其它分支只是为了保
存当前状态,那样你就可以直接跳到较老状态以修复高优先级的臭虫之类。
可以和电视的换台做类比,临时切到别的频道,来看看其它台那正放什么。但并不是简
单地按几个按钮,你不得不创建,检出,合并,以及删除临时分支。幸运的是,Git已经
有了和电视机遥控器一样方便的快捷方式:
$ git stash
这个命令保存当前状态到一个临时的地方(一个隐藏的地方)并且恢复之前状态。你的
工作目录看起来和你开始编辑之前一样,并且你可以修复臭虫,引入之前变更等。当你
想回到隐藏状态的时候,键入:
$ git stash apply # 你可能需要解决一些冲突
你可以有多个隐藏,并用不同的方式来操作他们。参见 *git help slash* 。也许你已
经猜到,Git维护在这个场景之后的分支以执行魔法技巧.
=== 按你希望的方式工作 ===
你可能犹疑于分支是否值得一试。毕竟,克隆也几乎一样快,并且你可以用 *cd* 来在
彼此之间切换,而不是用Git深奥的命令。
考虑一下浏览器。为什么同时支持多标签和多窗口?因为允许两者同时接纳纳了多种风
格的用户。一些用户喜欢只保持一个打开的窗口,然后用标签浏览多个网页。一些可能
坚持另一个极端:任何地方都没有标签的多窗口。一些喜好处在两者之间。
分支类似你工作目录的标签,克隆类似打开的浏览器新窗口。这些是本地操作很快,那
为什么不试着找出最适合你的组合呢?Git让你按你确实所希望的那样工作。