一些git實(shí)用技巧

原創(chuàng) @shhp 轉(zhuǎn)載請(qǐng)注明作者和出處

這篇文章將通過場(chǎng)景分析的方式講解一些git的實(shí)用技巧。這些技巧的使用頻率或許不是很高捆蜀,但真正需要用到的時(shí)候研底,你可能會(huì)感慨相見恨晚畜吊。

場(chǎng)景一踱阿、罪魁禍?zhǔn)?/h3>

程序員小A發(fā)現(xiàn)源文件B.java中的某一行引發(fā)了一個(gè)bug」芮現(xiàn)在小A要找出是誰在什么時(shí)間提交了這次修改。那么小A應(yīng)該怎么做呢软舌?

最直接的想法應(yīng)該是察看B.java這個(gè)文件的提交歷史才漆,在一個(gè)個(gè)commit中找出導(dǎo)致bug的修改。高級(jí)一點(diǎn)的話可以使用git bisect進(jìn)行二分查找葫隙。其實(shí)git提供了一個(gè)簡(jiǎn)單直接的命令git blame可以幫助我們快速地找到那個(gè)“罪魁禍?zhǔn)住薄?code>git blame命令會(huì)輸出指定文件中每一行的最后一次修改的作者栽烂、時(shí)間以及commit hash. 例如執(zhí)行git blame B.java的輸出如下:

^87fe8e2 (little A 2016-06-18 14:21:23 +0800 1) public class B {
^87fe8e2 (little A 2016-06-18 14:21:23 +0800 2) 
^87fe8e2 (little A 2016-06-18 14:21:23 +0800 3)         public static void main(String[] args) {
51497e8a (someone  2016-06-18 14:22:21 +0800 4)       System.out.println("It is me! Haha!");
^87fe8e2 (little A 2016-06-18 14:21:23 +0800 5)   }
^87fe8e2 (little A 2016-06-18 14:21:23 +0800 6) }

可以看到someone就是那個(gè)“罪魁禍?zhǔn)住保躏仇。ê冒闪到牛鋵?shí)我們還是不知道他是誰)

場(chǎng)景二腺办、亡羊補(bǔ)牢1.0

小A剛剛提交了一個(gè)commit,但發(fā)現(xiàn)提交信息寫錯(cuò)了糟描。小A該如何修改這次的提交信息呢怀喉?

補(bǔ)救的方法有不少,這里列舉兩個(gè):

  1. 執(zhí)行命令git commit --amend, 在vim編輯界面修改提交信息后保存即可船响。這算是最簡(jiǎn)單的方法了躬拢。

  2. 依次執(zhí)行

     git reset HEAD~1
     git commit -am "new message"
    

    這個(gè)方法首先將當(dāng)前的working tree還原到最后一次commit之前的狀態(tài),然后再進(jìn)行一次新的commit.

場(chǎng)景三见间、亡羊補(bǔ)牢2.0

現(xiàn)在難度升級(jí)聊闯,如果小A想修改中間某個(gè)commit的提交信息,該怎么辦呢米诉?

這時(shí)可以使用強(qiáng)大的git rebase -i命令菱蔬。輸入git rebase -i加一個(gè)commit hash之后回車,進(jìn)入一個(gè)vim編輯界面史侣。界面上按序列出了指定commit之后的所有commit拴泌,類似下面這樣:

pick 383fd55 llal pick 1ddcdab update new.txt
pick 1519f1f update new.txt 2
pick fdc6370 delete new.txt
pick 0a8bcf8 add back new.txt
# Rebase 2aa6567..0a8bcf8 onto 2aa6567 (5 command(s))
# # Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

在每一行的開頭可以指定一個(gè)你想執(zhí)行的命令。默認(rèn)是pick, 也就是不做任何修改【鳎現(xiàn)在我們想修改中間的某個(gè)commit信息蚪腐,只需把該commit所在行的pick替換成reword或者簡(jiǎn)寫r,然后保存税朴。接下來會(huì)出現(xiàn)新的編輯界面回季,然后我們就可以修改提交信息了。

可以看到除了reword還有其他一些命令掉房,后面會(huì)用到其中的某幾個(gè)茧跋。

場(chǎng)景四、追悔莫及

