簡體   English   中英

將根提交父級更改為指向另一個提交(連接兩個獨立的git存儲庫)

[英]Change the root commit parent to point to another commit (connecting two independent git repositories)

我在svn信息庫中有一個擁有3年以上歷史的項目。 它已遷移到git,但是執行此操作的人只是選擇了最新版本並扔掉了這3年的全部歷史。

現在,該項目在一個存儲庫中具有最近3-4個月的歷史記錄,而我將其他3年的svn歷史記錄導入了新的git存儲庫中。

有什么方法可以將第二個存儲庫的根提交連接到第一個存儲庫的最后一個提交中?

它是這樣的:

  *   2017-04-21 - last commit on master
  |   
  *   2017-03-20 - merge branch Y into master
  |\  
  | * 2017-03-19 - commit on branch Y
  | | 
  * | 2017-03-18 - merge branch X into master
 /| * 2017-02-17 - commit on another new branch Y
* |/  2017-02-16 - commit on branch X
| *   2017-02-15 - commit on master branch
* |   2017-01-14 - commit on new branch X
 \|   
  *   2017-01-13 - first commit on new repository
  |   
  *   2017-01-12 - init new git project with the last version of the code in svn repository
  .   
  .   
There is no relationship between the two different repositories yet, this is what I wanna
do. I want to connect the root commit of 2nd repository with the last commit of the first
one.
  .
  .   
  *   2017-01-09 - commit
  |   
  *   2017-01-08 - commit
  |   
  *   2017-01-07 - merge
 /|   
* |   2016-01-06 - 2nd commit the other branch
| *   2016-01-05 - commit on trunk
* |   2016-01-04 - commit on new branch
 \|   
  *   2015-01-03 - first commit
  |   
  *   2015-01-02 - beggining of the project

更新:

我只是知道我需要做一個git rebase ,但是如何? 請讓我們考慮一下提交日期,就像SHA-1代碼一樣。答案是使用git filter-branch--parent-filter選項,而不是git rebase

更新2:

我嘗試了命令git filter-branch --parent-filter 'test $GIT_COMMIT = 443aec8880e898710796a1c4fb4decea1ca5ff66 && echo "-p 98e2b95e07b84ad1e40c3231e66840ea910e9d66" || cat' HEAD git filter-branch --parent-filter 'test $GIT_COMMIT = 443aec8880e898710796a1c4fb4decea1ca5ff66 && echo "-p 98e2b95e07b84ad1e40c3231e66840ea910e9d66" || cat' HEAD ,它不起作用:

PS D:\git\rebase-test\rep2cc> git filter-branch --parent-filter 'test $GIT_COMMIT = 443aec8880e898710796a1c4fb4decea1ca5ff66 && echo "-p 98e2b95e07b84ad1e40c3231e66840ea910e9d66" || cat' HEAD
fatal: ambiguous argument '98e2b95e07b84ad1e40c3231e66840ea910e9d66 || cat': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

更新3:

它不適用於Windows CMD或PowerShell,但適用於Windows上的Git Bash。

首先,您需要一個具有所有可用歷史記錄的倉庫。

克隆最近回購歷史記錄的回購。 將具有舊歷史記錄的倉庫添加為遠程倉庫。 我建議將此克隆作為“鏡像”,並通過用此克隆替換原始回購來完成。 但是,您也可以關閉--mirror ,然后通過將所有引用推回原點來完成(可能根據所使用的方法強制推動)。

git clone --mirror url/of/current/repo
cd repo
git remote add history url/of/historical/repo
git fetch history

您需要做的下一件事是弄清楚將在哪里拼接歷史記錄。 我認為描述此術語的措辭有點模糊...您想要的是找到與兩個歷史都有提交的最新SVN版本相對應的兩個提交。 例如,您的SVN存儲庫包含版本1、2、3和4。現在您有了

Recent-History Repo

C --- D --- E --- F <--(master)

Old-History Repo

A --- B --- C' --- D'

其中A表示版本1, B表示第2版, CC'代表版本3,以及DD'表示版本4. EF是原始遷移之后創建的工作。 因此,您想將其父級為D (在此示例中為E )的提交拼接到D'

現在,我可以想到兩種方法,每種方法各有利弊。

改寫最近的歷史

如果您可以協調所有開發人員過渡到新的回購協議,則 IMO是最好的方法(這意味着您安排一個時間,讓他們都同意推送所有出色的工作,因此他們會丟棄其克隆;然后您進行轉換;然后他們全部重新克隆)是(有效地)將最近的歷史重新建立到舊的歷史上。

如果確實只有一個分支,則可以使用rebase

git rebase --onto D' D master

(其中DD'替換為提交的SHA ID)。

您更可能在最近的歷史中有一些分支和合並; 在這種情況下,變基操作將很快開始成為問題。 另一方面,您可以利用D具有與D'相同的樹的事實-因此,重定基數和重定父級或多或少是等效的。

因此,您可以將git filter-branch--parent-filter一起使用進行重寫。 根據https://git-scm.com/docs/git-filter-branch上文檔中的示例,您將執行以下操作

git filter-branch --parent-filter 'test $GIT_COMMIT = D && echo "-p D'" || cat' HEAD

(其中DD'再次被提交的SHA ID取代)。

這將創建您需要清理的“備份”引用。 最后你會得到

A --- B --- C' --- D' --- E' --- F' <--(master)

事實是FF'取代了,這就需要硬轉換(或多或少)。

現在,如果您在第1步進行了鏡像克隆,則可以考慮清除reflog,刪除遠程服務器並運行gc ,然后這是一個新的隨時可用的原始存儲庫。

如果您進行了常規克隆,則需要push -f所有引用都push -f到原點,這很可能在原點回購中留下一些混亂。

使用“替換提交”

另一個選項不會造成硬性轉換,但會給您帶來很多麻煩,需要您永遠解決。 您可以使用git replace 在您的組合回購中

git replace `D` `D'`

默認情況下,當生成日志輸出或其他內容時,如果git找到D ,它將在輸出中替換D' (及其歷史記錄)。

有一些已知的故障。 可能存在未知的故障。 默認情況下,不會共享使所有這些工作都起作用的“替換引用”,因此您必須有意識地推送和獲取它們。

暫無
暫無

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

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