簡體   English   中英

Git:使用分支及其遠程在不同分支上修復存儲庫

[英]Git: Fix repo with a branch and its remote on different branches

我不知道這是怎么發生的,但是我有一個處於以下狀態的 git repo:

A--B--C--D  master
    \
     E--F   origin/master

提交EF在這一點上已經過時了; 他們對B所做的更改沒有相關性,如有必要,可以將其刪除。

我只保留了origin遠程作為我的代碼進行備份,而不是別人已經克隆它,這樣我就可以使用任何蠻力我所需要的。

清除此問題的最干凈方法是什么?

我只保留遠程源作為我代碼的備份,沒有其他人克隆它,所以我可以使用我需要的任何蠻力。

在這種情況下, git push --force origin master就足夠了。 非常確定您對存儲庫中的origin/master問題,並且在(單獨的)Git 存儲庫中的master超過origin ,不再能夠找到提交F

(您自己的存儲庫會在一段時間內記住EF提交,在reflog 名稱origin/master@{ number } ,因此只要您保持自己的存儲庫完整無缺,如果結果證明沒有,您仍然可以取回它們畢竟已經過時了。然而,在某些時候它們真的會被刪除。服務器可能根本沒有 reflogs,它的提交EF副本可能會相對較快地消失——在幾秒鍾、幾小時或幾天內,例如。)

這如何以及為什么有效

每個 Git 存儲庫都有自己的分支名稱,這些名稱對該特定 Git 存儲庫來說是半私有的。 在您調用origin的機器上有一個存儲庫,它有一個分支名稱master

您的遠程跟蹤名稱,1origin/master ,是什么記住一些其他Git有它的分支名稱的Git的方法。 在這種情況下,您的origin/master是您的 Git 對originmaster的記憶。

當你讓你的 Git 通過git fetchgit push調用他們的 Git 時,兩個 Git 有一個啟動對話。 fetch 和 push 略有不同,但您可以使用git ls-remote觀察git fetch本身將觀察到什么。 只需運行git ls-remote origin (或保留origin作為默認值通常是origin反正):您的 Git 將溢出它列出的另一個Git 的分支、標簽和其他名稱。 這是git fetch的第一部分:您的 Git 打電話給他們的 Git 並獲取此列表。

當您使用git fetch ,您的 Git 使用此列表向他們的 Git 詢問他們擁有的、您沒有的、您的 Git 希望擁有的任何提交和其他內部 Git 對象。 例如,如果你還沒有提交F ,而你的origin/master記住了提交BE ,並且他們已經提交F作為他們的master ,你的 Git 會說:我想要提交F ,他們將其添加到要發送的提交列表中。 然后他們會提供提交E一個 Git必須提供每個提交的父母——你的 Git 要么說不,我已經有了,要么(在這種情況下,他們會提供BE的父母,等等在)。

然后,他們的 fetch 過程將獲得這些提交所需的任何內容捆綁到您的 Git 中——這是您將看到counting objectscompressing objects ——並將其發送過去。 您的 Git 擴展了這些,以便您擁有一組正確的提交及其數據,然后根據存儲在master的哈希 ID 創建或更新您的origin/master master :現在您肯定有提交F ,您的 Git 可以創建您的origin/master指向它。

因此,如果您運行:

git fetch origin

在任何時候——這是命令的“讓我得到一切”形式——你的 Git 將調用他們的 Git 並獲得初步的“一切”列表。 這兩個 Git 會從那里找出您的 Git 需要獲得什么,並將其提供給您的 Git。 然后,您的 Git 將根據所有分支名稱創建或更新所有遠程跟蹤名稱。

當您使用git push ,這與 Git 與fetch的對立面非常接近——由於歷史錯誤2,這對是pushfetch而不是pushpull —— 會發生類似的過程,但有兩個關鍵區別:

  • 你的 Git 發送,而不是接收。 (您的 Git 仍然選擇要發送的內容,並且“如果發送提交則必須提供父項”仍然有效,依此類推,但使用git fetch ,他們的 Git 已發送,而您的 Git 已收到。)

  • 最后,不是某些 Git 更新某種“遠程跟蹤名稱”,而是您的 Git 要求(禮貌地)或命令(強制地)他們的 Git 來設置它的一些分支名稱。 3

如果您要求或命令他們設置他們的master ,並且他們服從,您的 Git 現在知道他們的master設置為您提供的哈希 ID,因此您的 Git 現在更新您的origin/master遠程跟蹤名稱。

當您使用溫和的、詢問類型的git push origin master ,您的 Git 會發送您擁有但他們沒有的提交——例如CD然后禮貌地詢問他們:請,如果可以,請將您的master設置為指向提交D ? 他們會說不 如果我這樣做,我會忘記提交F 這個錯誤隨着 Git 行話的拒絕non-fast-forward再次出現,但這只是意味着他們說不,因為這會丟失提交F ,因此也會丟失E

但這正是您希望他們做的。 所以你只需要給他們一個強有力的命令:設置你的master 他們仍然可以拒絕——例如,如果你沒有許可——但是你當然有許可,所以在這種情況下他們會服從,並失去提交F

git push有兩種強制模式: git push --force是古老的版本, git push --force-with-lease是更現代的(自 Git 1.9 左右以來)變體。 它們之間的區別在於--force只是說set ,但--force-with-lease說:我認為你的master是 _____。 如果是這樣,請將其設置為 _____ 並讓我知道您這樣做了; 如果沒有,告訴我我錯了,畢竟不要設置你的master 第一個空白填充了您的 Git 的origin/master值:您的 Git 對其 Git 的master的記憶。 因此,這使您能夠確保您讓他們扔掉的正是您認為他們會扔掉的東西。

如果您是另一個 Git 的唯一用戶,則無需關心--force-with-lease添加的內容:您認為正確的,根據定義就是正確的。 但是如果您擔心自己可能會健忘(例如,如果您使用兩台不同的筆記本電腦並且不記得哪台是最新的),您可以使用更高級的 check-first-then-force --force-with-lease 使用--force-with-lease永遠不會錯,除了舊的--force是歷史默認值這一事實之外, --force-with-lease確實應該是默認值。


1 Git 稱這些遠程跟蹤分支名稱,但幾年前我決定這里的分支這個詞是無用的混亂,會造成一些額外的混亂,所以我現在只稱它們為遠程跟蹤名稱

2通常,在獲取提交后,您希望集成這些提交。 這就是git pull所做的:它運行git fetch獲取提交,然后運行第二個 Git 命令來集成這些提交。 這在早期似乎是正確的自然粒度,因此git pull是面向用戶的命令,與git push相反。

然而,事實證明,將提取操作與集成操作分開通常很重要,例如,在兩者之間插入某種檢查操作,以便選擇正確的集成形式 Mercurial 做對了,而 Git 做錯了:在 Mercurial 中, hg pull表示 Git 對git fetch含義,您必須向hg pull添加一個單獨的操作或一個額外的標志,以使其也執行集成步驟。

3你可以選擇你要求他們設置的名字,這樣你就可以設置你的 Git 詢問或命令標簽名稱,或者其他一些名稱,但一般來說,這里的通常情況是“分支名稱”。

暫無
暫無

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

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