簡體   English   中英

git merge --rebase:如何查找“以前的/以前的sha1”

[英]git merge --rebase: how to find “former/previous sha1”

想象我有分支develop和分支feature

feature有一個提交shaX

有人用--rebase合並了對feature develop ,並進行了推送,因此該要素的提交現在已經shaY ,歷史已被重寫。

目前,我只有shaY 但是我想從shaX重新創建原始feature分支。

我怎樣才能得到shaX時,我只知道shaY


我可以(如果需要)接受在進行錯誤合並的開發人員的計算機上完成的解決方案,但就我所知,並且更喜歡可以在任何計算機上(如果可能)完成的解決方案,因為該開發人員可以消失或他的機器被毀

正如Mort在評論中所說 ,您不一定必須在任何計算機上執行此操作。

確實,我們必須考慮的不是機器 ,而是存儲庫 問題變成了:哪一組存儲庫具有X ,或者有X ,我們如何找到它? 只要我們牢記一旦找到該集合,它實際上就是單個存儲庫的列表,那么我們稱之為“誰”,“什么”或“存儲庫”之類的東西並不重要。

誰有承諾?

由於Git是分布式的,因此可能有很多存儲庫副本。 每個副本都可能略有不同。 某些副本(盡管數量可以為零具有原始提交,而某些副本將沒有 您說的第一個數字可能為零的原因:

...開發人員可能會離開或他的[副本]被銷毀

如果他是唯一擁有可行副本的人,並且現在已經消失了,那么您的原始副本將減少為零,而且很不走運。 但是,由於他在自己的Git存儲庫中執行了原始操作,因此我們知道他一定在某個時候必須使用哈希X進行原始提交。 因此問題擴展到:還有誰(其他存儲庫)可能還有X? 第二,對於那些可能擁有它的人,我們如何找到它?

對第一個問題的回答始於此: 任何撿起它的人,在某個時候都有它。 如果是這樣,他們可能仍然有。 如果沒有,他們顯然沒有。

通常,大多數人選擇提交的方式是通過運行git fetch (請注意, git clone是一個包裝器,一旦創建了新的存儲庫,它將運行git fetch ,因此即使git clone也是git fetch一種情況。)當您運行git fetch ,您指示Git連接到另一個Git。 您的Git詢問另一個Git: 您擁有哪些分支和標簽名稱? 他們的Git向您發送一個列表,您的Git挑選出自己喜歡的名稱,並要求他們的Git發送任何可訪問的提交以及其他與這些名稱一起的對象,而您的Git尚不具備這些名稱。

一旦您的Git具有了這些對象,您的Git就將使用這些名稱並(通常)以某種方式對其進行更改,然后將這些名稱放入您自己的存儲庫中。 如果他們有一個名為feature的分支,則您的Git會使用其名稱feature ,並將其轉換為您自己的名稱origin/feature 然后,您的Git將您自己的參考 refs/remotes/origin/feature設置為哈希ID,以對其分支feature進行尖端提交。

(對於標記名,您自己的Git通常不會任何更改,這就是為什么標記名比分支名“更全局”的原因。)

通常,大多數運行git fetch只會帶來一個分支-例如,如果我運行git pull origin master (運行git fetch origin master ),我最終會指示Git連接到您的Git,詢問您的Git什么分支和標簽等您擁有的東西,但隨后只帶您的master ,然后我將其稱為我的origin/master -或帶走所有分支。 因此,任何運行git fetch到另一個Git並在feature名稱下具有“良好”提交的Git並帶來了feature ,都將帶來“良好提交X ”。

這為您提供了候選庫:最初誰會選擇X 任何運行git fetch (包括由git clonegit pull運行的git fetch -es,盡管后者傾向於限制獲取)的人都到具有X的存儲庫,而該存儲庫具有X。

還有另一套存儲庫需要考慮,因為還有另一種獲取提交的方式: git push可以發送提交。 git push操作類似於git fetch ,除了角色是相反的。 我沒有讓我的Git與您的Git對話,以便我的Git可以從您的Git中獲取提交,而是讓我的Git與您的Git對話,以便我的Git可以向您的Git 提供提交。 我提供了提交對象和任何其他對象,然后我發送了一個請求: 請為此哈希ID設置您的分支或標記名稱,例如refs/heads/feature 使用--force我發送命令: 將您的名稱設置為此哈希ID! 強制標志會覆蓋在接收端執行的默認“是快進”檢查(但不會在接收端強制執行任何其他檢查:仍然可以拒絕該命令)。

因此,任何通過git push獲得良好提交的人都可以擁有它。 即使隨后的強制推送重寫了會導致良好提交X的名稱,這仍然可能是正確的,但是默認情況下,由於下一節中給出的原因,事實並非如此。

如果您有X ,您還有X嗎?

現在我們已經排好所有候選存儲庫,我們需要檢查它們。 看的地方在reflogs中 引用日志是Git用於保留引用發生的歷史的內容。

上面,我們一直在使用“參考”,而沒有正確定義它。 引用只是以refs/開頭的名稱。 Git通過這些引用可以找到幾乎所有內容。 例如,分支名稱是以refs/heads/開頭的引用,標簽名稱是以refs/tags/開頭的引用。 每個引用存儲一個(單個)哈希ID。

每當您有Git 更新參考時(將當前的哈希ID替換為新的ID),您都可以選擇讓Git在日志條目中保存 值。 這些日志條目是您的引用日志。

每個引用都有一個reflog,特殊名稱HEAD也有一個reflog。 每個reflog的長度都可能是無限的(Git會在每次引用更新時添加它的長度),因此,為了避免reflog占用無限空間,Git還會為每個reflog條目分配一個時間戳 Reflog條目然后最終到期。

任何給定的reflog條目的到期時間默認為30或90天。 這部分比較棘手,我沒有時間在這里寫下,所以讓我們以30天的較短時間為准。 但是,當reflog條目處於活動狀態時,它會保留早期的哈希ID,並且通過保留它們,可以將這些對象“活動”在存儲庫數據庫中。

同時,還有其他兩個棘手的部分:

  • 默認情況下,接受git push請求的服務器將禁用 reflog。 如果他們推了一個不好的替代品,這使他們不太可能保留良好的提交X。
  • 客戶(更可能擁有X的客戶)一直在 feature 重命名origin/feature

因此,查看是否可以找到具有良好哈希值X的提交的地方是在已運行git fetch每個客戶端的reflog中 ,可能是針對origin/featurereflog中

在任何給定的Git存儲庫上查看reflog的命令是git reflog reference (這實際上運行git log -g因此受用戶配置git log選項的影響。)這是我在Git的Git存儲庫副本上的git reflog origin/mastergit reflog origin/pu的代碼段:

3dc57ebfb refs/remotes/origin/master@{2}: fetch: fast-forward

ca0964be6 refs/remotes/origin/pu@{1}: fetch: forced-update

我展示了這些內容,以說明更常規的訪3dc57ebfb新提交而不丟棄舊提交)之間的區別: origin/master@{2}指向提交3dc57ebfb ,並且當該更新發生時,這是常規樣式更新。 但是origin/pu@{1}指向ca0964be6並且當該更新發生時,它是“強制更新”。

如果有人選擇了良好的提交X ,然后feature被重新建立基礎並強制推入origin ,並且有人選擇了新的錯誤提交鏈,則他們的origin/feature將經歷強制更新。 這意味着您將在reflog中看到強制更新,這又意味着較早的引用有機會指向良好提交X或歷史導致良好提交X的提交。

無論它實際上直指XX的一些后裔是偶然的事情,你必須手動檢查這些提交給找出來。

暫無
暫無

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

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