-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1432 lines (1427 loc) · 102 KB
/
index.html
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noodp" />
<title>Git 使用指南 - 夜航星</title><meta name="Description" content="个人博客"><meta property="og:title" content="Git 使用指南" />
<meta property="og:description" content="Git 是目前世界上最先进的分布式文本文件版本控制系统 Git 快速上手 Cheat Sheet:workspace :: Git Cheatsheet 、常用 Git 命令清单 - 阮一峰的网络日志 Git 使用流程" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://austinxt.github.io/2019-03-26-git/" /><meta property="og:image" content="https://austinxt.github.io/images/avatar.png"/><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2019-04-06T00:00:00+08:00" />
<meta property="article:modified_time" content="2019-04-06T00:00:00+08:00" /><meta property="og:site_name" content="夜航星" />
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://austinxt.github.io/images/avatar.png"/>
<meta name="twitter:title" content="Git 使用指南"/>
<meta name="twitter:description" content="Git 是目前世界上最先进的分布式文本文件版本控制系统 Git 快速上手 Cheat Sheet:workspace :: Git Cheatsheet 、常用 Git 命令清单 - 阮一峰的网络日志 Git 使用流程"/>
<meta name="application-name" content="夜航星">
<meta name="apple-mobile-web-app-title" content="夜航星"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://austinxt.github.io/2019-03-26-git/" /><link rel="prev" href="https://austinxt.github.io/2019-04-06-deploy-django/" /><link rel="next" href="https://austinxt.github.io/2019-07-15-cancer-history/" /><link rel="stylesheet" href="/css/style.min.87bf1911dd101ec4f361dc638848b84bc1cdf6bfede2bce9f7291cbf99fdcc4d.css" integrity="sha256-h78ZEd0QHsTzYdxjiEi4S8HN9r/t4rzp9ykcv5n9zE0="><link rel="preload" href="/lib/fontawesome-free/all.min.0df5a33710e433de1f5415b1d47e4130ca7466aee5b81955f1045c4844bbb3ed.css" integrity="sha256-DfWjNxDkM94fVBWx1H5BMMp0Zq7luBlV8QRcSES7s+0=" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/lib/fontawesome-free/all.min.0df5a33710e433de1f5415b1d47e4130ca7466aee5b81955f1045c4844bbb3ed.css" integrity="sha256-DfWjNxDkM94fVBWx1H5BMMp0Zq7luBlV8QRcSES7s+0="></noscript><link rel="preload" href="/lib/animate/animate.min.5fbaeb9f8e25d7e0143bae61d4b1802c16ce7390b96ceb2d498b0d96ff4c853f.css" integrity="sha256-X7rrn44l1+AUO65h1LGALBbOc5C5bOstSYsNlv9MhT8=" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/lib/animate/animate.min.5fbaeb9f8e25d7e0143bae61d4b1802c16ce7390b96ceb2d498b0d96ff4c853f.css" integrity="sha256-X7rrn44l1+AUO65h1LGALBbOc5C5bOstSYsNlv9MhT8="></noscript><script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "BlogPosting",
"headline": "Git 使用指南",
"inLanguage": "zh-CN",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https:\/\/austinxt.github.io\/2019-03-26-git\/"
},"genre": "posts","keywords": "Git","wordcount": 8548 ,
"url": "https:\/\/austinxt.github.io\/2019-03-26-git\/","datePublished": "2019-04-06T00:00:00+08:00","dateModified": "2019-04-06T00:00:00+08:00","publisher": {
"@type": "Organization",
"name": ""},"author": {
"@type": "Person",
"name": "夜航星"
},"description": ""
}
</script></head>
<body data-header-desktop="fixed" data-header-mobile="auto"><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>
<div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
<div class="header-wrapper">
<div class="header-title">
<a href="/" title="夜航星">夜航星</a>
</div>
<div class="menu">
<div class="menu-inner"><a class="menu-item" href="/talks/"> 呓语 </a><a class="menu-item" href="/posts/" title="文章"> 文章 </a><a class="menu-item" href="/tags/"> 标签 </a><a class="menu-item" href="/categories/"> 分类 </a><span class="menu-item delimiter"></span><span class="menu-item search" id="search-desktop">
<input type="text" placeholder="搜索标题或内容" id="search-input-desktop">
<a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-desktop" title="Search">
<i class="fas fa-search fa-fw" aria-hidden="true"></i>
</a>
<a href="javascript:void(0);" class="search-button search-clear" id="search-clear-desktop" title="Clear">
<i class="fas fa-times-circle fa-fw" aria-hidden="true"></i>
</a>
<span class="search-button search-loading" id="search-loading-desktop">
<i class="fas fa-spinner fa-fw fa-spin" aria-hidden="true"></i>
</span>
</span><a href="javascript:void(0);" class="menu-item theme-switch" title="Switch Theme">
<i class="fas fa-adjust fa-fw" aria-hidden="true"></i>
</a>
</div>
</div>
</div>
</header><header class="mobile" id="header-mobile">
<div class="header-container">
<div class="header-wrapper">
<div class="header-title">
<a href="/" title="夜航星">夜航星</a>
</div>
<div class="menu-toggle" id="menu-toggle-mobile">
<span></span><span></span><span></span>
</div>
</div>
<div class="menu" id="menu-mobile"><div class="search-wrapper">
<div class="search mobile" id="search-mobile">
<input type="text" placeholder="搜索标题或内容" id="search-input-mobile">
<a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-mobile" title="Search">
<i class="fas fa-search fa-fw" aria-hidden="true"></i>
</a>
<a href="javascript:void(0);" class="search-button search-clear" id="search-clear-mobile" title="Clear">
<i class="fas fa-times-circle fa-fw" aria-hidden="true"></i>
</a>
<span class="search-button search-loading" id="search-loading-mobile">
<i class="fas fa-spinner fa-fw fa-spin" aria-hidden="true"></i>
</span>
</div>
<a href="javascript:void(0);" class="search-cancel" id="search-cancel-mobile">
Cancel
</a>
</div><a class="menu-item" href="/talks/" title="">呓语</a><a class="menu-item" href="/posts/" title="文章">文章</a><a class="menu-item" href="/tags/" title="">标签</a><a class="menu-item" href="/categories/" title="">分类</a><a href="javascript:void(0);" class="menu-item theme-switch" title="Switch Theme">
<i class="fas fa-adjust fa-fw" aria-hidden="true"></i>
</a></div>
</div>
</header><div class="search-dropdown desktop">
<div id="search-dropdown-desktop"></div>
</div>
<div class="search-dropdown mobile">
<div id="search-dropdown-mobile"></div>
</div><main class="main">
<div class="container"><div class="toc" id="toc-auto">
<h2 class="toc-title">Contents</h2>
<div class="toc-content" id="toc-content-auto"></div>
</div><article class="page single"><h1 class="single-title animate__animated animate__flipInX">Git 使用指南</h1><div class="post-meta">
<div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel="author" class="author"><i class="fas fa-user-circle fa-fw" aria-hidden="true"></i>夜航星</a></span> <span class="post-category">included in <a href="/categories/%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/"><i class="far fa-folder fa-fw" aria-hidden="true"></i>知识整理</a></span></div>
<div class="post-meta-line"><i class="far fa-calendar-alt fa-fw" aria-hidden="true"></i> <time datetime="2019-04-06">2019-04-06</time> <i class="fas fa-pencil-alt fa-fw" aria-hidden="true"></i> 8548 words
<i class="far fa-clock fa-fw" aria-hidden="true"></i> 18 minutes </div>
</div><div class="details toc" id="toc-static" data-kept="">
<div class="details-summary toc-title">
<span>Contents</span>
<span><i class="details-icon fas fa-angle-right" aria-hidden="true"></i></span>
</div>
<div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
<ul>
<li><a href="#git-快速上手">Git 快速上手</a>
<ul>
<li><a href="#git-基本概念">Git 基本概念</a></li>
<li><a href="#安装-git">安装 Git</a>
<ul>
<li><a href="#linux">Linux</a></li>
<li><a href="#macos">macOS</a></li>
</ul>
</li>
<li><a href="#全局配置">全局配置</a></li>
<li><a href="#创建版本库-repository仓库-和提交修改">创建版本库 (repository,仓库) 和提交修改</a>
<ul>
<li><a href="#创建版本库">创建版本库</a></li>
<li><a href="#把工作区目录的修改添加到暂存区">把工作区(目录)的修改添加到暂存区</a></li>
<li><a href="#查看仓库当前状态">查看仓库当前状态</a></li>
<li><a href="#提交到当前分支">提交到当前分支</a></li>
<li><a href="#一步将工作区的修改提交到分支">一步将工作区的修改提交到分支</a></li>
</ul>
</li>
<li><a href="#撤销修改和版本回滚">撤销修改和版本回滚</a>
<ul>
<li><a href="#查看工作区的修改">查看工作区的修改</a></li>
<li><a href="#撤销工作区修改">撤销工作区修改</a></li>
<li><a href="#撤销添加到暂存区">撤销添加到暂存区</a></li>
<li><a href="#版本回退">版本回退</a></li>
<li><a href="#删除文件">删除文件</a></li>
</ul>
</li>
<li><a href="#远程仓库">远程仓库</a>
<ul>
<li><a href="#建立本地-ssh-key-密钥对">建立本地 SSH Key 密钥对</a></li>
<li><a href="#把公钥给-github">把公钥给 GitHub</a></li>
<li><a href="#关联远程仓库">关联远程仓库</a></li>
<li><a href="#从远程库克隆">从远程库克隆</a></li>
<li><a href="#ssh-警告">SSH 警告</a></li>
<li><a href="#忽略特殊文件">忽略特殊文件</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#分支管理">分支管理</a>
<ul>
<li><a href="#创建与合并分支">创建与合并分支</a>
<ul>
<li><a href="#创建分支">创建分支</a></li>
<li><a href="#合并分支">合并分支</a></li>
<li><a href="#解决分支合并冲突">解决分支合并冲突</a></li>
</ul>
</li>
<li><a href="#分支管理策略">分支管理策略</a>
<ul>
<li><a href="#bug-分支">Bug 分支</a></li>
<li><a href="#feature-分支">Feature 分支</a></li>
<li><a href="#git-工作流程">Git 工作流程</a></li>
</ul>
</li>
<li><a href="#多人协作开发">多人协作开发</a>
<ul>
<li><a href="#推送分支">推送分支</a></li>
<li><a href="#抓取分支">抓取分支</a></li>
<li><a href="#rebase">Rebase</a></li>
</ul>
</li>
<li><a href="#git-远程操作">Git 远程操作</a>
<ul>
<li><a href="#git-remote">git remote</a></li>
<li><a href="#git-fetch">git fetch</a></li>
<li><a href="#git-pull">git pull</a></li>
<li><a href="#git-push">git push</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#标签管理">标签管理</a>
<ul>
<li><a href="#创建标签">创建标签</a></li>
<li><a href="#操作标签">操作标签</a></li>
</ul>
</li>
<li><a href="#其他-git-技巧">其他 Git 技巧</a>
<ul>
<li><a href="#配置别名">配置别名</a></li>
<li><a href="#搭建-git-服务器">搭建 Git 服务器</a></li>
</ul>
</li>
<li><a href="#ref">Ref</a></li>
<li><a href="#changelog">ChangeLog</a></li>
</ul>
</nav></div>
</div><div class="content" id="content"><blockquote>
<p>Git 是目前世界上最先进的分布式文本文件版本控制系统</p>
</blockquote>
<h2 id="git-快速上手">Git 快速上手</h2>
<p>Cheat Sheet:<a href="http://ndpsoftware.com/git-cheatsheet.html#loc=workspace;" target="_blank" rel="noopener noreffer ">workspace :: Git Cheatsheet</a> 、<a href="http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html" target="_blank" rel="noopener noreffer ">常用 Git 命令清单 - 阮一峰的网络日志</a></p>
<p>Git 使用流程:<a href="http://www.ruanyifeng.com/blog/2015/08/git-use-process.html" target="_blank" rel="noopener noreffer ">Git 使用规范流程 - 阮一峰的网络日志</a></p>
<h3 id="git-基本概念">Git 基本概念</h3>
<ul>
<li>工作区(Working Directory),即电脑里能看到的目录</li>
<li>版本库/本地仓库(Repository),即工作区的隐藏目录 <code>.git</code> ,包含暂存区、分支、HEAD 等</li>
<li>暂存区(stage/index),存在于版本库之中</li>
<li>分支(branch),Git 创建版本库时,会自动创建第一个分支 <code>master</code> ,以及指向 <code>master</code> 的一个指针 <code>HEAD</code></li>
<li>远程仓库(remote repository)</li>
</ul>
<p><img
class="lazyload"
src="/svg/loading.min.svg"
data-src="http://gityuan.com/images/git/1.png"
data-srcset="http://gityuan.com/images/git/1.png, http://gityuan.com/images/git/1.png 1.5x, http://gityuan.com/images/git/1.png 2x"
data-sizes="auto"
alt="http://gityuan.com/images/git/1.png"
title="http://gityuan.com/images/git/1.png" /></p>
<p>上图来自:<a href="http://gityuan.com/2015/06/27/git-notes/" target="_blank" rel="noopener noreffer ">Git 常用命令 - Gityuan 博客 | 袁辉辉的 Android 博客</a></p>
<h3 id="安装-git">安装 Git</h3>
<h4 id="linux">Linux</h4>
<p>可以用 <code>git</code> 在终端测试系统是否安装了 Git,安装方法是 <code>sudo apt-get install git</code></p>
<h4 id="macos">macOS</h4>
<p>一是安装 homebrew,然后通过 homebrew 安装 Git,具体方法请参考 homebrew 的文档:<a href="https://brew.sh/" target="_blank" rel="noopener noreffer ">The missing package manager for macOS (or Linux)</a>。</p>
<p>二是直接从 AppStore 安装 Xcode,更简单,也更推荐。Xcode 集成了 Git,不过默认没有安装,你需要运行 Xcode,选择菜单 <code>Xcode->Preferences</code> ,在弹出窗口中找到 <code>Downloads</code> ,选择 <code>Command Line Tools</code>,点 <code>Install</code>就可以完成安装了。</p>
<h3 id="全局配置">全局配置</h3>
<p>安装完成后,还需要最后一步设置,在命令行输入:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git config --global user.name <span class="s2">"Your Name"</span>
</span></span><span class="line"><span class="cl">$ git config --global user.email <span class="s2">"email@example.com"</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>因为 Git 是分布式版本控制系统,所以要表明各自的身份。</p>
<h3 id="创建版本库-repository仓库-和提交修改">创建版本库 (repository,仓库) 和提交修改</h3>
<p>版本库可以简单理解成一个目录,这个目录里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以还原。</p>
<h4 id="创建版本库">创建版本库</h4>
<p>进入到一个目录,通过 <code>git init</code> 命令把这个目录变成 Git 可以管理的仓库,此时输入 <code>ls -ah</code> 命令,发现当前目录下多了一个 <code>.git</code> 的目录</p>
<h4 id="把工作区目录的修改添加到暂存区">把工作区(目录)的修改添加到暂存区</h4>
<p>若新建了 <code>README.md</code> ,用命令 <code>git add README.md</code> 把文件添加到仓库暂存区,<code>git add .</code> 可将所有的修改添加到暂存区</p>
<h4 id="查看仓库当前状态">查看仓库当前状态</h4>
<p>用命令 <code>git status</code> 可以查看仓库当前状态</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">On branch master
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">No commits yet
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Changes to be committed:
</span></span><span class="line"><span class="cl"> (use "git rm --cached <file>..." to unstage)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> new file: README.md
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="提交到当前分支">提交到当前分支</h4>
<p>用命令 <code>git commit -m "commit message"</code> 把本次修改提交到当前分支,此时工作区变为 <code>nothing to commit, working tree clean</code></p>
<h4 id="一步将工作区的修改提交到分支">一步将工作区的修改提交到分支</h4>
<p>用命令 <code>git commit -am "commit message"</code> 可以提交工作区所有 tracked 的修改到当前分支。</p>
<h3 id="撤销修改和版本回滚">撤销修改和版本回滚</h3>
<p>万事都有失,Git 挽回失误的操作有撤销「添加到暂存区」、撤销「本次提交到当前分支」、回滚到「之前的某一次提交」。</p>
<h4 id="查看工作区的修改">查看工作区的修改</h4>
<p><code>git diff</code> 查看上次对工作区的修改,显示工作区与暂存区的比较(优先)或工作区与当前分支比较,显示的格式正是 Unix 通用的 diff 格式。</p>
<h4 id="撤销工作区修改">撤销工作区修改</h4>
<p>用 <code>git status</code> 查看当前仓库状态时,<code>Changes not staged for commit:</code> 下面会提示如何撤销工作区修改, <code>use "git checkout -- <file>..." to discard changes in working directory</code> ,即用 <code>git checkout -- <file></code> 将文件在工作区的修改恢复到上一次添加到暂存区后的状态(优先)或当前分支的状态。</p>
<h4 id="撤销添加到暂存区">撤销添加到暂存区</h4>
<p>用 <code>git status</code> 查看当前仓库状态时,<code>Changes to be committed:</code> 下面会提示如何撤销暂存区的修改, <code>use "git reset HEAD <file>..." to unstage</code> ,即用 <code>git reset HEAD <file></code> 把暂存区的修改撤销掉,重新放回工作区。若再用 <code>git checkout -- <file></code> 可以把文件恢复与版本库中当前版本一致。</p>
<h4 id="版本回退">版本回退</h4>
<p>用 <code>git log</code> 命令查看提交日志(从最近到最远),加上 <code>--pretty=oneline</code> 参数,仅显示版本号(commit id)、commit message 和 HEAD 指针的指向当前版本。</p>
<p>使用 <code>git reset</code> 命令可退回以前版本,原理是改变 HEAD 指针的指向,其间提交的版本不可在 <code>git log</code> 命令下显示。</p>
<ul>
<li>使用 <code>git reset --hard HEAD^</code> 命令退回到上一个版本</li>
<li>或用 <code>git reset --hard HEAD~n</code> 往前退回 n 版本</li>
<li>或用 <code>git reset -- hard <前五位 commit id></code> 回退到一特定版本</li>
</ul>
<p>Git 提供了一个命令 <code>git reflog</code> 来记录每一次提交,包括 HEAD 指针之后的版本,用 <code>git reset -- hard <前五位 commit id></code> 依旧可以回退到一特定版本。</p>
<h4 id="删除文件">删除文件</h4>
<p>从版本库中删除文件可用命令 <code>git rm <file></code> ,参数 <code> —cached</code> 保存工作区的文件, <code> -f</code> 删除工作区和版本库的文件。</p>
<h3 id="远程仓库">远程仓库</h3>
<p>远程仓库以 GitHub 为例。</p>
<h4 id="建立本地-ssh-key-密钥对">建立本地 SSH Key 密钥对</h4>
<p>本地 Git 仓库和 GitHub 仓库之间的传输是通过 SSH 加密的,需要创建 SSH Key。</p>
<p>在用户主目录下,看看有没有 <code>.ssh/ </code> 目录,若有,再看看这个目录下有没有 <code>id_rsa</code> 和 <code>id_rsa.pub</code> 文件,若有,可直接跳过这一步。若没有,打开 Shell 创建 SSH Key,<code>ssh-keygen -t rsa -C "youremail@example.com"</code> ,为了方便无需设置密码。</p>
<p>一路回车后,在用户主目录里找到 <code>.ssh</code> 目录,里面有 <code>id_rsa</code> 和 <code>id_rsa.pub</code> 两个文件,即 SSH Key 的密钥对, <code>id_rsa</code> 是私钥,不能泄露出去, <code>id_rsa.pub</code> 是公钥。</p>
<h4 id="把公钥给-github">把公钥给 GitHub</h4>
<p>登陆 GitHub,打开 <code>Account settings</code> ,进入 <code>SSH Keys</code> 页面,点 <code>Add SSH Key</code> ,填上任意 Title,在 Key 文本框里粘贴 <code>id_rsa.pub</code> 文件的内容。</p>
<h4 id="关联远程仓库">关联远程仓库</h4>
<p>在 GitHub 新建一个空仓库,根据 GitHub 提示,在本地仓库下运行 <code>git remote add origin git@github.com:<GitHub Username>/<repository name>.git</code> 命令。 <code>origin</code> 就是远程仓库的名字,是 Git 的默认叫法。</p>
<p>下一步把本地库的所有内容推送到远程库上,运行 <code>git push -u origin master</code> 可以把当前分支 <code>master</code> 推送到 <code>origin</code> 。参数 <code>-u</code> 会把本地的 <code>master</code> 分支与远程的 <code>master</code> 分支关联,以后推送或拉取时就可以简化为 <code>git push</code> 和 <code>git pull</code> 。</p>
<h4 id="从远程库克隆">从远程库克隆</h4>
<p>运行 <code>git clone git@github.com:<GitHub Username>/<repository name>.git</code> 可以将远程仓库克隆到本地,会在当前目录下生成一个 <code>repository name</code> 文件。</p>
<p>Git 支持多种协议,包括 <code>https </code>,但通过 <code>ssh</code> 支持的原生 <code>git</code> 协议速度最快。</p>
<h4 id="ssh-警告">SSH 警告</h4>
<p>第一次使用 Git 的 <code>clone</code> 或者 <code>push</code> 命令连接 GitHub 时,会得到一个警告:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
</span></span><span class="line"><span class="cl">RSA key fingerprint is xx.xx.xx.xx.xx.
</span></span><span class="line"><span class="cl">Are you sure you want to continue connecting (yes/no)?
</span></span></code></pre></td></tr></table>
</div>
</div><p>这是因为 Git 使用 SSH 连接,而 SSH 连接在第一次验证 GitHub 服务器的 Key 时,需要你确认 GitHub 的 Key 的指纹信息是否真的来自 GitHub 的服务器,输入<code>yes</code> 回车即可。此时 <code>~/.ssh/konwn_host</code> 文件里会多一个 github.com host.</p>
<h4 id="忽略特殊文件">忽略特殊文件</h4>
<p>在 Git 工作区的根目录下创建一个特殊的 <code>.gitignore</code> 文件,然后把要忽略的文件名填进去,Git 就会自动忽略这些文件。GitHub 已经为我们准备了各种配置文件:<a href="https://github.com/github/gitignore" target="_blank" rel="noopener noreffer ">github/gitignore: A collection of useful .gitignore templates</a> ,再把 <code>.gitignore</code> 也提交到 Git。</p>
<p>忽略文件的原则是:</p>
<ol>
<li>忽略操作系统自动生成的文件,比如缩略图等;</li>
<li>忽略编译生成的中间文件、可执行文件等,也就是若一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如 Python 编译产生的 <code>.pyc</code> 文件、 <code>.pyo</code> 文件和 <code>dist</code> 目录;</li>
<li>忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。</li>
</ol>
<p>若确实想添加被忽略的文件,可以用 <code>-f</code> 强制添加到 Git,<code>git add -f test.pyc</code> 。</p>
<p><code>git check-ignore </code>命令检查被忽略的文件来自哪条规则</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git check-ignore -v test.pyc
</span></span><span class="line"><span class="cl">.gitignore:2:__pycache__/ test.pyc
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>.gitignore </code>的第 2 行规则忽略了该文件。</p>
<h2 id="分支管理">分支管理</h2>
<p>分支管理可以让开发者从容地写一个新功能,而不用担心代码无处提交。</p>
<h3 id="创建与合并分支">创建与合并分支</h3>
<p>截止到目前,在 Git 里只有一个分支,叫主分支,即<code>master</code>分支。<code>master</code> 指向提交,<code>HEAD </code>指向当前分支,每次提交,<code>master </code>分支都会向前移动一步。</p>
<h4 id="创建分支">创建分支</h4>
<p>运行 <code>git checkout -b dev</code> 创建新的分支,并切换到 <code>dev</code> 分支。 <code>git checkout</code> 加上 <code>-b</code>参数表示创建并切换,相当于创建新的分支 <code>git branch dev</code> 加上切换分支 <code>git checkout dev</code> .</p>
<p>创建新的分支时,例如 <code>dev</code> ,Git 会新建了一个指针叫 <code>dev</code> ,指向 <code>master</code> 相同的提交,再把 <code>HEAD</code> 指向 <code>dev</code> ,就表示当前分支在 <code>dev</code> 上。现在开始,对工作区的修改和提交就是针对 <code>dev</code> 分支,比如新提交一次后,<code>dev </code>指针往前移动一步,而 <code>master</code> 指针不变。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> master
</span></span><span class="line"><span class="cl"> ↓
</span></span><span class="line"><span class="cl">○---○---○---○---○
</span></span><span class="line"><span class="cl"> ↑
</span></span><span class="line"><span class="cl"> dev ← HEAD
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="合并分支">合并分支</h4>
<p>假如在 <code>dev</code> 上的工作完成了,就可以把 <code>dev</code> 合并到 <code>master</code> 上,最简单的方法,就是直接把 <code>master</code> 指向 <code>dev</code> 的当前提交。</p>
<p>命令是运行 <code>git checkout master</code> 把 HEAD 指针指向 <code>master</code> 分支,然后运行 <code>git merge dev</code> 把 <code>dev</code> 分支的工作成果合并到 <code>master</code> 分支上。终端返回 <code>Fast-forward</code> 信息表示这次合并是「快进模式」,即直接把 <code>master</code> 指向 <code>dev</code> 的当前提交。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> master ← HEAD
</span></span><span class="line"><span class="cl"> ↓
</span></span><span class="line"><span class="cl">○---○---○---○---○
</span></span><span class="line"><span class="cl"> ↑
</span></span><span class="line"><span class="cl"> dev
</span></span></code></pre></td></tr></table>
</div>
</div><p>但不是每次合并都能 <code>Fast-forward</code> ,后面会讲其他方式的合并。</p>
<p>合并完分支后,可以删除 <code>dev</code> 分支, <code>git branch -d dev</code> ,即删除<code>dev</code> 指针。删除后,查看 <code>branch</code> , <code>git branch</code> ,只剩下 <code>master</code> 分支。</p>
<h4 id="解决分支合并冲突">解决分支合并冲突</h4>
<p>若在新建的分支 <code>dev</code> 修改了 <code>README.md</code> 并提交,又切换回 <code>master</code> 分支,修改了 <code>README.md</code> 并提交,则此时的 <code>master</code> 和 <code>dev</code> 处在不同的提交时间轴上。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> master ← HEAD
</span></span><span class="line"><span class="cl"> ↓
</span></span><span class="line"><span class="cl">○---○---○---○---○
</span></span><span class="line"><span class="cl"> \---○
</span></span><span class="line"><span class="cl"> ↑
</span></span><span class="line"><span class="cl"> dev
</span></span></code></pre></td></tr></table>
</div>
</div><p>此时运行 <code>git merge dev</code> ,会报错( <code>git status</code> 也会提示冲突的文件)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Auto-merging README.md
</span></span><span class="line"><span class="cl">CONFLICT (content): Merge conflict in README.md
</span></span><span class="line"><span class="cl">Automatic merge failed; fix conflicts and then commit the result.
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>README.md</code> 文件存在冲突,必须手动解决冲突后再提交。查看 <code>README.md</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o"><<<<<<</span>< HEAD
</span></span><span class="line"><span class="cl">Creating a new branch is quick <span class="p">&</span> simple.
</span></span><span class="line"><span class="cl"><span class="o">=======</span>
</span></span><span class="line"><span class="cl">Creating a new branch is quick AND simple.
</span></span><span class="line"><span class="cl">>>>>>>> dev
</span></span></code></pre></td></tr></table>
</div>
</div><p>Git 用 <code><<<<<<<</code> , <code>======= </code>, <code>>>>>>>></code> 标记出不同分支的内容,假如修改 <code>README.md</code> 为</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Creating a new branch is quick and simple.
</span></span></code></pre></td></tr></table>
</div>
</div><p>再提交</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git add README.md
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">"conflict fixed"</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>现在 <code>master</code> 分支和 <code>dev</code> 成了下图所示</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> master ← HEAD
</span></span><span class="line"><span class="cl"> ↓
</span></span><span class="line"><span class="cl">○---○---○---○---○---○
</span></span><span class="line"><span class="cl"> \--○--/
</span></span><span class="line"><span class="cl"> ↑
</span></span><span class="line"><span class="cl"> dev
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>git log --graph --pretty=oneline --abbrev-commit</code> 可以看到分支的合并情况。 <code> —graph</code> 参数可查看分支合并图,<code>--abbrev-commit</code> 参数可缩写 commit 信息。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">* b75b466 (HEAD -> master) conflict fixed
</span></span><span class="line"><span class="cl">|\
</span></span><span class="line"><span class="cl">| * 3d0eb40 (feature1) using And
</span></span><span class="line"><span class="cl">* | 42c89d0 using &
</span></span><span class="line"><span class="cl">|/
</span></span><span class="line"><span class="cl">* 01c11b4 branch test
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>删除 <code>dev</code> 分支。</p>
<h3 id="分支管理策略">分支管理策略</h3>
<p>通常,合并分支时,若可能,Git 会用 <code>Fast forward</code> 模式,但这种模式下,删除分支后会丢掉分支信息。</p>
<p>若要强制禁用 <code>Fast forward </code>模式,Git 就会在 merge 时生成一个新的 commit,这样,从分支历史上就可以看出分支信息。可以在 merge 时添加 <code>--no-ff</code> 参数在分支历史上呈现合并分支信息,<code>--no-ff</code> 参数表示禁用 <code>Fast forward</code> 。</p>
<p>仍然创建并切换 <code>dev</code> 分支,修改 <code>README.md</code> 文件,并提交一个新的 commit,再切换回 <code>master</code> 。此时运行 <code>git merge --no-ff -m "merge with no-ff" dev</code> ,终端返回</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Merge made by the 'recursive' strategy.
</span></span><span class="line"><span class="cl"> README.md | 1 +
</span></span><span class="line"><span class="cl"> 1 file changed, 1 insertion(+)
</span></span></code></pre></td></tr></table>
</div>
</div><p>合并后,用 <code>git log</code> 查看分支历史</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git log --graph --pretty<span class="o">=</span>oneline --abbrev-commit
</span></span><span class="line"><span class="cl">* 3481f74 <span class="o">(</span>HEAD -> master<span class="o">)</span> merge with no-ff
</span></span><span class="line"><span class="cl"><span class="p">|</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> * 3a86b6c <span class="o">(</span>dev<span class="o">)</span> add merge
</span></span><span class="line"><span class="cl"><span class="p">|</span>/
</span></span><span class="line"><span class="cl">* b75b466 conflict fixed
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>在实际开发中,应该按照几个基本原则进行分支管理:</p>
<ol>
<li><code>master </code>分支应该非常稳定,仅用来发布新版本,平时不能在上面干活;</li>
<li>干活都在 <code>dev</code> 分支上,版本发布时,再把 <code>dev</code> 分支合并到 <code>master</code> 上,在 <code>master</code> 分支发布版本;</li>
<li>团队合作时,每个人都在 <code>dev</code> 分支上干活,每个人都有自己的分支,时不时地往 <code>dev</code> 分支上合并。</li>
</ol>
<h4 id="bug-分支">Bug 分支</h4>
<p>每个 bug 都可以通过一个新的临时分支来修复,修复后合并分支,然后将临时分支删除。</p>
<p>Git 提供了一个 <code>stash</code> 功能,可以把当前工作现场「储藏」起来,等以后恢复现场后继续工作。</p>
<p>在 <code>dev</code> 分支修改 <code>README.md</code> 后,</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git stash
</span></span><span class="line"><span class="cl">Saved working directory and index state WIP on dev: 3a86b6c <span class="nb">test</span> hard merge
</span></span></code></pre></td></tr></table>
</div>
</div><p>现在用 <code>git status</code> 查看工作区,是干净的,因此可以放心地创建分支来修复 bug。</p>
<p>若需要在 <code>master </code>分支上修复 bug,则从 <code>master</code> 创建临时分支。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git checkout master
</span></span><span class="line"><span class="cl">$ git checkout -b issue-101
</span></span></code></pre></td></tr></table>
</div>
</div><p>修改 bug,这里修改了 <code>README.md</code> ,然后提交</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git commit -am <span class="s2">"fix bug 101"</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>issue-101 4d97816<span class="o">]</span> fix bug <span class="m">101</span>
</span></span><span class="line"><span class="cl"> <span class="m">1</span> file changed, <span class="m">1</span> insertion<span class="o">(</span>+<span class="o">)</span>, <span class="m">1</span> deletion<span class="o">(</span>-<span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>修复完成后,切换到 <code>master</code> 分支,并完成合并,最后删除 <code>issue-101</code> 分支</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git checkout master
</span></span><span class="line"><span class="cl">$ git merge --no-ff -m <span class="s2">"merged bug fix 101"</span> issue-101
</span></span><span class="line"><span class="cl">Merge made by the <span class="s1">'recursive'</span> strategy.
</span></span><span class="line"><span class="cl"> readme.txt <span class="p">|</span> <span class="m">2</span> +-
</span></span><span class="line"><span class="cl"> <span class="m">1</span> file changed, <span class="m">1</span> insertion<span class="o">(</span>+<span class="o">)</span>, <span class="m">1</span> deletion<span class="o">(</span>-<span class="o">)</span>
</span></span><span class="line"><span class="cl">$ git branch -d issue-101
</span></span></code></pre></td></tr></table>
</div>
</div><p>重新回到 <code>dev</code> 分支干活</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git checkout dev
</span></span><span class="line"><span class="cl">$ git status
</span></span><span class="line"><span class="cl">On branch dev
</span></span><span class="line"><span class="cl">nothing to commit, working tree clean
</span></span></code></pre></td></tr></table>
</div>
</div><p>工作区是干净的,用 <code>git stash list</code> 命令工作现场</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git stash list
</span></span><span class="line"><span class="cl">stash@<span class="o">{</span>0<span class="o">}</span>: WIP on dev: 3a86b6c add merge
</span></span></code></pre></td></tr></table>
</div>
</div><p>恢复工作现场有两个办法</p>
<ul>
<li>用 <code>git stash apply</code> 恢复,但是恢复后,stash 内容并不删除,需要用 <code>git stash drop</code> 来删除</li>
<li>用 <code>git stash pop</code> ,恢复的同时把 stash 内容也删了</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git stash pop
</span></span><span class="line"><span class="cl">On branch dev
</span></span><span class="line"><span class="cl">Changes not staged <span class="k">for</span> commit:
</span></span><span class="line"><span class="cl"> <span class="o">(</span>use <span class="s2">"git add <file>..."</span> to update what will be committed<span class="o">)</span>
</span></span><span class="line"><span class="cl"> <span class="o">(</span>use <span class="s2">"git checkout -- <file>..."</span> to discard changes in working directory<span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> modified: README.md
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">no changes added to commit <span class="o">(</span>use <span class="s2">"git add"</span> and/or <span class="s2">"git commit -a"</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">Dropped refs/stash@<span class="o">{</span>0<span class="o">}</span> <span class="o">(</span>e8f4328c3334144570f3c6d38641fc971aa460a2<span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>此外,还可以多次 stash,恢复的时候,先用 <code>git stash list</code> 查看,然后恢复指定的 stash,用命令 <code>git stash apply stash@{0}</code> 。</p>
<h4 id="feature-分支">Feature 分支</h4>
<p>软件开发中,总有无穷无尽的新的功能要不断添加进来。每添加一个新功能,最好在新建分支 <code>feature</code> 上面开发(以免污染 <code>dev</code> ),完成后合并删除 <code>feature</code> 分支。</p>
<p>若新功能突然不需要了,<code>git branch -d feature-name</code> 命令会报错</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">error: The branch 'feature-name' is not fully merged.
</span></span><span class="line"><span class="cl">If you are sure you want to delete it, run 'git branch -D feature-name'.
</span></span></code></pre></td></tr></table>
</div>
</div><p>可以运行 <code>git branch -D feature-name</code> 强行删除。</p>
<h4 id="git-工作流程">Git 工作流程</h4>
<p><a href="http://www.ruanyifeng.com/blog/2015/12/git-workflow.html" target="_blank" rel="noopener noreffer ">Git 工作流程 - 阮一峰的网络日志</a></p>
<p><a href="http://www.ruanyifeng.com/blog/2012/07/git.html" target="_blank" rel="noopener noreffer ">Git 分支管理策略 - 阮一峰的网络日志</a></p>
<h3 id="多人协作开发">多人协作开发</h3>
<p>要查看远程库的信息,用 <code>git remote</code> ,或者用 <code>git remote -v</code> 显示更详细的信息</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git remote -v
</span></span><span class="line"><span class="cl">origin git@github.com:michaelliao/learngit.git <span class="o">(</span>fetch<span class="o">)</span>
</span></span><span class="line"><span class="cl">origin git@github.com:michaelliao/learngit.git <span class="o">(</span>push<span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>上面显示了可以抓取和推送的 <code>origin</code> 的地址,若没有推送权限,就看不到 push 的地址。</p>
<h4 id="推送分支">推送分支</h4>
<p>推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样 Git 就会把该分支推送到远程库对应的远程分支上,例如 <code>git push origin dev</code> 。</p>
<p>有些本地分支不需要往远程推送,有些本地分支需要往远程推送</p>
<ul>
<li><code>master </code> 分支是主分支,要时刻与远程同步;</li>
<li><code>dev</code> 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;</li>
<li>bug 分支只用于在本地修复 bug,就没必要推到远程了;</li>
<li>feature 分支是否推到远程,取决于是否和小伙伴合作在上面开发。</li>
</ul>
<h4 id="抓取分支">抓取分支</h4>
<p>多人协作时,大家都会往 <code>master</code> 和 <code>dev</code> 分支上推送各自的修改。</p>
<p>假设有小伙伴要在 <code>dev</code> 分支上开发,就必须创建远程 <code>origin</code> 的 <code>dev</code> 分支到本地,于是他用命令 <code>git checkout -b dev origin/dev</code> 创建本地 <code>dev</code> 分支。接着他修改了 <code>README.md</code> ,并提交到本地仓库的 <code>dev</code> 分支,然后 <code>git push origin dev</code> 推送到远程仓库。</p>
<p>碰巧你也修改了 <code>README.md</code> ,并提交到本地仓库的 <code>dev</code> 分支。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git push origin dev
</span></span><span class="line"><span class="cl">To github.com:<github username>/<repository>.git
</span></span><span class="line"><span class="cl"> ! <span class="o">[</span>rejected<span class="o">]</span> dev -> dev <span class="o">(</span>non-fast-forward<span class="o">)</span>
</span></span><span class="line"><span class="cl">error: failed to push some refs to <span class="s1">'git@github.com:<github username>/<repository>.git'</span>
</span></span><span class="line"><span class="cl">hint: Updates were rejected because the tip of your current branch is behind
</span></span><span class="line"><span class="cl">hint: its remote counterpart. Integrate the remote changes <span class="o">(</span>e.g.
</span></span><span class="line"><span class="cl">hint: <span class="s1">'git pull ...'</span><span class="o">)</span> before pushing again.
</span></span><span class="line"><span class="cl">hint: See the <span class="s1">'Note about fast-forwards'</span> in <span class="s1">'git push --help'</span> <span class="k">for</span> details.
</span></span></code></pre></td></tr></table>
</div>
</div><p>因为有小伙伴的最新提交和你试图推送的提交有冲突,所以推送失败。解决办法 Git 已经提示我们,先用 <code>git pull</code> 把最新的提交从 <code>origin/dev</code> 抓下来,然后在本地合并,解决冲突,再推送。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git pull
</span></span><span class="line"><span class="cl">There is no tracking information <span class="k">for</span> the current branch.
</span></span><span class="line"><span class="cl">Please specify which branch you want to merge with.
</span></span><span class="line"><span class="cl">See git-pull<span class="o">(</span>1<span class="o">)</span> <span class="k">for</span> details.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> git pull <remote> <branch>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">If you wish to <span class="nb">set</span> tracking information <span class="k">for</span> this branch you can <span class="k">do</span> so with:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> git branch --set-upstream-to<span class="o">=</span>origin/<branch> dev
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>git pull </code>也失败了,原因是没有指定本地 <code>dev</code> 分支与远程 <code>origin/dev</code> 分支的链接,根据提示设置 <code>dev</code> 和 <code>origin/dev</code> 的链接,再 pull</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git branch --set-upstream-to<span class="o">=</span>origin/dev dev
</span></span><span class="line"><span class="cl">Branch <span class="s1">'dev'</span> <span class="nb">set</span> up to track remote branch <span class="s1">'dev'</span> from <span class="s1">'origin'</span>.
</span></span><span class="line"><span class="cl">$ git pull
</span></span><span class="line"><span class="cl">Auto-merging README.md
</span></span><span class="line"><span class="cl">CONFLICT <span class="o">(</span>add/add<span class="o">)</span>: Merge conflict in README.md
</span></span><span class="line"><span class="cl">Automatic merge failed<span class="p">;</span> fix conflicts and <span class="k">then</span> commit the result.
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>git pull </code> 成功,但是合并有冲突,需要手动解决,见前文「解决分支合并冲突」,再 <code>git push origin dev</code> 。</p>
<h4 id="rebase">Rebase</h4>
<p>多人在同一个分支上协作时,很容易出现冲突。即使没有冲突,后 push 的小伙伴也不得不先 pull,在本地合并,然后才能 push 成功。</p>
<p>每次合并再 push 后,分支变成了这样</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git log --graph --pretty<span class="o">=</span>oneline --abbrev-commit
</span></span><span class="line"><span class="cl">* d1be385 <span class="o">(</span>HEAD -> master, origin/master<span class="o">)</span> init hello
</span></span><span class="line"><span class="cl">* e5e69f1 Merge branch <span class="s1">'dev'</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> * 57c53ab <span class="o">(</span>origin/dev, dev<span class="o">)</span> fix env conflict
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="p">|</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> <span class="p">|</span> * 7a5e5dd add env
</span></span><span class="line"><span class="cl"><span class="p">|</span> * <span class="p">|</span> 7bd91f1 add new env
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="p">|</span>/
</span></span><span class="line"><span class="cl">* <span class="p">|</span> 12a631b merged bug fix <span class="m">101</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span><span class="se">\ \
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> * <span class="p">|</span> 4c805e2 fix bug <span class="m">101</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>/ /
</span></span><span class="line"><span class="cl">* <span class="p">|</span> e1e9c68 merge with no-ff
</span></span><span class="line"><span class="cl"><span class="p">|</span><span class="se">\ \
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> <span class="p">|</span>/
</span></span><span class="line"><span class="cl"><span class="p">|</span> * f52c633 add merge
</span></span><span class="line"><span class="cl"><span class="p">|</span>/
</span></span><span class="line"><span class="cl">* cf810e4 conflict fixed
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>Git 有一种称为 rebase(变基) 的操作,能把分叉的提交变成直线,使查看历史提交的变化更容易。</p>
<p>在和远程分支同步后,对 <code>hello.py</code> 做了两次提交。用 <code>git log</code> 命令查看</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git log --graph --pretty<span class="o">=</span>oneline --abbrev-commit
</span></span><span class="line"><span class="cl">* 582d922 <span class="o">(</span>HEAD -> master<span class="o">)</span> add author
</span></span><span class="line"><span class="cl">* <span class="m">8875536</span> add comment
</span></span><span class="line"><span class="cl">* d1be385 <span class="o">(</span>origin/master<span class="o">)</span> init hello
</span></span><span class="line"><span class="cl">* e5e69f1 Merge branch <span class="s1">'dev'</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> * 57c53ab <span class="o">(</span>origin/dev, dev<span class="o">)</span> fix env conflict
</span></span><span class="line"><span class="cl"><span class="p">|</span> <span class="p">|</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> <span class="p">|</span> * 7a5e5dd add env
</span></span><span class="line"><span class="cl"><span class="p">|</span> * <span class="p">|</span> 7bd91f1 add new env
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>注意到 Git 用 <code>(HEAD -> master)</code> 和 <code>(origin/master)</code> 标识出当前分支的 HEAD 和远程 origin 的位置分别是 <code>582d922 add author</code> 和 <code>d1be385 init hello</code> ,本地分支比远程分支快两个提交。</p>
<p>现在尝试推送本地分支</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git push origin master
</span></span><span class="line"><span class="cl">To github.com:<github username>/<repository>.git
</span></span><span class="line"><span class="cl"> ! <span class="o">[</span>rejected<span class="o">]</span> master -> master <span class="o">(</span>fetch first<span class="o">)</span>
</span></span><span class="line"><span class="cl">error: failed to push some refs to <span class="s1">'git@github.com:<github username>/<repository>.git'</span>
</span></span><span class="line"><span class="cl">hint: Updates were rejected because the remote contains work that you <span class="k">do</span>
</span></span><span class="line"><span class="cl">hint: not have locally. This is usually caused by another repository pushing
</span></span><span class="line"><span class="cl">hint: to the same ref. You may want to first integrate the remote changes
</span></span><span class="line"><span class="cl">hint: <span class="o">(</span>e.g., <span class="s1">'git pull ...'</span><span class="o">)</span> before pushing again.
</span></span><span class="line"><span class="cl">hint: See the <span class="s1">'Note about fast-forwards'</span> in <span class="s1">'git push --help'</span> <span class="k">for</span> details.
</span></span></code></pre></td></tr></table>
</div>
</div><p>说明有小伙伴抢先推送了远程分支,按照提示先 pull</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git pull
</span></span><span class="line"><span class="cl">remote: Counting objects: 3, <span class="k">done</span>.
</span></span><span class="line"><span class="cl">remote: Compressing objects: 100% <span class="o">(</span>1/1<span class="o">)</span>, <span class="k">done</span>.
</span></span><span class="line"><span class="cl">remote: Total <span class="m">3</span> <span class="o">(</span>delta 1<span class="o">)</span>, reused <span class="m">3</span> <span class="o">(</span>delta 1<span class="o">)</span>, pack-reused <span class="m">0</span>
</span></span><span class="line"><span class="cl">Unpacking objects: 100% <span class="o">(</span>3/3<span class="o">)</span>, <span class="k">done</span>.
</span></span><span class="line"><span class="cl">From github.com:<github username>/<repository>
</span></span><span class="line"><span class="cl"> d1be385..f005ed4 master -> origin/master
</span></span><span class="line"><span class="cl"> * <span class="o">[</span>new tag<span class="o">]</span> v1.0 -> v1.0
</span></span><span class="line"><span class="cl">Auto-merging hello.py
</span></span><span class="line"><span class="cl">Merge made by the <span class="s1">'recursive'</span> strategy.
</span></span><span class="line"><span class="cl"> hello.py <span class="p">|</span> <span class="m">1</span> +
</span></span><span class="line"><span class="cl"> <span class="m">1</span> file changed, <span class="m">1</span> insertion<span class="o">(</span>+<span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>再用 <code>git status</code> 查看状态</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git status
</span></span><span class="line"><span class="cl">On branch master
</span></span><span class="line"><span class="cl">Your branch is ahead of <span class="s1">'origin/master'</span> by <span class="m">3</span> commits.
</span></span><span class="line"><span class="cl"> <span class="o">(</span>use <span class="s2">"git push"</span> to publish your <span class="nb">local</span> commits<span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">nothing to commit, working tree clean
</span></span></code></pre></td></tr></table>
</div>
</div><p>加上刚才合并的提交,现在本地分支比远程分支超前 3 个提交,用 <code>git log</code> 查看</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git log --graph --pretty<span class="o">=</span>oneline --abbrev-commit
</span></span><span class="line"><span class="cl">* e0ea545 <span class="o">(</span>HEAD -> master<span class="o">)</span> Merge branch <span class="s1">'master'</span> of github.com:<github username>/<repository>
</span></span><span class="line"><span class="cl"><span class="p">|</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> * f005ed4 <span class="o">(</span>origin/master<span class="o">)</span> <span class="nb">set</span> <span class="nv">exit</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">* <span class="p">|</span> 582d922 add author
</span></span><span class="line"><span class="cl">* <span class="p">|</span> <span class="m">8875536</span> add comment
</span></span><span class="line"><span class="cl"><span class="p">|</span>/
</span></span><span class="line"><span class="cl">* d1be385 init hello
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><p>不好看!此时,rebase 派上了用场,把本地前几次推送的版本,从前往后与小伙伴已经推送的版本合并</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git rebase
</span></span><span class="line"><span class="cl">First, rewinding head to replay your work on top of it...
</span></span><span class="line"><span class="cl">Applying: add comment
</span></span><span class="line"><span class="cl">Using index info to reconstruct a base tree...
</span></span><span class="line"><span class="cl">M hello.py
</span></span><span class="line"><span class="cl">Falling back to patching base and 3-way merge...
</span></span><span class="line"><span class="cl">Auto-merging hello.py
</span></span><span class="line"><span class="cl">Applying: add author
</span></span><span class="line"><span class="cl">Using index info to reconstruct a base tree...
</span></span><span class="line"><span class="cl">M hello.py
</span></span><span class="line"><span class="cl">Falling back to patching base and 3-way merge...
</span></span><span class="line"><span class="cl">Auto-merging hello.py
</span></span></code></pre></td></tr></table>
</div>
</div><p>再用 <code>git log</code> 看看</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ git log --graph --pretty<span class="o">=</span>oneline --abbrev-commit