[英]Git: How to create patches for a merge?
當我使用git format-patch
時,它似乎不包括合並。 如何執行合並,然后將其作為一組補丁通過電子郵件發送給某人?
例如,假設我合並兩個分支並在合並之上執行另一個提交:
git init
echo "initial file" > test.txt
git add test.txt
git commit -m "Commit A"
git checkout -b foo master
echo "foo" > test.txt
git commit -a -m "Commit B"
git checkout -b bar master
echo "bar" > test.txt
git commit -a -m "Commit C"
git merge foo
echo "foobar" > test.txt
git commit -a -m "Commit M"
echo "2nd line" >> test.txt
git commit -a -m "Commit D"
這將創建以下樹:
B
/ \
A M - D
\ /
C
現在我嘗試檢查初始提交並重放上述更改:
git checkout -b replay master
git format-patch --stdout master..bar | git am -3
這會產生合並沖突。 在這種情況下, git format-patch master..bar
只生成 3 個補丁,省略“Commit M”。 我該如何處理?
——傑弗里·李
似乎沒有一個解決方案可以生成單獨的提交,例如git format-patch
,但是FWIW,你可以格式化一個包含有效合並提交的補丁,適合/兼容git am
:
顯然, Git參考指南提供了第一個提示:
git log -p show patch在每次提交時引入
[...]這意味着對於任何提交,您都可以獲得提交給項目的提交補丁。 您可以通過使用特定提交SHA運行
git show [SHA]
來執行此操作,也可以運行git log -p
,它告訴Git在每次提交后放置補丁。 [...]
現在, git-log的手冊頁給出了第二個提示:
git log -p -m --first-parent
...顯示包含更改差異的歷史記錄,但僅限於“主分支”透視圖,跳過來自合並分支的提交,並顯示合並引入的完整變更差異。 只有遵循嚴格的策略,在停留在單個集成分支上時合並所有主題分支才有意義。
這反過來意味着具體步驟:
# Perform the merge:
git checkout master
git merge feature
... resolve conflicts or whatever ...
git commit
# Format a patch:
git log -p --reverse --pretty=email --stat -m --first-parent origin/master..HEAD > feature.patch
這可以按預期應用:
git am feature.patch
同樣,這將不包含單個提交,但它會從合並提交中生成一個git am
兼容的補丁。
當然,如果你首先不需要兼容git am
補丁,那么它就更簡單了:
git diff origin/master > feature.patch
但我想你已經想到了,如果你在這里登陸這個頁面,你實際上正在尋找我上面描述的解決方法/解決方案。 ;)
請注意,裸git log -p
不會顯示合並提交“M”的任何補丁內容,但使用git log -p -c
會將其哄騙。 然而, git format-patch
不接受類似於任何參數-c
(或--combined
, -cc
被接受) git log
。
我也是難過的。
擴展了sun
的答案,我找到了一個命令,它可以生成一系列補丁,類似於git format-patch
會產生git format-patch
,並且你可以提供給git am
來生成個人提交的歷史記錄:
git log -p --pretty=email --stat -m --first-parent --reverse origin/master..HEAD | \
csplit -b %04d.patch - '/^From [a-z0-9]\{40\} .*$/' '{*}'
rm xx0000.patch
修補程序將命名為xx0001.patch
到xxLAST.patch
如果您檢查前兩個補丁的內容,您將看到問題:
diff --git a/test.txt b/test.txt
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-initial file
+foo
diff --git a/test.txt b/test.txt
index 7c21ad4..5716ca5 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-initial file
+bar
從您當時正在處理的分支(foo和bar)的角度來看,這兩個提交都刪除了“初始文件”行並完全替換了其他內容。 AFAIK,當你生成一個具有重疊變化的非線性進程的補丁時,沒有辦法避免這種沖突(在這種情況下你的分支提交B和C)。
人們通常使用補丁來添加單個功能或修復已知良好的先前工作狀態的錯誤 - 補丁協議根本不夠復雜,無法像Git本身那樣處理合並歷史。 如果你想讓某人看到你的合並,那么你需要在分支之間推/拉而不是退回差異/補丁。
使用Philippe De Muyter的解決方案,我制作了一個版本,以與git-format-patch相同的方式格式化補丁(據我所知)。 只需將RANGE設置為所需的提交范圍(例如origin..HEAD),然后執行:
LIST=$(git log --oneline --first-parent --reverse ${RANGE});
I=0;
IFS=$'\n';
for ITEM in ${LIST}; do
NNNN=$(printf "%04d\n" $I);
COMMIT=$(echo "${ITEM}" | sed 's|^\([^ ]*\) \(.*\)|\1|');
TITLE=$(echo "${ITEM}" | sed 's|^\([^ ]*\) \(.*\)|\2|' | sed 's|[ -/~]|-|g' | sed 's|--*|-|g' | sed 's|^\(.\{52\}\).*|\1|');
FILENAME="${NNNN}-${TITLE}.patch";
echo "${FILENAME}";
git log -p --pretty=email --stat -m --first-parent ${COMMIT}~1..${COMMIT} > ${FILENAME};
I=$(($I+1));
done
請注意,如果您使用git-quiltimport,那么您將需要排除任何空的合並提交,否則您將收到錯誤“Patch為空。它是否分裂錯誤?”。
使用 Git 2.32(2021 年第二季度),“ format-patch
”文檔更加清晰:它跳過了合並。
請參閱Jeff King ( peff
)的提交 8e0601f (2021 年 5 月 1 日)。
(由Junio C Hamano -- gitster
--在提交 270f8bf中合並,2021 年 5 月 11 日)
docs/format-patch
:提及合並處理簽字人:傑夫·金
Format-patch 沒有辦法以
git-am
(或任何其他工具)可以應用的方式格式化合並,因此它只是省略了它們。
但是,對於不熟悉該工具如何工作的用戶來說,這可能是一個令人驚訝的暗示。
讓我們在文檔中添加一個注釋,使其更加清晰。
git format-patch
現在包含在其手冊頁中:
准備每個非合並提交及其“補丁”
git format-patch
現在包含在其手冊頁中:
注意事項
請注意,
format-patch
將忽略輸出中的合並提交,即使它們是請求范圍的一部分。
一個簡單的“補丁”不包含足夠的信息讓接收端重現相同的合並提交。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.