小A發(fā)現(xiàn)當(dāng)前分支test上的最后N個(gè)commit有問題卓囚,想丟棄它們瘾杭,于是執(zhí)行了git reset --hard HEAD~N. 過了一段時(shí)間,小A突然想起之前丟棄的N個(gè)commit里面還有一些重要的修改哪亿!那么小A有什么辦法找回丟棄的那N個(gè)commit呢粥烁?

這時(shí)可以求助于git提供的ORIG_HEAD這個(gè)變量。在進(jìn)行pull蝇棉、merge或者reset等操作后讨阻,HEAD一般都會(huì)移動(dòng)好幾個(gè)commit。而ORIG_HEAD就是指向這些操作之前HEAD所指向的那個(gè)commit篡殷《鬯保可以認(rèn)為ORIG_HEAD是git提供的一劑后悔藥。小A要找回之前丟棄的N個(gè)commit,可以這么做:

git checkout -b temp ORIG_HEAD
git checkout test
git merge temp

首先創(chuàng)建一個(gè)分支temp指向ORIG_HEAD指向的commit奇瘦。然后切回test分支棘催,merge一下temp,就可以讓那N個(gè)commit重新回到test分支耳标。

但是醇坝,如果小A在丟棄了那幾個(gè)commit之后又做了pullmerge或者reset等操作次坡,改變了ORIG_HEAD的值呼猪,那么上面這個(gè)方法就無效了。不過辦法總比困難多砸琅,這時(shí)使用git reflog可以解決這個(gè)問題宋距。git會(huì)記錄HEAD的改變歷史,而git reflog就是把這個(gè)歷史記錄輸出症脂。這個(gè)命令的輸出如下:

87fe8e2 HEAD@{0}: reset: moving to HEAD~1
d42533e HEAD@{1}: checkout: moving from master to test
d42533e HEAD@{2}: commit: another

小A只需找到執(zhí)行reset命令的那一行乡革,那么它下面一行最前面的commit hash就是“解藥”了。找到了這個(gè)commit摊腋,之后再仿照上面的步驟操作就可以了沸版。

場(chǎng)景五、挑三揀四1.0

小A對(duì)一個(gè)文件B做了多處修改兴蒸。在提交的時(shí)候發(fā)現(xiàn)有一些修改是需要排除在這次提交之外的视粮。
那么怎么做可以對(duì)同一個(gè)文件的多處修改進(jìn)行選擇性提交?

這時(shí)可以使用git add -p命令。輸入此命令(后面可以指定文件名)后橙凳,git會(huì)對(duì)每一個(gè)修改區(qū)塊(一般來講一段連續(xù)的修改算是一個(gè)區(qū)塊)詢問需要執(zhí)行的指令:

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?

其中各指令的含義如下:

y - 將此區(qū)塊加入index
n - 不加入index蕾殴,并跳到下一個(gè)區(qū)塊
q - 不加入index,同時(shí)結(jié)束操作
a - 將此區(qū)塊以及當(dāng)前文件剩余區(qū)塊都加入index岛啸,跳到下一個(gè)文件
d - 與a相反
g - 選擇具體的區(qū)塊進(jìn)行操作
/ - 搜索能夠匹配給定正則表達(dá)式的區(qū)塊
j - 將此區(qū)塊標(biāo)記成“暫定”钓觉,跳到下一個(gè)“暫定”的區(qū)塊
J - 將此區(qū)塊標(biāo)記成“暫定”,跳到下一個(gè)區(qū)塊
k - 將此區(qū)塊標(biāo)記成“暫定”坚踩,跳到前一個(gè)“暫定”的區(qū)塊
K - 將此區(qū)塊標(biāo)記成“暫定”荡灾,跳到前一個(gè)區(qū)塊
s - 將當(dāng)前區(qū)塊劃分成更小的區(qū)塊
e - 進(jìn)入編輯界面進(jìn)行更細(xì)的選擇
? - 打印幫助

如果選擇執(zhí)行指令e則會(huì)進(jìn)入一個(gè)新的vim編輯頁(yè)面,如下所示:

# Manual hunk edit mode -- see bottom for a quick guide
@@ -1,3 +1,3 @@
 origin
-1
-2
+abc
+xyz
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

在這個(gè)界面可以進(jìn)行更細(xì)致的操作:將某一行開頭的-號(hào)換成空格瞬铸,該行的刪除修改則不會(huì)加入index批幌,但這個(gè)刪除的修改仍然保留;將以號(hào)開頭的某一行刪除嗓节,該行則不會(huì)加入index荧缘,但添加的這一行仍然保留在文件中。

