如何告诉Git两个提交在不相交的历史中实际上是相同的?

时间:2016-09-30 16:55:32

标签: git version-control git-svn

我有一个Git repo,它是来自另一个Git repo的克隆,它是来自巨型SVN repo的克隆。我们可以从SVN更新其他Git repo并从中提交给SVN,但是与另一个用户一起提交。

我想用我自己的用户直接将我的本地提交发布到SVN repo。

这就是我尝试过的:我手动创建了git-svn分支,将其添加到.git/config

[branch "master"]
[svn-remote "svn"]
        url = https://url/to/svn/trunk/repo_name
        fetch = :refs/remotes/git-svn

然后git svn fetch,下载了32k提交。

但我最终得到了两个不相关的历史:

  1. 一个来自Git:
    1. 从提交674c35a开始,表示原始克隆点处SVN仓库的状态。
    2. 分支master始终与SVN同步(通过其他Git仓库)。
    3. 分支dev有我们目前的发展,应该合并到master(通常被压扁),然后提交回SVN回购。
  2. 一个用于SVN回购:
    1. 从正确的初始提交开始。
    2. 它有30k +提交。
    3. Git最初从SVN [fb1b9c7]克隆的提交(但只有前一次提交的diff,而不是整个repo作为开始提交)。
    4. 然后,git/origin/master应该是共同的提交(100+)。
  3. 如何告诉Git启动提交(674c35a)实际上与SVN提交(fb1b9c7)相同?那么Git可以以某种方式理解克隆之后master中的提交实际上与git-svn相同吗?

    我已尝试使用--onto进行变基,正如here所解释的那样,但这并不是我想要的(提交不在分支的顶部)。

3 个答案:

答案 0 :(得分:1)

我相信我的博客文章Grafting History with Git中有一个适用于此的方法,为了遵守网站规则,我将在此总结:

现状:

  • 两个git repos,有不同的历史,但有一个来源

目标状态:

  • 一个git仓库,有两个分支代表那些不同的历史
  • 将这两个历史转换为Git分支(我认为你已经有了这个)
  • 通过比较日志和查看哈希更改的时间来找出分歧点
    • 使用git log --reverse --format="%T %H"获取每个分支上的tree-id和commit-id列表,并将其保存到文件
    • 比较列表以查看树形哈希发散的位置(我使用可以做列的diff程序,你可以只使用awk和diff)
  • 查看目标回购分支上的分歧点并制作新分支
  • 从源获取所有对象到目标
  • 对于原始源中的每个修订,请在目标上创建一个新修订
    • 使用git read-tree -um $TREEID
    • 结帐外国版本的树
    • 使用git commit --reuse-message $ORIGINAL_COMMIT
    • 使用原始提交消息

或者......将您的tree-id + commit-id列表添加到此脚本中。

#!/bin/bash
# graft script
while read TREE COMMIT
do
 git read-tree -um $TREE
 git commit --reuse-message $COMMIT
done

答案 1 :(得分:0)

你的历史可能看起来像这样:

*--*--*--fb1b9c7--*--*--* [git-svn] (version of master from SVN)

         674c35a--*--*--* [master] (version of master from Git)
                         \
                          *--*--*--* [dev]

看起来您有两个问题:您的Git历史记录不包含完整SVN历史记录中的30k +提交,dev基于(不完整的)Git历史记录而不是SVN版本。

fb1b9c7 == 674c35a以来,您应该可以:

git rebase --onto git-svn master dev

我的实验表明git rebase并不关心目标分支(git-svn)与基本分支(master)的历史记录不同。 SVN只存储差异也无关紧要,因为git-svn会在获取过程中将这些差异转换为真正的Git提交。

由于历史记录包含相同的内容,您甚至可以这样做:

git checkout dev
git rebase git-svn

之后,您可以删除master并让该树稍后进行垃圾回收。 (如果您仍需要单独的master分支,请在删除原始git checkout -b master git-svn后执行master

当你说:

  

(提交不在分支的顶部)

我假设您指的是提交fb1b9c7674c35a。但是,这些提交被埋没在历史中并不重要,因为我们将选择一个(fb1b9c7)使用,并让另一个进行垃圾收集,如上所述。

答案 2 :(得分:0)

如果您想用另一个提交替换一个提交,只需使用git replace,例如git replace 674c35a fb1b9c7
如果您想要永久保留,请使用git rebase