假设我的设置看起来很像
phd/code/ phd/figures/ phd/thesis/
由于历史原因,这些都有自己的git存储库.但我想将它们合并为一个,以简化一些事情.例如,现在我可能会进行两组更改,并且必须执行类似的操作
cd phd/code git commit cd ../figures git commit
表演(现在)很棒
cd phd git commit
似乎有几种方法可以使用子模块或从我的子存储库中提取,但这比我正在寻找的要复杂一些.至少,我很高兴
cd phd git init git add [[everything that's already in my other repositories]]
但这似乎不是一个单行.有什么git
可以帮助我吗?
这是我在这里给出的解决方案:
首先对您的phd目录进行完整备份:我不想为您失去多年的辛勤工作负责!;-)
$ cp -r phd phd-backup
将内容移动phd/code
到phd/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
对于相同的内容phd/figures
和phd/thesis
(只需更换code
与figures
和thesis
).
现在您的目录结构应如下所示:
phd |_code | |_.git | |_code | |_(your code...) |_figures | |_.git | |_figures | |_(your figures...) |_thesis |_.git |_thesis |_(your thesis...)
然后在根目录中创建一个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
最后,你现在应该拥有你想要的东西:
phd |_.git |_code | |_(your code...) |_figures | |_(your figures...) |_thesis |_(your thesis...)
这个过程的一个好处是它将保留非版本化的文件和目录.
希望这可以帮助.
只是一个字的警告不过的:如果你的code
目录已经有一个code
子目录或文件,事情可能会去非常错误的(同为figures
和thesis
的课程).如果是这种情况,只需在完成整个过程之前重命名该目录或文件:
$ cd phd/code $ git mv code code-repository-migration $ git commit -m "preparing the code directory for migration"
当程序完成后,添加最后一步:
$ cd phd $ git mv code/code-repository-migration code/code $ git commit -m "final step for code directory migration"
当然,如果code
子目录或文件没有版本化,只需使用mv
而不是git mv
,并忘记git commit
s.
git-stitch-repo
将处理git-fast-export --all --date-order
命令行上给出的git存储库的输出,并创建一个适合于此的流git-fast-import
将创建一个新的存储库,其中包含一个新的提交树中的所有提交,该提交树尊重所有源存储库的历史记录.
也许,简单地(类似于之前的答案,但使用更简单的命令)在每个单独的旧存储库中进行提交,将内容移动到适当命名的子目录中,例如:
$ 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"
然后将三个单独的回购合并为一个新的,通过做smth像:
$ cd ../.. $ mkdir phd.all $ cd phd.all $ git init $ git pull ../phd/code ...
然后你将保存你的历史,但将继续一个回购.
您可以尝试子树合并策略.它会让你将repo B合并到repo A中.优点git-filter-branch
是它不需要你重写你的历史记录(打破SHA1总和).
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
在这种情况下,您需要从filter-branch中排除初始修订版 - HEAD
即将结尾处更改为[SHA of 2nd revision]..HEAD
- 请参阅:
http://www.git.code-experiments.com/blog/2010/03/merging-git-repositories.html
@MiniQuark解决方案帮助了我很多,但不幸的是它没有考虑源代码库中的标签(至少在我的情况下).以下是我对@MiniQuark答案的改进.
首先创建包含组合repo和merged repos的目录,为每个合并的目录创建目录.
$ mkdir new_phd
$ mkdir new_phd/code
$ mkdir new_phd/figures
$ mkdir new_phd/thesis
拉动每个存储库并获取所有标记.(仅针对code
子目录提供说明)
$ cd new_phd/code
$ git init
$ git pull ../../original_phd/code master
$ git fetch ../../original_phd/code refs/tags/*:refs/tags/*
(这是改进点2 MiniQuark答案)移动的内容new_phd/code
来new_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
这样做之后,标签的数量将是过滤分支之前的两倍.旧标签保留在repo中,并code_
添加带前缀的新标签.
$ git tag
mytag1
code_mytag1
手动删除旧标签:
$ ls .git/refs/tags/*| grep -v"/ code_"| xargs rm
对其他子目录重复2,3,4点
现在我们有@MiniQuark anwser point 3中的目录结构.
如同MiniQuark anwser的第4点那样,但是在执行拉动之后和删除.git
目录之前,请获取标记:
$ git fetch catalog refs/tags/*:refs/tags/*
继续..
这只是另一种解决方案.希望它对某人有所帮助,它帮助了我:)
来自亚里士多德Pagaltzis的 git-stitch-repo 回答仅适用于具有简单线性历史的存储库.
MiniQuark的答案适用于所有存储库,但它不处理标记和分支.
我创建了一个程序,其工作方式与MiniQuark描述的相同,但它使用一个合并提交(具有N个父项),并且还重新创建所有标记和分支以指向这些合并提交.
有关如何使用它的示例,请参阅git-merge-repos存储库.