簡體   English   中英

Git:在推送后恢復與意外丟棄文件的合並

[英]Git: Revert a merge with accidentally discarded files, after it's been pushed

一個沒有經驗的用戶進行更改release ,然后合並到dev 哦不,合並沖突! 合並狀態顯示他們自己的沖突文件,以及其他團隊成員的所有其他修復。 作為一個偏執和謹慎的用戶,他們說:

那些不是我的文件,是我不小心修改了它們嗎? 啊哈,我應該discard它們!

合並提交現在只包含他們的更改,丟棄分支中的所有其他更改(可能是大量工作)。 他們將dev推向上游,錯誤逃脫檢測,直到另一個團隊成員注意到有什么不對勁。

大多數指導建議:

  1. 如果分支還沒有被推送: git reset
  2. 恢復合並: git revert -m 1 <commitId> 然而,這只會還原數據(也就是只有倒霉的用戶的更改),它不會撤消歷史記錄。 任何未來的merge嘗試都將忽略丟失的更改,因為歷史意味着它們已經被集成。
  3. 重寫歷史記錄、 rebasereset然后是git push origin -f 這意味着團隊的其他成員必須同步到強制dev分支。 如果團隊很大,或者錯誤沒有被迅速發現,或者存在精心設計的 CI 工具——這將成為一項非常痛苦的工作。

恕我直言,這讓我對 git 的設計產生了嚴重的疏忽。 很少有工具可以識別這種情況或從這種情況中恢復過來。 git diff不顯示丟棄的更改,並且git revert不會撤消那些丟棄的更改。 有沒有更好的方法來預防和解決這個問題?

正如 Linus ( https://mirrors.edge.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt ) 所詳述:

恢復常規提交只會有效地撤消該提交所做的事情,並且相當簡單。 但是恢復合並提交也會撤消提交更改的數據,但它對合並對歷史的影響絕對沒有任何影響。

所以合並仍然存在,它仍然會被視為將兩個分支連接在一起,未來的合並會將合並視為最后一個共享狀態 - 恢復引入的合並的恢復根本不會影響它。

因此,通過“還原”撤銷數據的變化,但是這是非常沒有在這個意義上,它不會取消的影響對信息庫歷史提交的“撤銷”。

好的,這就解釋了為什么revert不是一種有效的策略,但我們能做什么? 讓我們考慮以下幾點:

p---Q---r---s---M---t---u---   dev
     \         /
      A---B---C-------D---E    feature
  • ABC 是功能/發布分支​​工作
  • M 是錯誤的合並,是否丟棄了 AB 的更改,但保留了 C
  • DE 是后來的feature
  • 其余是主線分支dev上無關的更改

只要 M 存在於dev ,它就假定 ABC 的歷史已經被整合,即使 AB 的增量缺失。 為了在不改變dev歷史的情況下恢復它們,我們需要在備用歷史(即新的提交 ID)中重新創建增量。

如果只有幾個提交,您可以cherrypick每個提交單獨cherrypickdev因為挑選將數據復制到新的提交 ID 中。 然而,這不能很好地擴展到大型或復雜的分支歷史。

下一個選項是使用rebase --no-ff重新創建一個新的feature分支,可以從中合並丟失的更改。

git checkout E
git rebase --no-ff Q

這將創建以下內容:

      A'--B'--C'-------D'--E'    feature-fixed
     /                      \
p---Q---r---s---M---t---u---M2   dev
     \         /
      A---B---C--------D---E     feature

由於合並沖突,原始合並 M 可能只是成為一個問題。 這種方法的一個問題是,您不僅必須正確解決 ABC 中的原始沖突,而且現在您還需要應對 DE 和 TU 中新的可能沖突源。 在緊急情況下,這可能很難弄清楚發生了什么。

首選解決方案:

p---Q---r---S-------M---t---u-----M3      dev
     \       \     /              /
      A---B---\---C----D---E     /        feature
               \   \            /
                ----M2----------          fix

使用您可能熟悉的工具的更簡單策略是使用squash提交 (M2) 正確重新創建合並。 這會創建一個新的提交 ID(新歷史),因此來自 AB 的增量可以成功地集成回主線。 此方法還可以關閉合並沖突的可能來源,允許您首先糾正錯誤,然后處理上游更改。

方法:

在錯誤合並 (M) 登陸之前從dev分支。

git checkout -b fix S

您現在有一個干凈的石板,您可以從中執行更正的合並。 壁球標志會將這些更改壓縮為單個提交,但更重要的是它將生成一個新的提交 ID

git merge --squash C

可能此時您需要解決沖突,但是 M2 現在表示 M 最初應包含的所有數據。 您現在可以像往常一樣將其合並到 dev

git checkout dev
git merge fix

同樣,可能會出現合並沖突,但在這一點 (M3) 之后,您已經恢復了丟失的數據。 您現在可以按照正常方式自由進行,例如您可以自由地將 DE 從feature合並到dev或任何其他常規操作中。 這也意味着沒有其他團隊成員需要重置他們的本地dev分支,因為它會在他們下次執行pull時恢復。

暫無
暫無

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

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