[譯] 怎樣(以及爲何要)保持你的 Git 提交記錄的整潔

怎樣(以及爲何要)保持你的 Git 提交記錄的整潔

Git 提交記錄很容易變得混亂不堪,如今教你怎麼保持整潔!

提交功能是 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

  1. application_controller.rb & application_controller_spec.rb添加導航路由
  2. _navigation.html.haml & navigation_spec.rb頁面導航視圖
  3. index.html.haml渲染導航部分
  4. styles.css.scss爲導航添加樣式

在提交更改以後,咱們會爲分支建立一個合併請求。一旦建立了合併請求,在被合併到倉庫的 master 分支以前,一般會由你的同事對代碼進行審查。如今咱們瞭解一下代碼審查過程當中可能會遇到的不一樣狀況。shell

場景 1:我須要修改最近一次的提交

想象一下代碼審查者在審查 styles.css.scss 時提出了一個修改建議。這種狀況,修改起來很是簡單,由於樣式表修改是你分支上的最後一次提交。下面是咱們應該怎樣處理這種狀況:後端

  • 你直接在你的分支上對 styles.css.scss 作必要的修改。
  • 一旦你完成了修改,將這些修改添加到暫存區進行暫存;運行命令 git add styles.css.scss
  • 一旦修改被添加到暫存區,咱們須要將這些修改添加到咱們的最後一次提交;運行命令: git commit --amend
    • 命令分解:這裏,咱們使用 git commit 命令修改最近一次提交,把暫存中的任何修改合併到最近一次提交。
  • 這會在你的 Git 定義的文本編輯器中打開你最後一次的提交,它具備提交信息爲導航添加樣式
  • 由於咱們只更新了 CSS 聲明,因此咱們不須要修改提交信息。你能夠只作保存而後退出 Git 爲你打開的文本編輯器,你的更改會被反映到提交上。

因爲你修改了一個已經存在的提交,你須要使用 git push --force-with-lease <remote_name> <branch_name> 命令將這些修改強制推送到你的遠程倉庫。這個命令會使用咱們本地倉庫中所作的修改來覆蓋遠程倉庫中爲導航添加樣式這個提交。bash

當你強制推送分支時,有一點須要注意,那就是當你所在分支是一個多人協做的分支時,你的強制推送可能會給其餘人的正常推送形成麻煩,由於遠程分支上有一些強制推送的新的提交。所以,你應該合理地使用這個功能。你能夠在這裏學習到更多有關 Git 強制推送選項的信息。

場景 2:我須要修改一次特定的提交

在上一個場景中,由於咱們只須要修改最近的一次提交,因此作起來很是簡單,可是想象一下若是代碼審查者建議修改 _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 來將分支變基到咱們要修改的更改提交的前一個更改提交
    • 命令分解:如今咱們正在使用 Git 的 rebase 命令的交互模式,經過提交 SHA1 哈希值咱們能夠將分支進變基。
  • 這條命令會運行 Git 變基命令的交互模式,而且會打開文本編輯器展現你所變基到的更改提交以後的全部更改提交。它看起來是這樣的:
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> 命令將分支強制提交。

場景 3:我須要添加、移除或者合併提交

一個常見的場景就是當咱們剛剛修改了一些以前的提交併從新提交了一些新的更改。如今讓咱們儘量的精簡一下這些提交,用原來的提交合並它們。

你所要作的就是像其它場景中所作的那樣開始交互性的變基操做。

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 渲染導航部分。你只須要作:

  1. 把你想要合併的那些更改提交往上移動,以使得它們位於最終合併的更改提交之下。
  2. 將每個更改提交的模式由 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,但前提是你喜歡過這種有風險的生活,由於你沒有機會在這些合併應用前檢查它們。

場景 4:個人提交記錄沒啥有用的內容,我須要從新開始!

若是你在開發一個大型的功能,那一般會有許多修復和代碼審查反饋的修改頻繁的被提交。咱們能夠將提交的清理工做留到開發結束,而不是不斷從新設計分支。

這是建立補丁文件很是方便的地方。實際上,在開發人員可使用以 Git 爲基礎的服務好比 GitLab 以前,補丁文件一直是開發大型開源項目經過郵件分享代碼與合併代碼的主要方式。假設你有一個提交量很是巨大的分支(例如;add-page-navigation),它對於倉庫的變動歷史表述得不是很清晰。如下是如何爲您在此分支中所作的全部更改建立補丁文件:

  • 建立補丁文件的第一步是確保您的分支具備來自 master 分支的全部更改而且與這些更改沒有衝突。
  • 您能夠在 add-page-navigation 分支中籤出時運行 git rebase mastergit merge master,以將全部從 master 進行的更改轉移到您的分支上。
  • 如今建立補丁文件;運行 git diff master add-page-navigation > ~/add_page_navigation.patch
    • 命令分解:在這裏咱們使用了 Git 的 diff 特性,查詢 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 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索