Git
章節 ▾ 第二版

5.3 分散式 Git - 維護專案

維護專案

除了知道如何有效地貢獻專案之外,您可能還需要知道如何維護專案。這可能包括接受並套用透過 format-patch 產生並以電子郵件寄給您的修補程式,或整合您已新增為專案遠端的儲存庫中的遠端分支變更。無論您是維護正規儲存庫,還是想透過驗證或核准修補程式來協助,您都需要知道如何接受工作,以便讓其他貢獻者更清楚,並讓您長期維持下去。

在主題分支中工作

當您考慮整合新工作時,通常最好在主題分支中嘗試 — 一個專門用於嘗試新工作的臨時分支。這樣,您可以輕鬆地單獨調整修補程式,如果它沒有作用,可以將它擱置,直到您有時間再回來處理。如果您根據您要嘗試的工作的主題建立一個簡單的分支名稱,例如 ruby_client 或類似的描述性名稱,如果您必須放棄它一段時間並稍後再回來,您可以輕鬆記住它。Git 專案的維護者也傾向於對這些分支進行命名空間 — 例如 sc/ruby_client,其中 sc 是貢獻該工作的人的縮寫。您會記得,您可以像這樣從您的 master 分支建立分支

$ git branch sc/ruby_client master

或者,如果您想立即切換到它,您可以使用 checkout -b 選項

$ git checkout -b sc/ruby_client master

現在您已準備好將您收到的貢獻工作新增到此主題分支中,並確定是否要將其合併到您的長期分支中。

套用來自電子郵件的修補程式

如果您收到一封需要整合到專案中的修補程式電子郵件,您需要在您的主題分支中套用該修補程式以評估它。有兩種方法可以套用電子郵件修補程式:使用 git apply 或使用 git am

使用 apply 套用 Patch

如果你從某人那裡收到使用 git diff 或 Unix diff 命令(不建議使用;請參閱下一節)產生的 patch,你可以使用 git apply 命令套用它。假設你將 patch 儲存在 /tmp/patch-ruby-client.patch,你可以這樣套用 patch:

$ git apply /tmp/patch-ruby-client.patch

這會修改你工作目錄中的檔案。它幾乎等同於執行 patch -p1 命令來套用 patch,儘管它更加謹慎,並且比 patch 接受較少的模糊匹配。如果檔案新增、刪除和重新命名是以 git diff 格式描述的,它也會處理這些情況,而 patch 不會這樣做。最後,git apply 是一個「全部套用或全部中止」的模型,其中要麼全部套用,要麼全部不套用,而 patch 可以部分套用 patch 檔案,使你的工作目錄處於奇怪的狀態。總體而言,git applypatch 更為保守。它不會為你建立 commit — 執行後,你必須手動暫存並提交引入的變更。

你也可以使用 git apply 來查看 patch 在實際嘗試套用之前是否能順利套用 — 你可以使用 patch 執行 git apply --check

$ git apply --check 0001-see-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply

如果沒有輸出,則表示該 patch 應能順利套用。如果檢查失敗,此命令也會以非零狀態退出,因此你可以在腳本中使用它。

使用 am 套用 Patch

如果貢獻者是 Git 使用者,並且很樂意使用 format-patch 命令來產生他們的 patch,那麼你的工作會更輕鬆,因為 patch 包含作者資訊和給你的 commit 訊息。如果可以,請鼓勵你的貢獻者使用 format-patch 而不是 diff 來為你產生 patch。你應該只需要將 git apply 用於舊有的 patch 和類似的東西。

要套用由 format-patch 產生的 patch,你可以使用 git am (該命令名為 am,因為它用於「從郵件匣套用一系列 patch」)。從技術上講,git am 的構建是為了讀取 mbox 檔案,這是一種簡單的純文字格式,用於在一個文字檔案中儲存一個或多個電子郵件訊息。它看起來像這樣:

From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Add limit to log function

Limit log functionality to the first 20

這是你在上一節中看到的 git format-patch 命令的輸出開頭;它也代表一個有效的 mbox 電子郵件格式。如果有人使用 git send-email 正確地透過電子郵件將 patch 發送給你,並且你將其下載為 mbox 格式,那麼你可以將 git am 指向該 mbox 檔案,它將開始套用它看到的所有 patch。如果你運行可以將多封電子郵件儲存為 mbox 格式的郵件用戶端,則可以將整個 patch 系列儲存到一個檔案中,然後使用 git am 一次套用它們。

但是,如果有人將透過 git format-patch 產生的 patch 檔案上傳到票務系統或類似系統,你可以將該檔案儲存在本地,然後將儲存在磁碟上的該檔案傳遞給 git am 以套用它

$ git am 0001-limit-log-function.patch
Applying: Add limit to log function

你可以看到它順利套用了,並且自動為你建立了新的 commit。作者資訊取自電子郵件的 FromDate 標頭,並且 commit 的訊息取自電子郵件的 Subject 和主體(在 patch 之前)。例如,如果此 patch 是從上面的 mbox 範例套用的,則產生的 commit 將如下所示:

$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:     Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit:     Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700

   Add limit to log function

   Limit log functionality to the first 20

Commit 資訊表示套用 patch 的人和套用時間。Author 資訊是最初建立 patch 的個人和最初建立時間。

但是,patch 可能無法順利套用。也許你的主分支已經與建立 patch 的分支偏離太遠,或者 patch 依賴於你尚未套用的另一個 patch。在這種情況下,git am 流程將會失敗,並詢問你想做什麼

$ git am 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".

此命令會在它有問題的任何檔案中放置衝突標記,很像衝突合併或變基操作。你解決此問題的方式非常相似 — 編輯檔案以解決衝突,暫存新檔案,然後執行 git am --resolved 以繼續下一個 patch

$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: See if this helps the gem

如果你想讓 Git 更聰明地嘗試解決衝突,你可以將 -3 選項傳遞給它,這會使 Git 嘗試三向合併。預設情況下不啟用此選項,因為如果 patch 聲稱基於的 commit 不在你的儲存庫中,則該選項不起作用。如果你確實有該 commit — 如果 patch 是基於你擁有存取權的公開 commit — 那麼 -3 選項通常在套用衝突 patch 時會更加聰明

$ git am -3 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.

在這種情況下,如果沒有 -3 選項,patch 會被視為衝突。由於使用了 -3 選項,因此 patch 已順利套用。

如果要從 mbox 套用多個 patch,你也可以在互動模式下執行 am 命令,該命令會在找到的每個 patch 處停止,並詢問你是否要套用它

$ git am -3 -i mbox
Commit Body is:
--------------------------
See if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

如果你儲存了多個 patch,這很方便,因為你可以先檢視 patch(如果你不記得它是什麼),或者如果你已經套用過 patch,則不套用它。

當你的主題的所有 patch 都已套用並提交到你的分支時,你可以選擇是否以及如何將它們整合到更長的分支中。

檢出遠端分支

如果你的貢獻來自設定了自己的儲存庫、將多個變更推送進去,然後將儲存庫的 URL 和變更所在遠端分支的名稱發送給你的 Git 使用者,你可以將它們新增為遠端並在本地進行合併。

例如,如果 Jessica 發送電子郵件告訴你,她在她的儲存庫的 ruby-client 分支中有一項很棒的新功能,你可以透過新增遠端並在本地檢出該分支來測試它

$ git remote add jessica https://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client

如果她稍後再次透過電子郵件發送給你另一個包含另一項很棒功能的分支,你可以直接 fetchcheckout,因為你已經設定了遠端。

如果你與某人持續合作,這最有用。如果有人只是偶爾貢獻一個 patch,那麼透過電子郵件接受它可能比要求每個人都運行自己的伺服器並必須不斷新增和移除遠端來獲取一些 patch 更省時。你也不太可能想要有數百個遠端,每個遠端都適用於只貢獻一兩個 patch 的人。但是,腳本和託管服務可能會使此操作更容易 — 這很大程度上取決於你的開發方式和貢獻者的開發方式。

這種方法的另一個優點是,你也可以獲得 commit 的歷史記錄。儘管你可能有合理的合併問題,但你知道他們的工作在你的歷史記錄中的位置;正確的三向合併是預設值,而不是必須提供 -3 並希望 patch 是從你可以存取的公開 commit 中產生的。

如果你不是與某人持續合作,但仍然想以這種方式從他們那裡提取,你可以將遠端儲存庫的 URL 提供給 git pull 命令。這會執行一次性提取,並且不會將 URL 儲存為遠端參考

$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
 * branch            HEAD       -> FETCH_HEAD
Merge made by the 'recursive' strategy.

判斷引入的內容

現在你有一個包含貢獻工作的 Topic 分支。在這一點上,你可以確定你想如何處理它。本節會重新檢視一些命令,以便你可以了解如何使用它們來檢視如果你將此分支合併到你的主分支中,你將確切引入什麼內容。

通常,檢閱此分支中但不在你的 master 分支中的所有 commit 會很有幫助。你可以在分支名稱之前新增 --not 選項來排除 master 分支中的 commit。這與我們先前使用的 master..contrib 格式執行相同的操作。例如,如果你的貢獻者向你發送了兩個 patch,並且你建立了一個名為 contrib 的分支並在那裡套用了這些 patch,你可以執行此操作

$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Oct 24 09:53:59 2008 -0700

    See if this helps the gem

commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date:   Mon Oct 22 19:38:36 2008 -0700

    Update gemspec to hopefully work better

要查看每個 commit 引入了哪些變更,請記住,你可以將 -p 選項傳遞給 git log,它會將引入的 diff 附加到每個 commit。

要查看如果要將此 Topic 分支與另一個分支合併會發生的完整 diff,你可能必須使用一個奇怪的技巧才能獲得正確的結果。你可能會想到執行此操作

$ git diff master

此命令會為你提供一個 diff,但它可能會產生誤導。如果你的 master 分支自你從它建立 Topic 分支以來已經前進,那麼你會得到看似奇怪的結果。發生這種情況的原因是 Git 直接比較你所在 Topic 分支的最後一個 commit 的快照,以及 master 分支上最後一個 commit 的快照。例如,如果你在 master 分支上的檔案中新增了一行,則快照的直接比較會看起來像是 Topic 分支將要刪除該行。

如果 master 是你的 Topic 分支的直接祖先,這不是問題;但是,如果這兩個歷史記錄發生了分歧,則 diff 會看起來像是你正在新增你的 Topic 分支中的所有新內容,並刪除 master 分支獨有的所有內容。

你真正想要看到的是新增到 Topic 分支的變更 — 如果你將此分支與 master 合併,你將引入的工作。你可以透過讓 Git 將你的 Topic 分支上的最後一個 commit 與它與 master 分支的第一個共同祖先進行比較來做到這一點。

從技術上講,你可以透過明確找出共同祖先,然後在其上執行 diff 來做到這一點

$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

或者,更簡潔地說

$ git diff $(git merge-base contrib master)

但是,這兩種方法都不是特別方便,因此 Git 提供了另一種用於執行相同操作的簡寫方式:三點語法。在 git diff 命令的上下文中,你可以在另一個分支之後加上三個句點,以執行你所在分支的最後一個 commit 與其與另一個分支的共同祖先之間的 diff

$ git diff master...contrib

此命令僅顯示自目前 Topic 分支與 master 的共同祖先以來,你的目前 Topic 分支所引入的工作。這是一個非常實用的語法,值得記住。

