2017-05-19 72 views
0

我有一个在svn存储库中有超过3年历史的项目。它被迁移到git,但是做这个的人,只是拿最后一个版本,抛弃所有这3年的历史。更改根提交父指向另一个提交(连接两个独立的git存储库)

现在项目在一个存储库中有最近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并没有奏效:

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,但它确实在Git Bash上运行。

+2

那么,你有没有考虑过在同一个存储库中取得这两个数据,然后在另一个数据库上重新规划一个历史?这当然会重写所有提交历史的提交。 –

+1

Lasse说得对。只要建立一个新的回购与svn克隆正确,添加一个远程这个捣毁回购,获取和樱桃选择正确克隆svn回购史上克隆从svn后完成的git。 – eftshift0

+0

我是新的git,我刚刚得知我正在寻找的魔术字是'rebase' – lmcarreiro

回答

2

首先要做的事情是:您需要一个具有所有可用历史记录的回购单。

用最近的历史制作回购克隆。将旧历史记录添加为远程回购。我建议这个克隆是一个“镜像”,你用这个替换你的原始回购。但是,您也可以将--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的最佳方式如果你能协调各开发商切到一个新的回购(意思是你安排的时候,他们都同意,所有未完成的工作所以他们放弃他们的克隆;然后你做了转换;然后他们都重新克隆)是(有效地)将最近的历史重新放到旧的历史上。

如果真的只是一个分支,那么你可以从字面上使用衍合

git rebase --onto D' D master 

(其中DD'与提交的SHA ID替换)。

更有可能你有一些分支机构,并在最近的历史合并;在这种情况下,重组操作将很快开始成为问题。另一方面,您可以利用DD'具有相同的树的事实 - 因此rebase和re-parent或多或少是等价的。

因此,您可以使用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) 

这是一个事实,即F是由F'它创造了一个硬割接(或多或少)需要更换。

现在,如果您在第1步创建了镜像克隆,则可以考虑擦除引用日志,放弃远程设备并运行gc,然后这是一个新的即用型源代码回购。

如果你制作了一个常规克隆,那么你需要push -f所有的参考来源,这可能会在原点回购中留下一些混乱。

使用“替代提交”

其他选项不创建一个硬割接,但它留给你的小麻烦来处理,直到永远。您可以使用git replace。在您的合并回购

git replace `D` `D'` 

默认状态下,产生的日志输出或任何时候,如果发现的git D,它会在输出替代D'(和它的历史)。

有一些已知的故障。可能有未知的故障。默认情况下,使这一切工作的“替代参考”不共享,所以你必须有意识地推送和获取它们。

+0

我试过git替换,它不是我想要的。而且我的历史上有很多分支机构和合并,所以,转换操作确实成了一个问题,就像你说的。 – lmcarreiro

+0

第三种选择,我不明白......什么是“P”和“P”?并且命令'git filter-branch --parent-filter'test $ GIT_COMMIT = D && echo“-p D'”||猫'头'会在Windows上工作吗? – lmcarreiro

+0

对不起,“P”和“P”应该和其他地方一样是“D”和“D”我已更新。该命令将在'git bash'外壳的窗口中工作;只记得用适当的提交引用(例如SHA ID)替换'D'和'D'' –

相关问题