場(chǎng)景六拦宣、挑三揀四2.0

如果上面那個(gè)B文件是一個(gè)Untracked file截粗,那又該如何進(jìn)行選擇性提交呢信姓?

可以先執(zhí)行git add -N B命令。現(xiàn)在B里面的內(nèi)容都變成了unstaged的修改绸罗。之后再用上面的方法進(jìn)行選擇性提交财破。

場(chǎng)景七、萬源歸一

小A開發(fā)出了一款可以自動(dòng)編程并且提交代碼的AI工具从诲。不過有一天小A發(fā)現(xiàn)該工具的一個(gè)bug引發(fā)了一個(gè)問題:
它每修改一處就會(huì)進(jìn)行一次commit,這樣導(dǎo)致一次功能修改就提交了N多個(gè)commit靡羡。有什么辦法可以合并這些commit變成一個(gè)commit系洛?

可以再一次使用git rebase -i. 回顧場(chǎng)景三可以看到vim編輯界面的提示中有兩條指令:

# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message

這兩條指令都可以把當(dāng)前的commit歸并到前一個(gè)commit中,區(qū)別就在于是否保留當(dāng)前commit的提交信息略步。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末描扯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子趟薄,更是在濱河造成了極大的恐慌绽诚,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杭煎,死亡現(xiàn)場(chǎng)離奇詭異恩够,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)羡铲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門蜂桶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人也切,你說我怎么就攤上這事扑媚。” “怎么了雷恃?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵疆股,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我倒槐,道長(zhǎng)旬痹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任讨越,我火速辦了婚禮唱凯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谎痢。我一直安慰自己磕昼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布节猿。 她就那樣靜靜地躺著票从,像睡著了一般漫雕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上峰鄙,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天浸间,我揣著相機(jī)與錄音,去河邊找鬼吟榴。 笑死魁蒜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吩翻。 我是一名探鬼主播兜看,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼狭瞎!你這毒婦竟也來了细移?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤熊锭,失蹤者是張志新(化名)和其女友劉穎弧轧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碗殷,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡精绎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锌妻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捺典。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖从祝,靈堂內(nèi)的尸體忽然破棺而出襟己,到底是詐尸還是另有隱情,我是刑警寧澤牍陌,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布擎浴,位于F島的核電站,受9級(jí)特大地震影響毒涧,放射性物質(zhì)發(fā)生泄漏贮预。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一契讲、第九天 我趴在偏房一處隱蔽的房頂上張望仿吞。 院中可真熱鬧,春花似錦捡偏、人聲如沸唤冈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)你虹。三九已至绘搞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間傅物,已是汗流浹背夯辖。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留董饰,地道東北人蒿褂。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像卒暂,于是被迫代替她去往敵國(guó)和親啄栓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Git 基礎(chǔ) 基本原理 客戶端并不是只提取最新版本的文件快照介却,而是把代碼倉(cāng)庫(kù)完整的鏡像下來。這樣一來块茁,任何一處協(xié)同...
    __silhouette閱讀 15,887評(píng)論 5 147
  • Git 命令行學(xué)習(xí)筆記 Git 基礎(chǔ) 基本原理 客戶端并不是只提取最新版本的文件快照齿坷,而是把代碼倉(cāng)庫(kù)完整的鏡像下來...
    sunnyghx閱讀 3,921評(píng)論 0 11
  • 上班好累!活著好累数焊!胡思亂想好累永淌! 我想等等在放棄
    曾慌張?jiān)孟?/span>閱讀 473評(píng)論 0 0
  • 小美好完結(jié)啦干厚!還在糾結(jié)選江辰還是選林楊李滴?嘖嘖嘖~其實(shí)你離撲倒他們只差了一件事! 最近看了大火的《致我們單純的小美好...
    豬精女孩的少女心閱讀 506評(píng)論 0 0
  • 1 大寶比小寶大六歲蛮瞄。 大寶從小是長(zhǎng)輩們的焦點(diǎn)所坯, 是爺爺奶奶的開心果, 是爸爸的小公主挂捅, 是媽媽的小棉襖芹助。 當(dāng)她五...
    小兔魚娛閱讀 373評(píng)論 0 0