组合多个git存储库

Wil*_*son 203 git

假设我的设置看起来很像

phd/code/
phd/figures/
phd/thesis/
Run Code Online (Sandbox Code Playgroud)

由于历史原因,这些都有自己的git存储库.但我想将它们合并为一个,以简化一些事情.例如,现在我可能会进行两组更改,并且必须执行类似的操作

cd phd/code
git commit 
cd ../figures
git commit
Run Code Online (Sandbox Code Playgroud)

表演(现在)很棒

cd phd
git commit
Run Code Online (Sandbox Code Playgroud)

似乎有几种方法可以使用子模块或从我的子存储库中提取,但这比我正在寻找的要复杂一些.至少,我很高兴

cd phd
git init
git add [[everything that's already in my other repositories]]
Run Code Online (Sandbox Code Playgroud)

但这似乎不是一个单行.有什么git可以帮助我吗?

Min*_*ark 143

这是我在这里给出的解决方案:

  1. 首先对您的phd目录进行完整备份:我不想为您失去多年的辛勤工作负责!;-)

    $ cp -r phd phd-backup
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将内容移动phd/codephd/code/code,并修复历史记录,使其看起来一直存在(这使用git的filter-branch命令):

    $ cd phd/code
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s#\t#&code/#" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    
    Run Code Online (Sandbox Code Playgroud)
  3. 对于相同的内容phd/figuresphd/thesis(只需更换codefiguresthesis).

    现在您的目录结构应如下所示:

    phd
      |_code
      |    |_.git
      |    |_code
      |         |_(your code...)
      |_figures
      |    |_.git
      |    |_figures
      |         |_(your figures...)
      |_thesis
           |_.git
           |_thesis
                |_(your thesis...)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 然后在根目录中创建一个git存储库,将所有内容放入其中并删除旧存储库:

    $ cd phd
    $ git init
    
    $ git pull code
    $ rm -rf code/code
    $ rm -rf code/.git
    
    $ git pull figures --allow-unrelated-histories
    $ rm -rf figures/figures
    $ rm -rf figures/.git
    
    $ git pull thesis --allow-unrelated-histories
    $ rm -rf thesis/thesis
    $ rm -rf thesis/.git
    
    Run Code Online (Sandbox Code Playgroud)

    最后,你现在应该拥有你想要的东西:

    phd
      |_.git
      |_code
      |    |_(your code...)
      |_figures
      |    |_(your figures...)
      |_thesis
           |_(your thesis...)
    
    Run Code Online (Sandbox Code Playgroud)

这个过程的一个好处是它将保留非版本化的文件和目录.

希望这可以帮助.


只是一个字的警告不过的:如果你的code目录已经有一个code子目录或文件,事情可能会去非常错误的(同为figuresthesis的课程).如果是这种情况,只需在完成整个过程之前重命名该目录或文件:

$ cd phd/code
$ git mv code code-repository-migration
$ git commit -m "preparing the code directory for migration"
Run Code Online (Sandbox Code Playgroud)

当程序完成后,添加最后一步:

$ cd phd
$ git mv code/code-repository-migration code/code
$ git commit -m "final step for code directory migration"
Run Code Online (Sandbox Code Playgroud)

当然,如果code子目录或文件没有版本化,只需使用mv而不是git mv,并忘记git commits.

  • 感谢这个片段 - 它完全符合我的需要(一旦我考虑到Mac OS X sed没有处理"\ t"(我不得不使用^ V ^ I代替). (13认同)
  • 我一开始无法工作,最终在另一个旧留言板上找到问题的解决方案.在最后一行,我不得不在文件名周围加上引号:`mv"$ GIT_INDEX_FILE.new""$ GIT_INDEX_FILE"'HEAD`然后效果很好! (6认同)
  • 小心!MacOS X不使用sed的GNU扩展,因此它不知道序列\ t.结果是混乱的历史!我的解决方案是将代码粘贴到脚本文件中,在其中写入一个真正的<TAB>字符.在终端中,可以按ctrl + v输入一个选项卡,然后写入<TAB>.我没有尝试过克雷格的解决方案 (5认同)
  • 看完了(2)!另请注意,如果某些文件或目录包含连字符(' - '),则sed命令将失败.在这种情况下,你可以用's~\t~&code /〜'之类的东西替换它.在这里,应用相同的逻辑,注意名称中的"〜" (4认同)
  • funky filter-branch命令来自git的filter-branch手册页.你应该说:a)它应该被正确归因b)我不会仅仅因为有人,即使声誉很高,也把它​​发布在StackOverflow上.知道它来自手册我会. (2认同)
  • @CraigTrader考虑安装`gnu-sed`(例如使用`brew`).它平滑了不兼容性:) (2认同)
  • 卡在步骤 2 中,如何将文件移动到子目录中?mv 还是 git mv?我应该在之后提交更改吗,因为我无法拉动它,因为它说分支有未提交的更改。 (2认同)

Ari*_*zis 76

