[英]Git commit lost after merge
我們有 3 個分支(A、B、C),如下所示:
---\--A1--\------Am------Merge1---An---Merge2---
\ \ / /
\ \--C1---C2---/ /
\ /
\--B1--------------Bn---------/
問題出現在 Merge2。 在 Merge2 之后,分支 C 上的一些提交(不是全部,而是一些,比方說 C2)在分支 A 上丟失,它存在於 Merge1 和 Merge2 之間。
在進行 Merge2 時,只有一個文件沖突,與丟失的提交 (C2) 無關。 我們解決了沖突並成功完成了合並。
似乎 C2 在分支 A 上被 Merge2 反轉,沒有任何日志。
發生了什么? 造成這種情況的原因可能是什么?
你的意思不是提交本身丟失,而是在該提交中對 (某些文件) 所做的更改已被還原(未制作)。
值得注意的是,提交並不真正“對文件進行更改”。 相反,每個提交都存儲一整套完整且完整的文件。 當你要求Git向你展示一些提交時(假設它的ID是c2c2c2...
):
$ git show c2c2c2
Git的作用是:
c2c2c2...
c2c2c2...
的父提交c2c2c2...
這就是Git如何設法向您展示改變的內容:它將“您提交之前的內容”與“您提交的內容”進行比較。 (Git可以很快地進行優化,因為每個文件都被簡化為一個獨特的散列“指紋”,Git可以先比較指紋(散列)。如果散列相同,則文件是相同的。如果哈希值不同,它只需要提取實際文件數據。)
這種節省流程的整個文件,而不是累積更改,稱為“存儲快照”。 (其他版本控制系統傾向於積累變化,這稱為“存儲增量”。他們這樣做是因為保存對文件的更改顯然比保存文件所需的空間少得多.Git巧妙地圍繞這個問題偷偷摸摸地使用無論如何,磁盤空間比舊的基於delta的版本控制系統少。)
合並提交是特殊的,以一種特別明顯的方式。 查看您自己的圖表並考慮Merge1
。 在它之前發生了什么?
這里的答案是Am
和C2
都在“ Merge1
之前”。 也就是說,提交Merge1
有兩個父提交。
如果你要求Git向你展示提交Merge1
,哪個父級應該與之比較?
事情變得特別奇怪。 兩個命令git log -p
和git show
看起來非常相似。 事實上,他們都非常相似。 一個明顯的區別是git log -p
顯示了多個提交,而git show
只顯示了你告訴它顯示的一個提交。 你可以運行git log -n 1 -p <commit>
來顯示一個提交,現在看來它們完全相同 。
他們不是!
當您在合並提交中使用git show
時,Git會嘗試通過同時對兩個父項進行比較來解決“比較什么提交”問題。 產生的差異稱為組合差異 。
然而,當你在合並提交中使用git log -p
時,Git只是拋出了它的隱喻之手,說“我無法顯示針對兩個父母的補丁”,然后放棄並繼續進行下一次提交。 換句話說, git log -p
甚至不會為合並嘗試差異。
現在,在這種情況下,您可能想知道是否可以從提交c2c2c2...
您的文件發生了什么c2c2c2...
在兩個合並上使用git show
- 特別是在Merge2
,其中更改已被還原。 但是git show
默認會產生一個組合差異 ,而組合差異會故意省略很多差異輸出。 特別是,組合差異僅列出從所有父項修改的文件 。
假設您從C2
更改的文件是文件f2
。 而且,從圖中可以Merge2
, Merge2
的兩個父母是An
(它有你喜歡的方式的f2
)和Bn
(它沒有)。
這里實際發生的是,在創建Merge2
的合並期間,你以某種方式告訴Git使用提交Bn
的f2
版本。 也就是說,文件f2
在Merge2
是完全一樣文件f2
在Bn
,並且來自不同f2
中提交An
。
如果你使用git show
來查看Merge2
,組合的diff會跳過 f2
,因為它與 Bn
的f2
相同 。
同樣的道理,更糟糕的是,使用git log -p
:它完全跳過了合並,因為它太難以顯示差異。
即使沒有-p
,當你要求“文件改變”時, git log
也會做同樣的事情 - 完全跳過合並。 這就是為什么你不能在日志輸出中看到它。
(順便說一下, git log master -- f2
從未顯示提交C2
本身的原因是在git log
的選項中添加文件名會打開“歷史簡化”。在我認為有些錯誤的行為中,Git結束了簡化掉了太多的歷史,所以它永遠不會顯示提交C2
增加。 --full-history
的前-- f2
恢復C2
到設定而犯所展示的合並,至今下落不明,不過,因為。 git log
跳過它)。
有一個解決方案。 git show
和git log
都有一個額外的標志, -m
,它“拆分”合並。 也就是說,不是將Merge2
視為合並提交,而是將合並分解為兩個“虛擬提交”。 一個是“ Merge2
vs An
”,您將看到這兩個提交之間的所有差異,另一個將是“ Merge2
vs Bn
”,您將看到這兩個提交之間的所有差異。 這將顯示文件f2
被重新設置為它在Bn
的方式,丟失了出現在An
但不在Bn
中An
C2
的版本。
(包括--full-history
以及-m
以確保提交C2
顯示出來。)
這一部分根本不清楚。 你說有一個合並沖突,這意味着git merge
停止並獲得人工的手動幫助。 在此輔助期間的某個時刻,人類可能使用來自Bn
的文件f2
的版本更新索引(或者至少是在C2
沒有進行更改的f2
版本)。
這可能發生在合並期間,並且它有點陰險, 因為 Git顯示與這些壓縮(組合)差異合並,或者在git log -p
的情況下,默認情況下根本不合並。 這是值得注意的,特別是如果合並需要手動沖突解決。 在大多數情況下,捕獲此類合並錯誤的方法是使用自動化測試。 (當然,並非所有東西都可以測試。)
我也有這個問題,這就是我修復它的方法:
使用git log
顯示我的提交歷史記錄。
使用git show
<filename>
顯示對頑固文件所做的更改。
沒工作。 搜索了StackOverflow,嘗試了好幾次。
關閉並重新打開文件。 瞧。
我的Atom文本編輯器中新打開的文件顯示了我預期的更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.