簡體   English   中英

合並后 Git 提交丟失

[英]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的作用是:

  1. extract commit c2c2c2...
  2. 提取c2c2c2...的父提交c2c2c2...
  3. 產生從父母到孩子的差異列表

這就是Git如何設法向您展示改變的內容:它將“您提交之前的內容”與“您提交的內容”進行比較。 (Git可以很快地進行優化,因為每個文件都被簡化為一個獨特的散列“指紋”,Git可以先比較指紋(散列)。如果散列相同,則文件是相同的。如果哈希值不同,它只需要提取實際文件數據。)

這種節省流程的整個文件,而不是累積更改,稱為“存儲快照”。 (其他版本控制系統傾向於積累變化,這稱為“存儲增量”。他們這樣做是因為保存對文件的更改顯然比保存文件所需的空間少得多.Git巧妙地圍繞這個問題偷偷摸摸地使用無論如何,磁盤空間比舊的基於delta的版本控制系統少。)

為什么“Git存儲快照而不是增量”在這里非常重要

合並提交是特殊的,以一種特別明顯的方式。 查看您自己的圖表並考慮Merge1 在它之前發生了什么?

這里的答案是AmC2都在“ Merge1之前”。 也就是說,提交Merge1兩個父提交。

如果你要求Git向你展示提交Merge1 ,哪個父級應該與之比較?

事情變得特別奇怪。 兩個命令git log -pgit 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 而且,從圖中可以Merge2Merge2的兩個父母是An (它有你喜歡的方式的f2 )和Bn (它沒有)。

這里實際發生的是,在創建Merge2的合並期間,你以某種方式告訴Git使用提交Bnf2版本。 也就是說,文件f2Merge2是完全一樣文件f2Bn ,並且來自不同f2中提交An

如果你使用git show來查看Merge2 ,組合的diff會跳過 f2 ,因為它 Bnf2 相同

同樣的道理,更糟糕的是,使用git log -p :它完全跳過了合並,因為它太難以顯示差異。

即使沒有-p ,當你要求“文件改變”時, git log也會做同樣的事情 - 完全跳過合並。 這就是為什么你不能在日志輸出中看到它。

(順便說一下, git log master -- f2從未顯示提交C2本身的原因是在git log的選項中添加文件名會打開“歷史簡化”。在我認為有些錯誤的行為中,Git結束了簡化掉了太多的歷史,所以它永遠不會顯示提交C2增加。 --full-history的前-- f2恢復C2到設定而犯所展示的合並,至今下落不明,不過,因為。 git log跳過它)。

如何看待變化

有一個解決方案。 git showgit log都有一個額外的標志, -m ,它“拆分”合並。 也就是說,不是將Merge2視為合並提交,而是將合並分解為兩個“虛擬提交”。 一個是“ Merge2 vs An ”,您將看到這兩個提交之間的所有差異,另一個將是“ Merge2 vs Bn ”,您將看到兩個提交之間的所有差異。 這將顯示文件f2被重新設置為它在Bn的方式,丟失了出現在An但不在BnAn C2的版本。

(包括--full-history以及-m以確保提交C2顯示出來。)

這首先是怎么回事

這一部分根本不清楚。 你說有一個合並沖突,這意味着git merge停止並獲得人工的手動幫助。 在此輔助期間的某個時刻,人類可能使用來自Bn的文件f2的版本更新索引(或者至少是在C2沒有進行更改的f2版本)。

這可能發生在合並期間,並且它有點陰險, 因為 Git顯示與這些壓縮(組合)差異合並,或者在git log -p的情況下,默認情況下根本不合並。 這是值得注意的,特別是如果合並需要手動沖突解決。 在大多數情況下,捕獲此類合並錯誤的方法是使用自動化測試。 (當然,並非所有東西都可以測試。)

我也有這個問題,這就是我修復它的方法:

  1. 使用git log顯示我的提交歷史記錄。

  2. 使用git show <filename>顯示對頑固文件所做的更改。

  3. 沒工作。 搜索了StackOverflow,嘗試了好幾次。

  4. 關閉並重新打開文件。 瞧。

我的Atom文本編輯器中新打開的文件顯示了我預期的更改。

暫無
暫無

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

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