整合貢獻的工作

當你的 Topic 分支中的所有工作都準備好整合到更主流的分支時,問題是如何進行整合。此外,你想使用什麼整體工作流程來維護你的專案?你有多種選擇,因此我們將介紹其中的一些。

合併工作流程

一種基本的工作流程是將所有工作直接合併到你的 master 分支中。在這種情況下,你擁有一個 master 分支,其中包含基本上穩定的程式碼。當你的 Topic 分支中有你認為已完成的工作,或者其他人貢獻並且你已驗證過的工作時,你會將其合併到你的 master 分支中,刪除剛剛合併的 Topic 分支,然後重複此過程。

舉例來說,如果我們有一個儲存庫,其中包含在兩個名為 ruby_clientphp_client 的分支上的工作,其外觀如具有多個主題分支的歷史記錄所示,並且我們依序合併 ruby_clientphp_client,那麼你的歷史記錄最終會看起來像主題分支合併後所示。

History with several topic branches
圖 72. 具有多個主題分支的歷史記錄
After a topic branch merge
圖 73. 主題分支合併後

這可能是最簡單的工作流程,但如果你處理的是較大型或更穩定的專案,而你又希望對引入的內容非常謹慎時,這可能會出現問題。

如果你的專案更重要,你可能會想使用兩階段的合併週期。在這種情況下,你有兩個長時間運行的分支,masterdevelop,你決定只有在建立非常穩定的版本時才更新 master,而所有新程式碼都會整合到 develop 分支中。你會定期將這兩個分支推送到公開儲存庫。每次你有新的主題分支要合併時(在主題分支合併之前),你會將其合併到 develop 中(在主題分支合併之後);然後,當你標記版本時,你會將 master 快轉到現在穩定的 develop 分支所在的位置(在專案發佈之後)。

Before a topic branch merge
圖 74. 在主題分支合併之前
After a topic branch merge
圖 75. 在主題分支合併之後
After a project release
圖 76. 在專案發佈之後

這樣一來,當人們複製你的專案儲存庫時,他們可以簽出 master 來建立最新的穩定版本,並輕鬆保持更新,或者他們可以簽出 develop,這是更前沿的內容。你也可以透過擁有一個 integrate 分支來擴展這個概念,所有工作都會合併到其中。然後,當該分支上的程式碼庫穩定並通過測試時,你會將其合併到 develop 分支中;而當它證明自身穩定一段時間後,你會快轉你的 master 分支。

大型合併工作流程

Git 專案有四個長時間運行的分支:masternextseen(以前稱為 'pu' - 提議更新)用於新工作,而 maint 用於維護性的反向移植。當貢獻者引入新工作時,它們會以類似於我們描述的方式收集到維護者的儲存庫中的主題分支中(請參閱管理複雜的平行貢獻主題分支系列)。此時,會評估這些主題,以確定它們是否安全且可以接受,或者是否需要更多工作。如果它們是安全的,則會將它們合併到 next 中,並將該分支推送上去,以便所有人都可以嘗試整合在一起的主題。

Managing a complex series of parallel contributed topic branches
圖 77. 管理複雜的平行貢獻主題分支系列

如果這些主題仍然需要工作,則會將它們合併到 seen 中。當確定它們完全穩定時,會將這些主題重新合併到 master 中。然後會從 master 重建 nextseen 分支。這表示 master 幾乎總是向前移動,next 會偶爾進行 rebase,而 seen 則更頻繁地進行 rebase。

Merging contributed topic branches into long-term integration branches
圖 78. 將貢獻的主題分支合併到長期整合分支中

當一個主題分支最終合併到 master 中時,它會從儲存庫中刪除。Git 專案還有一個 maint 分支,它是從最後一個版本分叉出來的,以便在需要維護版本時提供反向移植的修補程式。因此,當你複製 Git 儲存庫時,你可以簽出四個分支,以評估專案在不同開發階段的狀況,具體取決於你想要多前沿,或者你想要如何貢獻;而維護者則有一個結構化的工作流程,以協助他們審核新的貢獻。Git 專案的工作流程是專門化的。為了清楚理解這一點,你可以查看Git 維護者指南

