合并两个git存储库以获取线性历史记录

时间:2013-06-06 21:44:02

标签: git merge

我有两个git存储库,它们之间有很多未跟踪的更改:

   ftp -->            C-- (untracked changes) --D
                     /                           \
   git        A--B--C <-- old/master              \
                                                   \
                                                    \
                                  new/master -->     D--E--F 

如何将旧存储库合并到新存储库中以获得线性历史记录,如

A--B--C--D--E--F

修改

受到How can I combine Git repositories into a linear history?

的启发

我做完了:

git clone url://new new
cd new/
git remote add old url://old
git fetch old
git reset --hard origin/master
git filter-branch --parent-filter 'sed "s_^\$_-p old/master_"' HEAD
git push origin master

唯一的问题是来自new / master的每次提交都加倍了(由于我认为父改变)所以我现在(M是合并提交)

         D---E---F--         
                    \
A--B--C--D'--E'--F'--M 

如何轻松删除不必要的提交(D-F和M)?

4 个答案:

答案 0 :(得分:4)

检查你的分支并运行:

  git reset --hard **SHA-OF-F'**

这将从您的分支中移除MD - F

答案 1 :(得分:3)

修复git filter-branch

的结果

如果您的存储库看起来像这样:

         D---E---F--
                    \
A--B--C--D'--E'--F'--M <-master

并且您希望结果如下所示:

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

然后您可以简单地强制master指向F'

git checkout master
git reset --hard <sha1-of-F'>

这会导致提交DEFM无法访问,有效删除它们(一段时间后它们将被垃圾收集)。< / p>

从头开始

假设您有两个看起来像这样的存储库:

  • old:A--B--C <-master
  • new:D--E--F <-master

你想要的结果是:

  • 合并:A--B--C--D'--E'--F' <- master

然后您可以执行以下步骤:

  1. 初始化combined存储库:

    git init combined
    cd combined
    git remote add old url:/to/old
    git remote add new url:/to/new
    git remote update
    

    此时您的combined存储库看起来像:

    A--B--C <-old/master
    
    D--E--F <-new/master
    

    请注意,这两个分支没有任何连接。

  2. master分支设置为指向C

    git reset --hard old/master
    

    现在您的存储库看起来像这样:

          old/master
          |
          v
    A--B--C <-master
    
    D--E--F <-new/master
    
  3. 找到D的sha1:

    d=$(git rev-list --reverse new/master | head -n 1)
    
  4. 通过阅读提交内容

    D导入您的工作目录和索引
    git read-tree -u --reset $d
    
  5. 使用与原始D提交相同的提交消息,作者,日期等提交D的内容:

    git commit -C $d
    

    现在您的存储库看起来像这样:

          old/master
          |
          v
    A--B--C--D' <-master
    
    D--E--F <-new/master
    
  6. 樱桃挑选剩下的提交:

    git cherry-pick $d..new/master
    

    现在您的存储库看起来像这样:

          old/master
          |
          v
    A--B--C--D'--E'--F' <-master
    
    D--E--F <-new/master
    
  7. 清理:

    git remote rm old
    git remote rm new
    

    现在您的存储库看起来像这样:

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

答案 2 :(得分:1)

如果ftp不是正确的分支而只是复制粘贴作业, this can work 为你

cd git
git rm -r .
cp -r ../ftp/. .
git add
git commit

答案 3 :(得分:0)

嗯,我不确定究竟是什么问题。但我要做的是删除一个包含副本的分支。这些提交不是必需的,并且可能会在删除分支时消失。如果它们在同一棵树中加倍,您可以自担风险使用git rebase

做类似

的事情
git rebase -i HEAD~5

将使用您可以执行的操作打开编辑器。如果删除带有提交的行,它将从树中删除它,您可以将提交压缩等。如果保存空文件,它将不会执行任何操作。

也就是说,请记住,在执行此类rebase后,主分支将不会快进,您必须覆盖服务器上的主分支。通过强制推动。换句话说,确保rebase正确,并且在推送新分支后,每个人都将在此分支上同步。如果有人有一个主人,并试图推动它失败,它可能会使事情变得更糟。

Git rebase就像重放提交历史一样。删除提交更像是跳过更改。如果你跳过一个加倍的提交,那么它将没有任何效果。但是每个提交都会有一个不同的shasum,这也意味着分支将与原始master分开。

在任何情况下,在执行任何操作之前保存master的sha1然后如果出现问题,只要没有垃圾收集,你总是可以检查master到commit。

删除其他分支将是最明智的想法,并且来自此主人的每个分支都将防止双打。除非你真的需要,否则应该避免重新定位。