簡體   English   中英

修復GIT存儲庫的歷史記錄

[英]Fixing history on GIT repository

我的GIT存儲庫中存在以下情況。 在做出改變之前,有人忘記了拉大師,然后他的當地大師承諾。 在那之后,由於某種原因,他將原點/主人合並到他的本地主人,然后推了它。 結果是原點/主人有點“切換位置”與他當地的主人。 我有意義嗎? 這是一個例子:

在推前

x----x-----x----x----x----x----x-----x----x (MASTER)

推后

 ---------------------------------------------x---x (MASTER)
|                                                 |
x----x-----x----x----x----x----x-----x----x-------

這有點搞亂了存儲庫,因為現在所有的歷史似乎都在分支上。

在那之后,有一些新的提交被推送到新的主人,然后由於一個現在不重要的原因,我們決定我們不想要那些,所以我們設法放棄了我們不想要的提交,並且同時將de MASTER恢復到原來的位置。 像這樣:

之前

 ---------------------------------------------x---x---x---x---x (MASTER)
|                                                 |
x----x-----x----x----x----x----x-----x----x-------

                                             (2)
 ---------------------------------------------x---x---x---x---x-- 
|                                               |                |
x----x-----x----x----x----x----x-----x----x-----x----------------x (MASTER)
                                         (1)                    (3)

正如你所看到的那樣,現在那個忘記了tu pull的人所提交的提交已被合並到最初的主人那里。 這是通過以下方式實現的:

git checkout <HASH OF COMMIT MARKED AS (1) >
git checkout -b refactor_master
git merge --no-ff <HASH OF COMMIT MARKED AS (2) >
git push origin refactor_master
git merge --strategy=ours mastergit checkout master
git merge refactor_master
git push origin master

這有效地使那些承諾所包含的變化從主人那里消失了,並且使主人變成了過去的樣子。 但是,我現在有一個不應該存在的“分支”。 實際上,標記為(3)的最后一次提交不會進行任何更改。 它只會“切換”主人。 有沒有辦法讓這些提交消失?

這是有道理的:他所做的是違反“主線發展是第一父母”的規則。

請注意,git本身沒有任何內容可以強制執行此規則。 這是不可能的,原因很簡單:誰定義哪條線是“主線”? 這個問題唯一可能的答案是“你”,其中“你”的意思是“運行git來操縱提交圖的人”。 所以這不是一個真正的git規則,它是一個“使用git”規則的人。

每當你運行git merge (或者在這種情況下“he”運行它),你選擇當前的分支作為開發的主線,以及你正在合並的任何合並的替代線。 因此,如果你這樣做:

$ git checkout master
$ make-some-change; git add ...; git commit -m message

$ git fetch origin # and let's assume this brings in a new commit
$ git merge origin/master

你告訴git將你的主人作為主線,並將上游變化合並為分支線。

請注意,最后兩個命令 - git fetch后跟git merge - 是git pull默認執行的操作。 反過來,這意味着“主線是第一父母”經常被違反,除非你非常嚴格/小心,否則不能依賴它。


有沒有辦法讓那些[merge]提交消失?

是的,但只能寫一個新的提交行(“重寫歷史”)。

讓我把你的最終圖表(不用擔心你是如何到達那里)並對繪圖進行一些小的改動以獲得更緊湊的表示:

  ------------------------A---M1--B--C--D
 /                           /           \
o--o--o--o--o--o--o--o--o---x-------------M2   <-- master

此時提交BD “在錯誤的行上”,因為合並提交M2的第一個父項是x ,其第二個父項是D 同時,提交AM1的第一個父級, xM1的第二個父級。

如果你真的非常關心第一父規則,你可以使用提交x來提交一個的提交行:

  ------------------------A---M1--B--C--D
 /                           /           \
o--o--o--o--o--o--o--o--o---x-------------M2   <-- master
                             \
                              A'--B'--C'--D'   <-- new-master

這里A'第一個也是唯一一個父是commit x ,當事情第一次“出錯”時,這就是master的提示。 B'的第一個也是唯一的父母是A',依此類推。

如果你有這個圖表,你從白板上刪除提交AM2並讓master點提交D' ,你將擁有:

o--o--o--o--o--o--o--o--o---x
                             \
                              A'--B'--C'--D'   <-- master

現在你可以“理順”從xA'的鏈接,它看起來像一個很好的線性歷史。

這是一個棘手的部分:這只是你想要的圖形 對於圖中的每個提交,git都會保留一個 :當你git checkout提交時,要放在工作目錄中的一組文件。 你想為每個提交A'通過D'可能不完全一樣的原始樹木A通過D

可以肯定的是, B'C'D'所需的樹將分別與BCD相同。 但是,您想要用於新提交A'的樹可能是當前在合並M1下的樹。 可能與提交A下的那個相同,但可能不是。 這實際上取決於AM1 A比較。

在沒有大量手工工作的情況下,有許多相對棘手的方法來構建新提交,但它們很難在文本中描述。 此外,這種“歷史重寫” - 當你強行讓舊的master標簽指向new-master的提交D'時發生的那一部分 - 給你所有的開發人員帶來了痛苦,他們正在做出以M2作為他們的承諾父提交。 他們必須將這些提交復制到新提交的新D'作為他們的父母。

這取決於你是否值得,這取決於你和他們。

git分支只是一個指向單個提交的標簽。 提交不知道當前指向哪個分支; 它也不知道以前哪些分支指向它的歷史。 因此,唯一真正重要的事情(並且改變是非常重要的)是提交歷史本身。

清除它的最簡單方法可能如下:找到您認為代表代碼庫的合理狀態的最新提交,並運行以下命令(假設該提交的哈希值為123abc ):

git checkout -B master 123abc
git push -f origin master

這將使master在本地(在運行這些命令的任何人的機器上)和服務器上指向123abc 當其他開發人員運行git fetch ,其origin/master會移動到123abc ,他們可以檢查出來,並把他們自己的master與有git checkout -B master origin/master (我不能完全肯定的語法此但是,命令,我手邊沒有git存儲庫。)

警告:除非你有一個分支指向比123abc更新的提交,否則這些提交似乎會消失。 如果你想稍后查看它們的內容以便清理它並重新提交它,你應該首先為這些提交創建分支,例如git branch tempbranch 567def

暫無
暫無

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

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