Rebasing 和 Cherry-Picking 工作流程

其他維護者傾向於將貢獻的工作 rebase 或 cherry-pick 到他們的 master 分支之上,而不是將其合併進來,以保持大部分線性歷史記錄。當你有一個主題分支中的工作,並且已確定要整合它時,你會移動到該分支並執行 rebase 命令,以在目前的 master(或 develop 等)分支之上重建變更。如果這一切順利,你可以快轉你的 master 分支,那麼你最終將得到一個線性的專案歷史記錄。

將引入的工作從一個分支移動到另一個分支的另一種方法是 cherry-pick。Git 中的 cherry-pick 就像是針對單一 commit 的 rebase。它會取得在 commit 中引入的修補程式,並嘗試將其重新應用到你目前所在的分支上。如果你在主題分支上有許多 commit,並且只想整合其中一個 commit,或者你只有一個主題分支上的 commit,並且你傾向於 cherry-pick 而不是執行 rebase 時,這會很有用。例如,假設你有的專案看起來像這樣

Example history before a cherry-pick
圖 79. 在 cherry-pick 之前的範例歷史記錄

如果你想將 commit e43a6 拉到你的 master 分支中,你可以執行

$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
 3 files changed, 17 insertions(+), 3 deletions(-)

這會拉入在 e43a6 中引入的相同變更,但你會獲得一個新的 commit SHA-1 值,因為套用的日期不同。現在你的歷史記錄看起來像這樣

History after cherry-picking a commit on a topic branch
圖 80. 在 cherry-picking 主題分支上的 commit 之後的歷史記錄

現在你可以移除你的主題分支並捨棄你不想拉入的 commit。

Rerere

如果你正在執行大量合併和 rebase,或者你正在維護一個長期存在的主題分支,Git 有一個名為「rerere」的功能可以提供協助。

Rerere 代表「reuse recorded resolution(重複使用記錄的解決方案)」— 這是一種捷徑來處理手動衝突解決的方法。啟用 rerere 後,Git 會保留成功合併的 pre- 和 post- 映像集,如果它注意到有一個衝突看起來和你已經修復的衝突完全一樣,它只會使用上次的修復,而不會打擾你。

此功能分為兩個部分:組態設定和命令。組態設定是 rerere.enabled,將其放入全域設定中會很方便

$ git config --global rerere.enabled true

現在,每當你執行會解決衝突的合併時,解決方案就會記錄在快取中,以備將來使用。

如果需要,你可以使用 git rerere 命令與 rerere 快取互動。當單獨叫用時,Git 會檢查其解決方案資料庫,並嘗試找出與任何目前合併衝突相符的項目並解決它們(儘管如果 rerere.enabled 設定為 true,則會自動執行此操作)。還有一些子命令可以用於查看將要記錄的內容、從快取中刪除特定解決方案,以及清除整個快取。我們將在Rerere中更詳細地介紹 rerere。

標記你的版本

當你決定建立版本時,你可能想指定一個標籤,以便你可以在未來隨時重新建立該版本。你可以如Git 基礎中所述建立新標籤。如果你決定以維護者的身分簽署標籤,標記可能會像這樣

$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09

如果你確實簽署了你的標籤,你可能會遇到發佈用於簽署標籤的公開 PGP 金鑰的問題。Git 專案的維護者已透過將其公開金鑰作為 blob 包含在儲存庫中,然後新增一個直接指向該內容的標籤來解決此問題。若要執行此操作,你可以執行 gpg --list-keys 來找出你想要的金鑰

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid                  Scott Chacon <schacon@gmail.com>
sub   2048g/45D02282 2009-02-09 [expires: 2010-02-09]

