clearly-describe-rm-mv
html 700 lines 25.3 KB
Raw
1 ---
2 layout: zh_reference
3 ---
4
5 <div class="box">
6 <h2>
7 <span class="docs">
8 <a target="new" href="http://git-scm.com/book/en/Git-Branching">书</a>
9 </span>
10 分支与合并
11 </h2>
12 <div class="block">
13 <p>分支是我最喜欢的 Git 特性之一。如果你用过其他版本控制系统,把你所知的分支给忘记,倒可能更有帮助些 ——
14 事实上,以我们使用分支的方式,把 Git 的分支看作 <i>上下文</i> 反而更合适。
15 当你检出分支时,你可以在两三个不同的分支之间来回切换。
16 </p>
17
18 <p class="nutshell">
19 <b>简而言之</b>,你可以执行 <code>git branch (branchname)</code> 来创建分支,
20 使用 <code>git checkout (branchname)</code> 命令切换到该分支,在该分支的上下文环境中,
21 提交快照等,之后可以很容易地来回切换。当你切换分支的时候,Git 会用该分支的最后提交的快照替换你的工作目录的内容,
22 所以多个分支不需要多个目录。使用 <code>git merge</code> 来合并分支。你可以多次合并到统一分支,
23 也可以选择在合并之后直接删除被并入的分支。
24 </p>
25
26 </div>
27 </div>
28
29 <div class="box">
30 <h2>
31 <span class="docs">
32 <a target="new" href="http://git-scm.com/docs/git-branch">文档</a> &nbsp;
33 <a target="new" href="http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is">书</a>
34 </span>
35 <a name="branch">git branch</a>
36 <span class="desc">列出、创建与管理工作上下文</span>
37 </h2>
38
39 <br/>
40
41 <h2>
42 <span class="docs">
43 <a target="new" href="http://git-scm.com/docs/git-checkout">文档</a> &nbsp;
44 <a target="new" href="http://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging">书</a>
45 </span>
46 <a name="checkout">git checkout</a>
47 <span class="desc">切换到新的分支上下文</span>
48 </h2>
49
50 <div class="block">
51 <p><code>git branch</code> 命令是 Git 中的通用分支管理工具,可以通过它完成多项任务。
52 我们先说你会用到的最多的命令 —— 列出分支、创建分支和删除分支。
53 我们还会介绍用来切换分支的 <code>git checkout</code> 命令。
54 </p>
55
56 <h4>
57 git branch
58 <small>列出可用的分支</small>
59 </h4>
60
61 <p>没有参数时,<code>git branch</code> 会列出你在本地的分支。你所在的分支的行首会有个星号作标记。
62 如果你开启了<a href="http://git-scm.com/book/en/Customizing-Git-Git-Configuration#Colors-in-Git">彩色模式</a>,当前分支会用绿色显示。
63 </p>
64
65 <pre>
66 $ git branch
67 * <span class="green">master</span>
68 </pre>
69
70 <p>此例的意思就是,我们有一个叫做“master”的分支,并且该分支是当前分支。
71 当你执行 <code>git init</code> 的时候,缺省情况下 Git 就会为你创建“master”分支。
72 但是这名字一点特殊意味都没有 —— 事实上你并不非得要一个叫做“master”的分支。
73 不过由于它是缺省分支名的缘故,绝大部分项目都有这个分支。
74 </p>
75
76 <h4>
77 git branch (branchname)
78 <small>创建新分支</small>
79 </h4>
80
81 <p>我们动手创建一个分支,并切换过去。执行 <code>git branch (branchname)</code> 即可。
82 </p>
83
84 <pre>
85 $ git branch testing
86 $ git branch
87 * <span class="green">master</span>
88 testing
89 </pre>
90
91 <p>现在我们可以看到,有了一个新分支。当你以此方式在上次提交更新之后创建了新分支,如果后来又有更新提交,
92 然后又切换到了“testing”分支,Git 将还原你的工作目录到你创建分支时候的样子 ——
93 你可以把它看作一个记录你当前进度的书签。让我们实际运用看看 ——
94 我们用 <code>git checkout (branch)</code> 切换到我们要修改的分支。
95 </p>
96
97 <pre>
98 <b>$ ls</b>
99 README hello.rb
100 <b>$ echo 'test content' > test.txt</b>
101 <b>$ echo 'more content' > more.txt</b>
102 <b>$ git add *.txt</b>
103 <b>$ git commit -m 'added two files'</b>
104 [master 8bd6d8b] added two files
105 2 files changed, 2 insertions(+), 0 deletions(-)
106 create mode 100644 more.txt
107 create mode 100644 test.txt
108 <b>$ ls</b>
109 README hello.rb more.txt test.txt
110 <b>$ git checkout testing</b>
111 Switched to branch 'testing'
112 <b>$ ls</b>
113 README hello.rb
114 </pre>
115
116 <p>当我们切换到“测试”分支的时候,我们添加的新文件被移除了。切换回“master”分支的时候,它们有重新出现了。
117 </p>
118
119 <pre>
120 <b>$ ls</b>
121 README hello.rb
122 <b>$ git checkout master</b>
123 Switched to branch 'master'
124 <b>$ ls</b>
125 README hello.rb more.txt test.txt
126 </pre>
127
128 <h4>
129 git checkout -b (branchname)
130 <small>创建新分支,并立即切换到它</small>
131 </h4>
132
133 <p>
134 通常情况下,你会更希望立即切换到新分支,从而在该分支中操作,然后当此分支的开发日趋稳定时,
135 将它合并到稳定版本的分支(例如“master”)中去。
136 执行 <code>git branch newbranch; git checkout newbranch</code> 也很简单,
137 不过 Git 还为你提供了快捷方式:<code>git checkout -b newbranch</code>。
138 </p>
139
140 <pre>
141 <b>$ git branch</b>
142 * master
143 <b>$ ls</b>
144 README hello.rb more.txt test.txt
145 <b>$ git checkout -b removals</b>
146 Switched to a new branch 'removals'
147 <b>$ git rm more.txt </b>
148 rm 'more.txt'
149 <b>$ git rm test.txt </b>
150 rm 'test.txt'
151 <b>$ ls</b>
152 README hello.rb
153 <b>$ git commit -am 'removed useless files'</b>
154 [removals 8f7c949] removed useless files
155 2 files changed, 0 insertions(+), 2 deletions(-)
156 delete mode 100644 more.txt
157 delete mode 100644 test.txt
158 <b>$ git checkout master</b>
159 Switched to branch 'master'
160 <b>$ ls</b>
161 README hello.rb more.txt test.txt
162 </pre>
163
164 <p>如你所见,我们创建了一个分支,在该分支的上下文中移除了一些文件,然后切换回我们的主分支,那些文件又回来了。
165 使用分支将工作切分开来,从而让我们能够在不同上下文中做事,并来回切换。
166 </p>
167
168 <p>
169 创建新分支,在其中完成一部分工作,完成之后将它合并到主分支并删除。你会觉得这很方便,因为这么做很快很容易。
170 如此,当你觉得这部分工作并不靠谱,舍弃它很容易。并且,如果你必须回到稳定分支做些事情,
171 也可以很方便地这个独立分支的工作先丢在一边,完成要事之后再切换回来。
172 </p>
173
174 <h4>
175 git branch -d (branchname)
176 <small>删除分支</small>
177 </h4>
178
179 <p>假设我们要删除一个分支(比如上例中的“testing”分支,该分支没啥特殊的内容了),
180 可以执行 <code>git branch -d (branch)</code> 把它删掉。
181 </p>
182
183 <pre>
184 <b>$ git branch</b>
185 * <span class="green">master</span>
186 testing
187 <b>$ git branch -d testing</b>
188 Deleted branch testing (was 78b2670).
189 <b>$ git branch</b>
190 * <span class="green">master</span>
191 </pre>
192
193 <p class="nutshell">
194 <b>简而言之</b> 使用 <code>git branch</code> 列出现有的分支、创建新分支以及删除不必要或者已合并的分支。
195 </p>
196
197 </div>
198 </div>
199
200 <div class="box">
201 <h2>
202 <span class="docs">
203 <a target="new" href="http://git-scm.com/docs/git-merge">docs</a> &nbsp;
204 <a target="new" href="http://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging#Basic-Merging">book</a>
205 </span>
206 <a name="merge">git merge</a>
207 <span class="desc">将分支合并到你的当前分支</span>
208 </h2>
209
210 <div class="block">
211 <p>一旦某分支有了独立内容,你终究会希望将它合并回到你的主分支。
212 你可以使用 <code>git merge</code> 命令将任何分支合并到当前分支中去。
213 我们那上例中的“removals”分支为例。假设我们创建了一个分支,移除了一些文件,并将它提交到该分支,
214 其实该分支是与我们的主分支(也就是“master”)独立开来的。
215 要想将这些移除操作包含在主分支中,你可以将“removals”分支合并回去。
216 </p>
217
218 <pre>
219 <b>$ git branch</b>
220 * <span class="green">master</span>
221 removals
222 <b>$ ls</b>
223 README hello.rb more.txt test.txt
224 <b>$ git merge removals</b>
225 Updating 8bd6d8b..8f7c949
226 Fast-forward
227 more.txt | 1 -
228 test.txt | 1 -
229 2 files changed, 0 insertions(+), 2 deletions(-)
230 delete mode 100644 more.txt
231 delete mode 100644 test.txt
232 <b>$ ls</b>
233 <span class="hl">README hello.rb</span>
234 </pre>
235
236 <h4>
237 更多复杂合并
238 </h4>
239
240 <p>当然,合并并不仅仅是简单的文件添加、移除的操作,Git 也会合并修改 —— 事实上,它很会合并修改。
241 举例,我们看看在某分支中编辑某个文件,然后在另一个分支中把它的名字改掉再做些修改,
242 最后将这俩分支合并起来。你觉得会变成一坨 shi?我们试试看。
243 </p>
244
245 <pre>
246 <b>$ git branch</b>
247 * master
248 <b>$ cat hello.rb </b>
249 class HelloWorld
250 def self.hello
251 puts "Hello World"
252 end
253 end
254
255 HelloWorld.hello
256 </pre>
257
258 <p>首先,我们创建一个叫做“change_class”的分支,切换过去,从而将重命名类等操作独立出来。我们将类名从 “HelloWorld” 改为 “HiWorld”。
259 </p>
260
261 <pre>
262 <b>$ git checkout -b change_class</b>
263 M hello.rb
264 Switched to a new branch 'change_class'
265 <b>$ vim hello.rb </b>
266 <b>$ head -1 hello.rb </b>
267 class HiWorld
268 <b>$ git commit -am 'changed the class name'</b>
269 [change_class 3467b0a] changed the class name
270 1 files changed, 2 insertions(+), 4 deletions(-)
271 </pre>
272
273 <p>然后,将重命名类操作提交到 “change_class” 分支中。
274 现在,假如切换回 “master” 分支我们可以看到类名恢复到了我们切换到 “change_class” 分支之前的样子。
275 现在,再做些修改(即代码中的输出),同时将文件名从 <code>hello.rb</code> 改为 <code>ruby.rb</code>。
276 </p>
277
278 <pre>
279 <b>$ git checkout master</b>
280 Switched to branch 'master'
281 <b>$ git mv hello.rb ruby.rb</b>
282 <b>$ vim ruby.rb </b>
283 <b>$ git diff</b>
284 <span class="umber">diff --git a/ruby.rb b/ruby.rb
285 index 2aabb6e..bf64b17 100644
286 --- a/ruby.rb
287 +++ b/ruby.rb</span>
288 <span class="lblue">@@ -1,7 +1,7 @@</span>
289 class HelloWorld
290
291 def self.hello
292 <span class="red">- puts "Hello World"</span>
293 <span class="green">+ puts "Hello World from Ruby"</span>
294 end
295
296 end
297 <b>$ git commit -am 'added from ruby'</b>
298 [master b7ae93b] added from ruby
299 1 files changed, 1 insertions(+), 1 deletions(-)
300 rename hello.rb => ruby.rb (65%)
301 </pre>
302
303 <p>现在这些改变已经记录到我的 “master” 分支了。请注意,这里类名还是 “HelloWorld”,而不是 “HiWorld”。
304 然后我想将类名的改变合并过来,我把 “change_class” 分支合并过来就行了。
305 但是,我已经将文件名都改掉了,Git 知道该怎么办么?
306 </p>
307
308 <pre>
309 <b>$ git branch</b>
310 change_class
311 * master
312 <b>$ git merge change_class</b>
313 Renaming hello.rb => ruby.rb
314 Auto-merging ruby.rb
315 Merge made by recursive.
316 ruby.rb | 6 ++----
317 1 files changed, 2 insertions(+), 4 deletions(-)
318 <b>$ cat ruby.rb</b>
319 class HiWorld
320 def self.hello
321 puts "Hello World from Ruby"
322 end
323 end
324
325 HiWorld.hello
326 </pre>
327
328 <p>不错,它就是发现了。请注意,在这部操作,我没有遇到合并冲突,并且文件已经重命名、类名也换掉了。挺酷。
329 </p>
330
331 <h4>
332 合并冲突
333 </h4>
334
335 <p>那么,Git 合并很有魔力,我们再也不用处理合并冲突了,对吗?不太确切。
336 不同分支中修改了相同区块的代码,电脑自己猜不透神马的情况下,冲突就摆在我们面前了。
337 我们看看两个分支中改了同一行代码的例子。
338 </p>
339
340 <pre>
341 <b>$ git branch</b>
342 * master
343 <b>$ git checkout -b fix_readme</b>
344 Switched to a new branch 'fix_readme'
345 <b>$ vim README </b>
346 <b>$ git commit -am 'fixed readme title'</b>
347 [fix_readme 3ac015d] fixed readme title
348 1 files changed, 1 insertions(+), 1 deletions(-)
349 </pre>
350
351 <p>我们在某分支中修改了 README 文件中的一行,并提交了。我们再在 “master” 分支中对同个文件的同一行内容作不同的修改。
352 </p>
353
354 <pre>
355 <b>$ git checkout master</b>
356 Switched to branch 'master'
357 <b>$ vim README </b>
358 <b>$ git commit -am 'fixed readme title differently'</b>
359 [master 3cbb6aa] fixed readme title differently
360 1 files changed, 1 insertions(+), 1 deletions(-)
361 </pre>
362
363 <p>有意思的来了 —— 我们将前一个分支合并到 “master” 分支,一个合并冲突就出现了。
364 </p>
365
366 <pre>
367 <b>$ git merge fix_readme</b>
368 Auto-merging README
369 CONFLICT (content): Merge conflict in README
370 Automatic merge failed; fix conflicts and then commit the result.
371 <b>$ cat README </b>
372 <<<<<<< HEAD
373 Many Hello World Examples
374 =======
375 Hello World Lang Examples
376 >>>>>>> fix_readme
377
378 This project has examples of hello world in
379 nearly every programming language.
380 </pre>
381
382 <p>你可以看到,Git 在产生合并冲突的地方插入了标准的与 Subversion 很像的合并冲突标记。
383 轮到我们去解决这些冲突了。在这里我们就手动把它解决。如果你要 Git 打开一个图形化的合并工具,
384 可以看看 <a href="http://git-scm.com/docs/git-mergetool">git 合并工具</a>
385 (比如 kdiff3、emerge、p4merge 等)。
386 </p>
387
388 <pre>
389 <b>$ vim README </b> <span class="exp">here I'm fixing the conflict</span>
390 <b>$ git diff</b>
391 <span class="umber">diff --cc README
392 index 9103e27,69cad1a..0000000
393 --- a/README
394 +++ b/README</span>
395 <span class="lblue">@@@ -1,4 -1,4 +1,4 @@@</span>
396 <span class="red">- Many Hello World Examples</span>
397 <span class="red">-Hello World Lang Examples</span>
398 <span class="green">++Many Hello World Lang Examples</span>
399
400 This project has examples of hello world in
401 </pre>
402
403 <p>在 Git 中,处理合并冲突的时候有个很酷的提示。
404 如果你执行 <code>git diff</code>,就像我演示的这样,它会告诉你冲突的两方,和你是如何解决的。
405 现在是时候把它标记为已解决了。在 Git 中,我们可以用 <code>git add</code> —— 要告诉 Git 文件冲突已经解决,你必须把它写入缓存区。
406 </p>
407
408 <pre>
409 <b>$ git status -s</b>
410 UU README
411 <b>$ git add README </b>
412 <b>$ git status -s</b>
413 M README
414 <b>$ git commit </b>
415 [master 8d585ea] Merge branch 'fix_readme'
416 </pre>
417
418 <p>现在我们成功解决了合并中的冲突,并提交了结果
419 </p>
420
421 <p class="nutshell">
422 <b>简而言之</b> 使用 <code>git merge</code> 将另一个分支并入当前的分支中去。
423 Git 会自动以最佳方式将两个不同快照中独特的工作合并到一个新快照中去。
424 </p>
425
426 </div>
427 </div>
428
429 <div class="box">
430 <h2>
431 <span class="docs">
432 <a target="new" href="http://git-scm.com/docs/git-log">文档</a> &nbsp;
433 <a target="new" href="http://git-scm.com/book/en/Git-Tools-Revision-Selection#Commit-Ranges">书</a>
434 </span>
435 <a name="log">git log</a>
436 <span class="desc">显示一个分支中提交的更改记录</span>
437 </h2>
438
439 <div class="block">
440
441 <p>到目前为止,我们已经提交快照到项目中,在不同的各自分离的上下文中切换,
442 但假如我们忘了自己是如何到目前这一步的那该怎么办?或者假如我们想知道此分支与彼分支到底有啥区别?
443 Git 提供了一个告诉你使你达成当前快照的所有提交消息的工具,叫做 <code>git log</code>。
444 </p>
445
446 <p>要理解日志(log)命令,你需要了解当执行 <code>git commit</code> 以存储一个快照的时候,都有啥信息被保存了。
447 除了文件详单、提交消息和提交者的信息,Git 还保存了你的此次提交所基于的快照。
448 也就是,假如你克隆了一个项目,你是在什么快照的基础上做的修改而得到新保存的快照的?
449 这有益于为项目进程提供上下文,使 Git 能够弄明白谁做了什么改动。
450 如果 Git 有你的快照所基于的快照的话,它就能自动判断你都改变了什么。而新提交所基于的提交,被称作新提交的“父亲”。
451 </p>
452
453 <p>某分支的按时间排序的“父亲”列表,当你在该分支时,可以执行 <code>git log</code> 以查看。
454 例如,如果我们在本章中操作的 Hello World 项目中执行 <code>git log</code>,我们可以看到已提交的消息。
455 </p>
456
457 <pre>
458 <b>$ git log</b>
459 <span class="yellow">commit 8d585ea6faf99facd39b55d6f6a3b3f481ad0d3d</span>
460 Merge: 3cbb6aa 3ac015d
461 Author: Scott Chacon &lt;schacon@gmail.com>
462 Date: Fri Jun 4 12:59:47 2010 +0200
463
464 Merge branch 'fix_readme'
465
466 Conflicts:
467 README
468
469 <span class="yellow">commit 3cbb6aae5c0cbd711c098e113ae436801371c95e</span>
470 Author: Scott Chacon &lt;schacon@gmail.com>
471 Date: Fri Jun 4 12:58:53 2010 +0200
472
473 fixed readme title differently
474
475 <span class="yellow">commit 3ac015da8ade34d4c7ebeffa2053fcac33fb495b</span>
476 Author: Scott Chacon &lt;schacon@gmail.com>
477 Date: Fri Jun 4 12:58:36 2010 +0200
478
479 fixed readme title
480
481 <span class="yellow">commit 558151a95567ba4181bab5746bc8f34bd87143d6</span>
482 Merge: b7ae93b 3467b0a
483 Author: Scott Chacon &lt;schacon@gmail.com>
484 Date: Fri Jun 4 12:37:05 2010 +0200
485
486 Merge branch 'change_class'
487 ...
488 </pre>
489
490 <p>我们可以用 <code>--oneline</code> 选项来查看历史记录的紧凑简洁的版本。
491 </p>
492
493 <pre>
494 <b>$ git log --oneline</b>
495 8d585ea Merge branch 'fix_readme'
496 3cbb6aa fixed readme title differently
497 3ac015d fixed readme title
498 558151a Merge branch 'change_class'
499 b7ae93b added from ruby
500 3467b0a changed the class name
501 17f4acf first commit
502 </pre>
503
504 <p>
505 这告诉我们的是,此项目的开发历史。如果提交消息描述性很好,这就能为我们提供关于有啥改动被应用、或者影响了当前快照的状态、以及这快照里头都有啥。
506 </p>
507
508 <p>我们还可以用它的十分有帮助的 <code>--graph</code> 选项,查看历史中什么时候出现了分支、合并。以下为相同的命令,开启了拓扑图选项:
509 </p>
510
511 <pre>
512 <b>$ git log --oneline --graph</b>
513 * 8d585ea Merge branch 'fix_readme'
514 |\
515 | * 3ac015d fixed readme title
516 * | 3cbb6aa fixed readme title differently
517 |/
518 * 558151a Merge branch 'change_class'
519 |\
520 | * 3467b0a changed the class name
521 * | b7ae93b added from ruby
522 |/
523 * 17f4acf first commit
524 </pre>
525
526 <p>现在我们可以更清楚明了地看到何时工作分叉、又何时归并。
527 这对查看发生了什么、应用了什么改变很有帮助,并且极大地帮助你管理你的分支。
528 让我们创建一个分支,在里头做些事情,然后切回到主分支,也做点事情,然后看看 <code>log</code>
529 命令是如何帮助我们理清这俩分支上都发生了啥的。
530 </p>
531
532 <p>首先我们创建一个分支,来添加 Erlang 编程语言的 Hello World 示例 ——
533 我们想要在一个分支里头做这个,以避免让可能还不能工作的代码弄乱我们的稳定分支。
534 这样就可以切来切去,片叶不沾身。
535 </p>
536
537 <pre>
538 <b>$ git checkout -b erlang</b>
539 Switched to a new branch 'erlang'
540 <b>$ vim erlang_hw.erl</b>
541 <b>$ git add erlang_hw.erl </b>
542 <b>$ git commit -m 'added erlang'</b>
543 [erlang ab5ab4c] added erlang
544 1 files changed, 5 insertions(+), 0 deletions(-)
545 create mode 100644 erlang_hw.erl
546 </pre>
547
548 <p>由于我们玩函数式编程很开心,以至于沉迷其中,又在“erlang”分支中添加了一个 Haskell 的示例程序。
549 </p>
550
551 <pre>
552 <b>$ vim haskell.hs</b>
553 <b>$ git add haskell.hs </b>
554 <b>$ git commit -m 'added haskell'</b>
555 [erlang 1834130] added haskell
556 1 files changed, 4 insertions(+), 0 deletions(-)
557 create mode 100644 haskell.hs
558 </pre>
559
560 <p>最后,我们决定还是把 Ruby 程序的类名改回原先的样子。与其创建另一个分支,我们可以返回主分支,改变它,然后直接提交。
561 </p>
562
563 <pre>
564 <b>$ git checkout master</b>
565 Switched to branch 'master'
566 <b>$ ls</b>
567 README ruby.rb
568 <b>$ vim ruby.rb </b>
569 <b>$ git commit -am 'reverted to old class name'</b>
570 [master 594f90b] reverted to old class name
571 1 files changed, 2 insertions(+), 2 deletions(-)
572 </pre>
573
574 <p>现在假设我们有段时间不做这个项目了,我们做别的去了。
575 当我们回来的时候,我们想知道“erlang”分支都是啥,而主分支的进度又是怎样。
576 仅仅看分支的名字,我们是无从知道自己还在里面有 Haskell 的改动的,但是用 <code>git log</code> 我们就可以。
577 如果你在命令行中提供一个分支名字,它就会显示该分支历史中“可及”的提交,即从该分支创立起可追溯的影响了最终的快照的提交。
578 </p>
579
580 <pre>
581 <b>$ git log --oneline erlang</b>
582 <span class="hl">1834130 added haskell</span>
583 ab5ab4c added erlang
584 8d585ea Merge branch 'fix_readme'
585 3cbb6aa fixed readme title differently
586 3ac015d fixed readme title
587 558151a Merge branch 'change_class'
588 b7ae93b added from ruby
589 3467b0a changed the class name
590 17f4acf first commit
591 </pre>
592
593 <p>如此,我们很容易就看到分支里头还包括了 Haskell 代码(高亮显示了)。
594 更酷的是,我们很容易地告诉 Git,我们只对某个分支中可及的提交感兴趣。换句话说,某分支中与其他分支相比唯一的提交。
595 </p>
596
597 <p>在此例中,如果我们想要合并“erlang”分支,我们需要看当合并的时候,都有啥提交会作用到我们的快照上去。
598 我们告诉 Git 的方式是,在不想要看到的分支前放一个 <code>^</code>。
599 例如,如果我们想要看“erlang”分支中但不在主分支中的提交,我们可以用 <code>erlang ^master</code>,或者反之。
600 </p>
601
602 <pre>
603 <b>$ git log --oneline erlang ^master</b>
604 1834130 added haskell
605 ab5ab4c added erlang
606 <b>$ git log --oneline master ^erlang</b>
607 594f90b reverted to old class name
608 </pre>
609
610 <p>这为我们提供了一个良好的、简易的分支管理工具。它使我们能够非常容易地查看对某个分支唯一的提交,从而知道我们缺少什么,以及当我们要合并时,会有什么被合并进去。
611 </p>
612
613 <p class="nutshell">
614 <b>简而言之</b> 使用 <code>git log</code> 列出促成当前分支目前的快照的提交历史记录。这使你能够看到项目是如何到达现在的状况的。
615 </p>
616
617 </div>
618 </div>
619
620 <div class="box">
621 <h2>
622 <span class="docs">
623 <a target="new" href="http://git-scm.com/docs/git-tag">文档</a> &nbsp;
624 <a target="new" href="http://git-scm.com/book/en/Git-Basics-Tagging">书</a>
625 </span>
626 <a name="tag">git tag</a>
627 <span class="desc">给历史记录中的某个重要的一点打上标签</span>
628 </h2>
629
630 <div class="block">
631
632 <p>
633 如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 <code>git tag</code> 给它打上标签。
634 该 <code>tag</code> 命令基本上会给该特殊提交打上永久的书签,从而使你在将来能够用它与其他提交比较。
635 通常,你会在切取一个发布版本或者交付一些东西的时候打个标签。
636 </p>
637
638 <p>比如说,我们想为我们的 Hello World 项目发布一个“1.0”版本。
639 我们可以用 <code>git tag -a v1.0</code> 命令给最新一次提交打上(<code>HEAD</code>)“v1.0”的标签。
640 <code>-a</code> 选项意为“创建一个带注解的标签”,从而使你为标签添加注解。绝大部分时候都会这么做的。
641 不用 <code>-a</code> 选项也可以执行的,但它不会记录这标签是啥时候打的,谁打的,也不会让你添加个标签的注解。
642 我推荐一直创建带注解的标签。
643 </p>
644
645 <pre>
646 <b>$ git tag -a v1.0 </b>
647 </pre>
648
649 <p>当你执行 <code>git tag -a</code> 命令时,Git 会打开你的编辑器,让你写一句标签注解,就像你给提交写注解一样。
650 </p>
651
652 <p>现在,注意当我们执行 <code>git log --decorate</code> 时,我们可以看到我们的标签了:
653 </p>
654
655 <pre>
656 <b>$ git log --oneline --decorate --graph</b>
657 * 594f90b (HEAD, <span class="hl">tag: v1.0</span>, master) reverted to old class name
658 * 8d585ea Merge branch 'fix_readme'
659 |\
660 | * 3ac015d (fix_readme) fixed readme title
661 * | 3cbb6aa fixed readme title differently
662 |/
663 * 558151a Merge branch 'change_class'
664 |\
665 | * 3467b0a changed the class name
666 * | b7ae93b added from ruby
667 |/
668 * 17f4acf first commit
669 </pre>
670
671 <p>如果我们有新提交,该标签依然会待在该提交的边上,所以我们已经给那个特定快照永久打上标签,并且能够将它与未来的快照做比较。
672 </p>
673
674 <p>不过我们并不需要给当前提交打标签。如果我们忘了给某个提交打标签,又将它发布了,我们可以给它追加标签。
675 在相同的命令末尾加上提交的 SHA,执行,就可以了。
676 例如,假设我们发布了提交 <code>558151a</code>(几个提交之前的事情了),但是那时候忘了给它打标签。
677 我们现在也可以:</p>
678
679 <pre>
680 <b>$ git tag -a v0.9 558151a</b>
681 <b>$ git log --oneline --decorate --graph</b>
682 * 594f90b (HEAD, tag: v1.0, master) reverted to old class name
683 * 8d585ea Merge branch 'fix_readme'
684 |\
685 | * 3ac015d (fix_readme) fixed readme title
686 * | 3cbb6aa fixed readme title differently
687 |/
688 * 558151a (<span class="hl">tag: v0.9</span>) Merge branch 'change_class'
689 |\
690 | * 3467b0a changed the class name
691 * | b7ae93b added from ruby
692 |/
693 * 17f4acf first commit
694 </pre>
695
696 </div>
697 </div>
698
699 <p><a href="/zh/remotes">到 分享与更新项目 &#187;</a></p>
700