簡體   English   中英

復制git存儲庫后,如何找回共享歷史記錄?

[英]How do I get shared history back after a git repository has been copied?

很久以前,在遠方的辦公室中,有人復制了一個github存儲庫,並將其上載到Visual Studio Team Services(VSTS)。 我們開發人員愉快地進行了編碼,開發了功能並修復了VSTS中的錯誤。 現在是時候將我們的代碼重新發布到開源社區的摯愛之中了……

不幸的是,我們的VSTS存儲庫與github存儲庫沒有共享歷史記錄,因為它是副本,而不是克隆。 雖然我們可以將github存儲庫添加為遠程存儲庫,但是將我們的代碼合並回主要分支中卻是令人討厭的沖突。 整個文件夾結構已被移動或重命名,並且開源開發人員已對github存儲庫中的這些文件進行了更改。

有什么辦法可以使分支機構回到原來的位置嗎? 像將整個分支樹重新建立到復制存儲庫時github上的最后一次提交一樣嗎?

我想出的最好的辦法是將VSTS中的每個CL都挑選到github上,這聽起來像是一些認真的偵探工作,弄清楚了在哪里插入重命名。

通常,將非克隆與實際克隆相結合是很困難的。

讓我們用git://github.com/repo作為原始示例來寫一個理論示例。 假設ssh://example.com/copy.git將代表您使用以下命令序列設置的存儲庫:

<download tarball or zip file from github.com/repo>
<extract tarball or zip file into directory D>
$ cd D
$ git init
$ git add .
$ git commit -m initial -m "" -m "imported from github.com/repo.git"

之后,您從該獨立存儲庫創建了--bare存儲庫,該存儲庫位於ssh://example.com/repo.git

現在已經過了一段時間,您已經意識到您想使用github.com/repo.git的實際克隆。 las,您的ssh://example.com/repo.gitgit://github.com/repo.git沒有共享歷史,也沒有共同的提交。 運行:

$ git clone ssh://example.com/repo.git combine
$ cd combine
$ git remote add public git://github.com/repo.git
$ git fetch public

獲取所有公共提交,但是嘗試將public/master與您自己的私有master合並是一團糟。

在某些非常特定的情況下,解決這個問題實際上並不難。 訣竅在於將現在位於您的combine存儲庫中的根提交 (可以從master訪問)與可以從所有public/*遠程跟蹤名稱訪問的combine存儲庫中的所有提交進行比較。 如果你是幸運的,正好一次提交的tree完全匹配自己的根犯的tree ,因為壓縮包,或-zip文件你有生產相同的樹。

如果您走運,則不會進行此類提交。 在這種情況下,您也許可以找到“足夠接近”的提交。 但是,假設您確實找到了可從public/master到達的提交,該提交與您自己的根提交完全匹配:

A--B--...--o--o   <-- master (HEAD), origin/master
        \
         ... (there may be other branches)

C--...--R--...--o   <-- public/master

在這里,大寫字母A代表您自己的根提交(從下載的tarball或zip文件中生成的根提交)的實際哈希ID,而B是緊隨其后的提交。 C代表可從public/master獲得的(或某些)根落實,並且主要在圖中只是為了說明:我們可以確定的是,至少還有一個這樣的根(無父母)落實。 字母R代表與您的提交A完全匹配的提交 ,這是當前最有趣的提交。

我們現在想做的是, 假設 第二個最有趣的提交B的父B是提交R而不是提交A 我們做得到! Git有一個叫做git replace git replace所做的是在進行一些更改的同時復制對象。 在我們的例子中,我們想要的是將提交B復制到看起來幾乎像B新提交B' ,但又發生了一件改變:它的父級。 而不是將提交A的哈希ID列為B'的父級,我們希望B'列出提交R的哈希ID。

換句話說,我們將擁有:

A---------B--...--o--o   <-- master (HEAD), origin/master

          B'
         /
C--...--R--...--o   <-- public/master

現在我們要做的就是說服Git,當它查找提交B ,它應該注意到存在該替換提交B' ,並迅速將視線從B轉移到B' 這就是git replace的其余工作。 因此,找到提交RB ,我們運行:

git replace --graft <hash-of-B> <hash-of-R>

現在,Git 假裝該圖顯示為:

          B'-...--o--o   <-- master (HEAD), origin/master
         /
C--...--R--...--o   <-- public/master

(好吧,除非我們運行git --no-replace-objects來查看實際情況,否則Git會假裝這樣做)。

大的或也許小的缺點

除了定位提交R工作相當艱巨之外-查找AB非常容易,它們是git rev-list --topo-order master列出的最后兩個哈希ID,此git replace技巧有一個缺陷。 更換犯B'在我們的資料庫中存在了,但它是通過一個特別的名稱的位置refs/replace/ hash ,其中hash是原來提交的哈希ID B 默認情況下,此替換對象(及其名稱) 不會發送到新的克隆

您可以創建確實具有替換對象及其名稱的克隆,並使用它們,然后一切正常。 但這意味着每次有人克隆您的combine存儲庫時,他們都必須運行:

git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'

或類似的(這個特殊的規則只是奴你克隆的refs/replace/命名空間origin的,這是原油,但有效)。

另外,您可以聲明一個賣旗日並運行git filter-branch或類似的方法以將替換固定在適當的位置。 我已經在其他地方描述了這一點,盡管目前我能找到的最好的答案是我如何將一個孤立的分支附加到“按原樣”掌握? 本質上,您將創建一個存儲庫,該存儲庫具有B'而不是B ,不具有A ,並且具有作為B'的后代的每個提交的新副本(除了父哈希ID之外,其他內容都相同)。 然后,您將所有用戶從舊的repo.git切換到新的。 這很痛苦,但是只有一次。

如果您不打算長時間使用組合存儲庫,則可能沒有關系。

除上述內容外,您還可以使用嫁接的歷史記錄來產生合並(一般而言,Git命令將在替換之后進行),之后您可能不需要替換嫁接提交。 在這種情況下,缺點是短暫的:它僅持續到合並代碼為止。

假設VSTS倉庫是Git倉庫,您可以:

  • 克隆您的GitHub存儲庫
  • 通過正確的提交創建一個新分支
  • 使用VSTS分支的第一次提交的鏡像副本覆蓋工作樹內容(以避免任何沖突解決)。 然后添加並提交。
  • VSTS的git cherry-pick(作為遠程添加並獲取),將VSTS master分支的所有提交轉移到新的本地分支(無沖突)
  • 將新分支推回GitHub存儲庫

暫無
暫無

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

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