簡體   English   中英

Git:手動合並未檢測到的重命名中的更改

[英]Git: Manually merge changes in an undetected rename

這個問題使用Git 2.7.0.windows.1 ,因此某些git命令可能已過時。

如果我的git merge命令沒有檢測到重命名的文件,我如何告訴git手動合並應該是單個文件的兩個文件中的更改,而無需重新開始合並並使用較低的重命名閾值?

復制步驟:

git init
echo "//Hello world!" > hw.h
git add . && git commit -m "Initial commit"
git checkout -b someBranch
mv hw.h hw.hpp
echo "//Foobar" > hw.hpp
git add . && git commit -m "Change hw to HPP & change content"
git checkout master
echo "//Boofar" > hw.h
git add . && git commit -m "Change content of hw"
git merge -X rename-threshold=100% someBranch

您將獲得合並沖突,但不會有沖突的塊。 也就是說,您應該獲得的唯一沖突/錯誤是:

CONFLICT (modify/delete): hw.h deleted in branchB and modified in HEAD. Version HEAD of hw.h left in tree.
Automatic merge failed; fix conflicts and then commit the result.

git status --porcelain將顯示:

UD hw.h
A  hw.hpp

通常,合並時,最好將檢測重命名的閾值設置得足夠低,以至於無法檢測到重命名。 例如, 有人建議5% 就我而言,我正在進行大量合並(> 1000個文件和大約900萬個LOC),並且我不得不將重命名閾值提高到足夠高的水平,以避免出現任何“誤報”。 實際降低了百分之一,而且我得到了大量錯誤檢測到的重命名(我知道,重復的代碼很爛)。 以我最終使用的價值,我只得到了很少的錯過的重命名,這似乎是一個更好的選擇。

TL; DR降低重命名閾值不是我的選擇; 如何在不開始合並的情況下告訴git將hw.hhw.hpp視為單個文件(有沖突),而不是如上所述的兩個文件?

用於此的工具有些笨拙,但它們那里。

您需要確保合並本身在提交之前停止。 您的情況會自動發生。 對於棘手的合並,Git認為它可以正確執行,但實際上並沒有,您可以添加--no-commit ,但這會影響接下來的幾個步驟。 我們暫時將忽略該問題。

接下來,您需要獲取該文件的所有三個版本。 由於Git因沖突而停止,因此我們處於良好狀態:這三個版本均可通過索引訪問。 請記住,我們關心的三個版本是merge base ,-- --ours--theirs

如果Git 正確檢測到重命名,則所有三個版本將以單個名稱在索引中。 既然沒有,他們就不是:我們需要兩個名字。 (在“ Git認為它正確合並的情況下”,該文件的合並基礎版本根本不在索引中,我們必須以其他方式檢索它。)在這種情況下,這兩個名稱是hw.hhw.hpp ,所以現在我們這樣做:

$ git show :1:hw.h > hw.h.base    # extract base version
$ git show :2:hw.h > hw.h         # extract ours
$ mv hw.hpp hw.h.theirs           # move theirs into place

(重命名並不是嚴格必須的,它只是為了使它們保持整潔並得到很好的說明。)

現在我們要用git merge-file

$ git merge-file hw.h hw.h.base hw.h.theirs

這將使用您配置的merge.conflictStyle以便合並文件中的內容與您期望的一樣,除了沖突行上的標簽略有不同。 我設置了diff3 ,所以我得到:

$ cat hw.h
<<<<<<< hw.h
//Boofar
||||||| hw.h.base
//Hello world!
=======
//Foobar
>>>>>>> hw.h.theirs

現在,您可以解決此像往常一樣, rm額外.base.theirs文件, git add最終的結果, git rm --cached hw.hpp ,和git commit (這取決於您何時使用git rm --cached hw.hpp :在提交之前的任何時間都可以安全地執行此操作,但是一旦完成,您將無法再從索引中獲取“它們的”;請參見下文。)

注意,“我們的”和“他們的”版本也可以通過git show HEAD:pathgit show MERGE_HEAD:path 為了獲得沒有索引的基本版本,我們必須運行git merge-base HEAD MERGE_HEAD來查找其哈希ID(然后假設還有一個合並基數1 ),以及git show <hash>:path 如果Git認為它正確完成了合並,這就是我們必須做的。

還要注意,如果您確實想(我想這只有在您想要使用其他一些需要它的工具時才是對的),您可以使用git update-index來隨機整理git update-index中的條目,移動hw.hpp入插槽,3 hw.h ,以免被顯示為“他們”,並顯示了以這種方式git status 對於此特定示例:

 $ printf '100644 bbda177a6ecfe285153467ff8fd332de5ecfb2f8 3\thw.h' |
     git update-index --index-info

這里的哈希值是從哪里來的git ls-files --stage ,是哈希hw.hpp (您需要執行第二步來刪除hw.hpp索引條目。)


1使用git merge-base --all查找所有合並庫。 如果有多個,則可以任意選擇一個(這是-s resolve作用),也可以嘗試將所有合並基礎合並為虛擬合並基礎 要合並兩個合並庫,您可以找到它們自己的合並庫,並使用該合並庫合並兩個庫,就好像它們是分支提示一樣。 根據需要進行遞歸和迭代-這是Git使用默認的-s recursive策略所做的-直到您擁有該文件的單個合並基礎版本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM