- 原文地址:How (and why!) to keep your Git commit history clean
- 原文做者:Kushal Pandya
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:DM.Zhong
- 校對者:Leo Lyu,YiLin Wang
提交功能是 Git 倉庫的關鍵部分之一,不只如此,提交信息也是倉庫的生命日誌。項目或者倉庫在隨着時間的推移不斷演變(新功能不斷加入,Bug 被不斷修復,體系架構也被重構),提交信息成爲了人們查看倉庫所發生的變化或者怎麼發生變化的地方。所以使用簡短精確的提交信息反映出內部的變化是很是重要的。css
Git 提交信息是你在你所寫的代碼上所留下的指紋。無論你今天提交了什麼代碼,一年以後你再看到這個變化;你會很是感謝你所寫的有意義的、乾淨整潔的提交信息,這也會使得你的同事工做更輕鬆。當根據上下文分開提交時,能夠更快地找到 Bug 是在哪一次提交中被引入的,將首先引發 Bug 的此次提交進行回退能夠很是簡便的修復 Bug。html
當開發大型項目時,咱們常常處理一大堆部件變更,包括更新、添加和移除。在這種場景中確保好好維護提交信息是很艱難的,尤爲是當開發週期是數天、數週、甚至數月時。所以爲了簡化維護提交記錄的工做,這篇文章會使用許多開發人員在 Git 倉庫上工做時可能會常常遇到的常見場景。前端
可是在咱們深刻了解以前,讓咱們快速瀏覽一下咱們假設的 Ruby 應用程序中典型的開發工做流程。android
注意: 這篇文章默認你已經掌握 Git 基礎,分支如何工做,如何將分支的未提交更改添加到暫存區以及如何提交更改。若是你不太熟悉這些流程,咱們的文檔是一個好的起點。ios
如今,咱們正在開發一個小型的 Ruby on Rails 項目,在這個項目中咱們須要在首頁添加一個導航視圖,這須要更新和添加許多文件。下面是整個流程分解的每一個步驟:git
application_controller.rb
index.html.haml
_navigation.html.haml
styles.css.scss
application_controller_spec.rb
navigation_spec.rb
由於全部的這些文件屬於不一樣的架構領域,咱們彼此隔離地提交這些文件的更改,以確保每次提交表明了特定的上下文,而且按照特定順序進行提交。我一般偏向於後端 -> 前端的提交順序:首先提交之後端爲中心的更改,其次提交中間層文件的更改,最後提交之前端爲中心的更改。github
application_controller.rb
& application_controller_spec.rb
;添加導航路由。_navigation.html.haml
& navigation_spec.rb
;頁面導航視圖。index.html.haml
;渲染導航部分。styles.css.scss
;爲導航添加樣式。在提交更改以後,咱們會爲分支建立一個合併請求。一旦建立了合併請求,在被合併到倉庫的 master
分支以前,一般會由你的同事對代碼進行審查。如今咱們瞭解一下代碼審查過程當中可能會遇到的不一樣狀況。shell
想象一下代碼審查者在審查 styles.css.scss
時提出了一個修改建議。這種狀況,修改起來很是簡單,由於樣式表修改是你分支上的最後一次提交。下面是咱們應該怎樣處理這種狀況:後端
styles.css.scss
作必要的修改。git add styles.css.scss
。git commit --amend
。
git commit
命令修改最近一次提交,把暫存中的任何修改合併到最近一次提交。因爲你修改了一個已經存在的提交,你須要使用 git push --force-with-lease <remote_name> <branch_name>
命令將這些修改強制推送到你的遠程倉庫。這個命令會使用咱們本地倉庫中所作的修改來覆蓋遠程倉庫中爲導航添加樣式
這個提交。bash
當你強制推送分支時,有一點須要注意,那就是當你所在分支是一個多人協做的分支時,你的強制推送可能會給其餘人的正常推送形成麻煩,由於遠程分支上有一些強制推送的新的提交。所以,你應該合理地使用這個功能。你能夠在這裏學習到更多有關 Git 強制推送選項的信息。
在上一個場景中,由於咱們只須要修改最近的一次提交,因此作起來很是簡單,可是想象一下若是代碼審查者建議修改 _navigation.html.haml
文件中的某些部分。在這種場景下,它是第二次提交,因此修改起來不像第一個場景中那麼直接。讓咱們看看怎麼處理這種狀況:
每次在分支上提交更改,都會有一個獨一無二的 SHA1 哈希字符串做爲更改提交的標誌。能夠把它看作區分每次提交的獨特 ID。能夠經過運行 git log
命令查看某個分支上的全部提交以及它們分別的 SHA1 哈希值。運行命令以後,能夠看到相似下面的輸出,其中最近一次的提交在頂部。
commit aa0a35a867ed2094da60042062e8f3d6000e3952 (HEAD -> add-page-navigation)
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 15:24:02 2018 +0530
爲導航添加樣式
commit c22a3fa0c5cdc175f2b8232b9704079d27c619d0
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:42:52 2018 +0000
渲染導航部分
commit 4155df1cdc7be01c98b0773497ff65c22ba1549f
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:42:51 2018 +0000
頁面導航視圖
commit 8d74af102941aa0b51e1a35b8ad731284e4b5a20
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:12:20 2018 +0000
添加導航路由
複製代碼
如今輪到 git rebase
命令表演了。無論何時咱們想要用 git rebase
命令修改一個特定的更改提交,咱們首先要將咱們分支的 HEAD 變基到咱們想要修改的更改提交以前。在這個場景中,咱們須要修改頁面導航視圖
的更改提交。
如今,注意咱們想要修改的更改提交以前的一個更改提交的哈希值;複製這個哈希值而後按照一下步驟進行操做:
git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20
來將分支變基到咱們要修改的更改提交的前一個更改提交
rebase
命令的交互模式,經過提交 SHA1 哈希值咱們能夠將分支進變基。pick 4155df1cdc7 頁面導航視圖 pick c22a3fa0c5c 渲染導航部分 pick aa0a35a867e 爲導航添加樣式 # Rebase 8d74af10294..aa0a35a867e onto 8d74af10294 (3 commands) # # 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 # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out 複製代碼
注意到每一個更改提交以前都有一個單詞 pick
,而且在它下面的內容裏面,有全部的咱們可使用的關鍵字。由於咱們想要編輯一個更改提交,因此咱們將命令 pick 4155df1cdc7 頁面導航視圖
修改成 edit 4155df1cdc7 頁面導航視圖
。保存更改並退出編輯器。
如今你的分支已經被變基到包含 _navigation.html.haml
的更改提交以前了。打開文件並完成每一個審查反饋中的修改需求。一旦你完成了修改,使用命令 git add _navigation.html.haml
將它們暫存起來。
由於咱們已經暫存了這些更改,因此如今應該把分支 HEAD 從新移動到咱們原來的更改提交(同時包含咱們全部的新的更改的提交),運行 git rebase --continue
,這將會在終端中打開你的默認編輯器而且向你展現變基期間咱們所作的更改的提交信息;頁面導航視圖
。若是須要你能夠修改這個提交信息,但如今咱們保留它,所以接下來保存修改而後退出編輯器。這個時候,Git 會從新展現你剛剛修改的更改提交以後的全部更改提交而且分支的 HEAD
已經回到了咱們原來的全部更改提交的頂部,它包含全部你對其中某個更改提交所作的全部新的更改。
由於咱們又一次修改了遠程倉庫中的一個提交,咱們須要再次使用 git push --force-with-lease <remote_name> <branch_name>
命令將分支強制提交。
一個常見的場景就是當咱們剛剛修改了一些以前的提交併從新提交了一些新的更改。如今讓咱們儘量的精簡一下這些提交,用原來的提交合並它們。
你所要作的就是像其它場景中所作的那樣開始交互性的變基操做。
pick 4155df1cdc7 頁面導航視圖
pick c22a3fa0c5c 渲染導航部分
pick aa0a35a867e 爲導航添加樣式
pick 62e858a322 Fix a typo
pick 5c25eb48c8 Ops another fix
pick 7f0718efe9 Fix 2
pick f0ffc19ef7 Argh Another fix!
複製代碼
如今假設你想要合併全部的那些提交到 c22a3fa0c5c 渲染導航部分
。你只須要作:
pick
改成 squash
或者 fixup
。注意: squash
模式會在描述中保留修改時的信息。而fixup
不會,它只會保留原來的提交信息。
你會如下面這種結果結束實驗:
pick 4155df1cdc7 頁面導航視圖
pick c22a3fa0c5c 渲染導航部分
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e 爲導航添加樣式
複製代碼
保存更改並退出編輯器,你就完成了!這就是完成以後的歷史提交記錄:
pick 4155df1cdc7 頁面導航視圖
pick 96373c0bcf 渲染導航部分
pick aa0a35a867e 爲導航添加樣式
複製代碼
像以前同樣,你如今所要作的全部工做只是運行 git push --force-with-lease <remote_name> <branch_name>
命令,而後全部的修改都被強制推送了。
若是你想要徹底地移除一個更改提交,而不是 squash
或者 fixup
,你只須要輸入 drop
或者簡單地刪除這一行。
爲避免發生衝突,請確保您在時間線上上移的提交不會觸及其後的提交所觸及的相同文件。
pick 4155df1cdc7 頁面導航視圖 pick c22a3fa0c5c 渲染導航部分 fixup 62e858a322 Fix a typo # this changes styles.css fixup 5c25eb48c8 Ops another fix # this changes image/logo.svg fixup 7f0718efe9 Fix 2 # this changes styles.css fixup f0ffc19ef7 Argh Another fix! # this changes styles.css pick aa0a35a867e 爲導航添加樣式 # this changes index.html (no conflict) 複製代碼
fixup
若是你很清楚你想要修改哪個更改提交,在提交更改時沒必要浪費腦力思考一些 "Fix 1", "Fix 2", …, "Fix 42" 這樣的名字。
步驟 1:初識 --fixup
在你暫存那些更改以後,使用如下命令提交更改:
git commit --fixup c22a3fa0c5c
複製代碼
(注意到這個哈希值是屬於 c22a3fa0c5c 渲染導航部分
這個更改提交的)
這會產生這樣的提交信息:fixup! 渲染導航部分
。
步驟 2:還有這個小夥伴 --autosquash
經過簡單的使用交互變基操做。你可讓 git
自動的把全部 fixup
放到正確的位置。
git rebase -i 4155df1cdc7 --autosquash
歷史提交記錄會變成下面這樣:
pick 4155df1cdc7 頁面導航視圖
pick c22a3fa0c5c 渲染導航部分
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e 爲導航添加樣式
複製代碼
一切就緒,你只須要審查並繼續。
若是你以爲本身喜歡冒險,你能夠作一個非交互式的變基 git rebase --autosquash
,但前提是你喜歡過這種有風險的生活,由於你沒有機會在這些合併應用前檢查它們。
若是你在開發一個大型的功能,那一般會有許多修復和代碼審查反饋的修改頻繁的被提交。咱們能夠將提交的清理工做留到開發結束,而不是不斷從新設計分支。
這是建立補丁文件很是方便的地方。實際上,在開發人員可使用以 Git 爲基礎的服務好比 GitLab 以前,補丁文件一直是開發大型開源項目經過郵件分享代碼與合併代碼的主要方式。假設你有一個提交量很是巨大的分支(例如;add-page-navigation
),它對於倉庫的變動歷史表述得不是很清晰。如下是如何爲您在此分支中所作的全部更改建立補丁文件:
master
分支的全部更改而且與這些更改沒有衝突。add-page-navigation
分支中籤出時運行 git rebase master
或 git merge master
,以將全部從 master
進行的更改轉移到您的分支上。git diff master add-page-navigation > ~/add_page_navigation.patch
。
master
分支和 add-page-navigation
分支之間的差別,而後重定向輸出(經過 >
符號)到一個文件,在咱們的用戶主目錄(在 *nix
系操做系統中一般是 ~/
)中命名爲 add_page_navigation.patch
。master
分支;運行 git checkout master
。add-page-navigation
;運行 git branch -D add-page-navigation
。請記住,咱們已經在建立的補丁文件中更改了此分支。master
被簽出);運行 git checkout -b add-page-navigation
。git apply ~/add_page_navigation.patch
。跟以前的場景同樣,咱們修改了整個分支,如今是時候強制推送了!
雖然咱們已經介紹了使用 Git 進行平常工做流程中出現的大多數常見和基本狀況,但重寫 Git 提交歷史是一個巨大的話題,若是你已經熟悉上述建議,您能夠在 Git 官方文檔。快樂的 git'ing!
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。