git-stitch-repo将处理git-fast-export --all --date-order命令行上给出的git存储库的输出,并创建一个适合于此的流git-fast-import将创建一个新的存储库,其中包含一个新的提交树中的所有提交,该提交树尊重所有源存储库的历史记录.

  • 呃,这是第三方工具,不是git的一部分... :-) (32认同)
  • 这是一个外部脚本,答案太短,并没有真正帮助,这个脚本有合并提交的问题,没有多少人会处理Perl或CPAN,这在答案中没有得到很好的解释.所以... -1,抱歉. (5认同)
  • 2018 年更新:`git-stitch-repo` 现在可以很好地处理分支和合并。要在 Mac 上安装它,请执行“sudo cpan install Git::FastExport”,如果可执行文件不在您的路径中,请尝试在“/usr/local/bin/git-stitch-repo”中查找它 (2认同)

imz*_*hev 20

也许,简单地(类似于之前的答案,但使用更简单的命令)在每个单独的旧存储库中进行提交,将内容移动到适当命名的子目录中,例如:

$ cd phd/code
$ mkdir code
# This won't work literally, because * would also match the new code/ subdir, but you understand what I mean:
$ git mv * code/
$ git commit -m "preparing the code directory for migration"
Run Code Online (Sandbox Code Playgroud)

然后将三个单独的回购合并为一个新的,通过做smth像:

$ cd ../..
$ mkdir phd.all
$ cd phd.all
$ git init
$ git pull ../phd/code
...
Run Code Online (Sandbox Code Playgroud)

然后你将保存你的历史,但将继续一个回购.


Lei*_*ldt 19

您可以尝试子树合并策略.它会让你将repo B合并到repo A中.优点git-filter-branch是它不需要你重写你的历史记录(打破SHA1总和).

  • @Tymek(对不起安全漏洞后,kernel.org的部分内容仍然失效).它打破了传入的回购B的SHA1.但A保持不变. (3认同)
  • 以下是该文档的镜像http://ftp.sunet.se/pub/Linux/kernel.org/software/scm/git/docs/howto/using-merge-subtree.html (2认同)

Gar*_*eth 7

git-filter-branch解决方案运行良好,但请注意,如果您的git repo来自SVN导入,它可能会失败并显示如下消息:

Rewrite 422a38a0e9d2c61098b98e6c56213ac83b7bacc2 (1/42)mv: cannot stat `/home/.../wikis/nodows/.git-rewrite/t/../index.new': No such file or directory
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您需要从filter-branch中排除初始修订版 - HEAD即将结尾处更改为[SHA of 2nd revision]..HEAD- 请参阅:

http://www.git.code-experiments.com/blog/2010/03/merging-git-repositories.html

  • 谢谢!我一直在摸不着为什么这不起作用!回购确实来自SVN. (2认同)

Mic*_*chK 5

@MiniQuark解决方案帮助了我很多,但不幸的是它没有考虑源代码库中的标签(至少在我的情况下).以下是我对@MiniQuark答案的改进.

  1. 首先创建包含组合repo和merged repos的目录,为每个合并的目录创建目录.

    $ mkdir new_phd
    $ mkdir new_phd/code
    $ mkdir new_phd/figures
    $ mkdir new_phd/thesis

  2. 拉动每个存储库并获取所有标记.(仅针对code子目录提供说明)

    $ cd new_phd/code
    $ git init
    $ git pull ../../original_phd/code master
    $ git fetch ../../original_phd/code refs/tags/*:refs/tags/*

  3. (这是改进点2 MiniQuark答案)移动的内容new_phd/codenew_phd/code/code,并添加code_每个前prefeix 标签

    $ git filter-branch --index-filter'git ls-files -s | sed"s-\t \"* - &code/ - "| GIT_INDEX_FILE = $ GIT_INDEX_FILE.new git update-index --index-info && mv $ GIT_INDEX_FILE.new $ GIT_INDEX_FILE'--tag-name-filter'sed"s - .* - 代码_& - "'HEAD

  4. 这样做之后,标签的数量将是过滤分支之前的两倍.旧标签保留在repo中,并code_添加带前缀的新标签.

    $ git tag
    mytag1
    code_mytag1

    手动删除旧标签:

    $ ls .git/refs/tags/*| grep -v"/ code_"| xargs rm

    对其他子目录重复2,3,4点

  5. 现在我们有@MiniQuark anwser point 3中的目录结构.

  6. 如同MiniQuark anwser的第4点那样,但是在执行拉动之后和删除.git目录之前,请获取标记:

    $ git fetch catalog refs/tags/*:refs/tags/*

    继续..

这只是另一种解决方案.希望它对某人有所帮助,它帮助了我:)


rob*_*nst 5

来自亚里士多德Pagaltzis的 git-stitch-repo 回答仅适用于具有简单线性历史的存储库.

MiniQuark的答案适用于所有存储库,但它不处理标记和分支.

我创建了一个程序,其工作方式与MiniQuark描述的相同,但它使用一个合并提交(具有N个父项),并且还重新创建所有标记和分支以指向这些合并提交.

有关如何使用它的示例,请参阅git-merge-repos存储库.


Pat*_*k_O 2

您建议的顺序

git init
git add *
git commit -a -m "import everything"
Run Code Online (Sandbox Code Playgroud)

会起作用,但你将失去你的提交历史记录。