然後,你可以透過匯出金鑰並透過 git hash-object 管道傳輸,直接將金鑰匯入 Git 資料庫,這會將包含這些內容的新 blob 寫入 Git,並傳回 blob 的 SHA-1

$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92

現在你已將金鑰的內容放入 Git 中,你可以透過指定 hash-object 命令提供的新 SHA-1 值,建立一個直接指向它的標籤

$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92

如果你執行 git push --tagsmaintainer-pgp-pub 標籤將會與所有人共用。如果有人想要驗證標籤,他們可以透過直接從資料庫中取出 blob 並將其匯入 GPG 來直接匯入你的 PGP 金鑰

$ git show maintainer-pgp-pub | gpg --import

他們可以使用該金鑰來驗證你的所有簽署標籤。此外,如果你在標籤訊息中包含指示,執行 git show <tag> 將可讓您為最終使用者提供關於標籤驗證的更具體指示。

產生組建編號

由於 Git 沒有像 'v123' 這種單調遞增的數字,或者每個 commit 對應的等效數字,如果你想要有一個人類可讀的名稱與 commit 一起使用,你可以在該 commit 上執行 git describe。作為回應,Git 會產生一個字串,該字串由早於該 commit 的最新標籤名稱組成,後接自該標籤以來的 commit 數,最後是所描述 commit 的部分 SHA-1 值(以字母「g」表示 Git 為字首)

$ git describe master
v1.6.2-rc1-20-g8c5b85c

這樣一來,你可以匯出快照或組建,並將其命名為人們可以理解的名稱。事實上,如果你從 Git 儲存庫複製的原始碼組建 Git,git --version 會提供類似這樣的內容。如果你描述的是你已直接標記的 commit,則會直接提供標籤名稱。

依預設,git describe 命令需要附註標籤(使用 -a-s 旗標建立的標籤);如果你也想利用輕量(未附註)標籤,請將 --tags 選項新增至命令。你也可以使用此字串作為 git checkoutgit show 命令的目標,儘管它依賴於結尾的縮寫 SHA-1 值,因此它可能不會永遠有效。例如,Linux 核心最近從 8 個字元跳到 10 個字元,以確保 SHA-1 物件的唯一性,因此較舊的 git describe 輸出名稱已失效。

準備發佈

現在你想要發佈組建。你想要執行的一件事是為那些不使用 Git 的可憐人建立最新程式碼快照的封存。執行此操作的命令是 git archive

$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz

如果有人開啟該 tarball,他們會在 project 目錄下取得專案的最新快照。你也可以以大致相同的方式建立 zip 封存,但將 --format=zip 選項傳遞給 git archive

$ git archive master --prefix='project/' --format=zip > `git describe master`.zip

你現在有一個不錯的 tarball 和專案版本的 zip 封存,你可以將它們上傳到你的網站或以電子郵件寄給人們。

Shortlog

是時候透過電子郵件通知你的郵寄清單中的人員,讓他們知道你的專案中發生了什麼事。快速取得自上次版本或電子郵件以來新增至你的專案之變更記錄的一種好方法是使用 git shortlog 命令。它會摘要你給定的範圍內的所有 commit;例如,如果你的上次版本名為 v1.0.1,則以下程式碼會提供自上次版本以來所有 commit 的摘要

$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
      Add support for annotated tags to Grit::Tag
      Add packed-refs annotated tag support.
      Add Grit::Commit#to_patch
      Update version and History.txt
      Remove stray `puts`
      Make ls_tree ignore nils

Tom Preston-Werner (4):
      fix dates in history
      dynamic version method
      Version bump to 1.0.2
      Regenerated gemspec for version 1.0.2

你會取得自 v1.0.1 以來所有 commit 的簡潔摘要,並依作者分組,你可以將其透過電子郵件寄給你的清單。

scroll-to-top