如何在不同的git存储库中复制文件及其历史记录?
我有一个项目a的文件,该文件已复制到项目B中。在B的一个分支中,原来属于项目a的代码已被修改 如何将B分支中所做更改的历史记录复制到原始项目A中 考虑到我不想将项目B的所有文件复制到A中,而只想复制已经属于项目A的文件如何在不同的git存储库中复制文件及其历史记录?,git,merge,repository,Git,Merge,Repository,我有一个项目a的文件,该文件已复制到项目B中。在B的一个分支中,原来属于项目a的代码已被修改 如何将B分支中所做更改的历史记录复制到原始项目A中 考虑到我不想将项目B的所有文件复制到A中,而只想复制已经属于项目A的文件 参考:有关git_DIR环境变量,请参阅“git帮助git”。然后添加Project B修改文件,就像您在Project B目录中一样。类似于下面的示例 移动到项目B并将git设置为项目A,使用“rev parse”命令验证项目A git cd <ProjectB>
参考:有关git_DIR环境变量,请参阅“git帮助git”。然后添加Project B修改文件,就像您在Project B目录中一样。类似于下面的示例 移动到项目B并将git设置为项目A,使用“rev parse”命令验证项目A git
cd <ProjectB>
GIT_DIR="<ProjectA/.git>"
git rev-parse --git-dir
还原git存储库
GIT_DIR=
(我将其中的一部分作为评论,但决定对此进行扩展。)
注意,在Git中,文件没有历史记录。提交是历史记录,提交有文件
例如,可能commita666666
具有文件A
、B
和C
以及消息“modify A”,其历史记录为“父级为a555555
”。现在我们后退一步提交a55555
。它有文件A
、B
和C
以及消息“添加文件C”和父级a444444
。然后我们后退一步提交a444444
,其中包含文件A
和B
、父a33333
,以及一些消息;等等
听起来您想要做的是提取每个涉及特定路径的提交(“项目B中的文件”),将这些特定文件路径复制到其他存储库,然后在其他存储库中进行新的提交,可能会重新使用当前提交中的提交消息
有很多方法可以做到这一点。没有一个一定是最好的,尽管有些可能会让事情变得更容易,这取决于你想要什么样的结果。也没有一个是完全内置于Git的,所以您必须至少做一点编程。我将展示一种方法,这对我来说是最明显的
您还应该决定要对合并提交做什么(如果有的话)。合并会导致非线性历史,复制非线性历史需要非常聪明或某种简化。我会把细节留给你
至于如何复制提交,这里有两种相对简单的方法,它们假设我们只关心某种线性或线性化历史
基本设置和查找有趣的提交
设置repo src,该源存储库包含您要从中进行复制的提交(即您所问的项目B的repo副本)。设置第二个repo dst,即您将文件从src中的commit复制到的目标(target)
现在我们需要找到“有趣的提交”。这些是修改“感兴趣的文件”的提交,即您希望复制到dst中的文件
列出提交ID的Git命令是Git rev list
,它需要大约40亿个选项来指定哪些Git对象是有趣的以及如何显示它们。在我们的例子中,我们希望提交,以相反的拓扑顺序列出(最早的第一个),从您想要复制的最新点开始,可能从分支名称开始,可能在某个指定点停止,但仅那些修改了特定路径的提交。因此:
(请注意,您可以列出目录路径。)此处latest
是分支名称或提交ID^stopat
是文字字符^
,后跟名称或其他提交ID;路径s是所有“感兴趣”的文件的名称,或充满文件的目录
您可能还希望包括--第一个父项
和/或--无合并
,这取决于您希望历史记录线性化的方式。学习为自己做决定
(在此过程中,您可能会注意到,stopat..latest
是一种速记语法,与我们在上面的较长形式中所做的相同。)
您可能希望将上述命令的输出重定向到一个文件,因为它可能相当长。然后,您可以检查所选修订或其中的一些随机子集,以查看是否喜欢所选修订。(使用git show
查看特定提交;请注意,默认情况下,git show
使用组合的差异来显示合并提交。)
现在您已经有了一个有趣的提交列表,我们可以继续讨论将这些提交从src复制(部分)到dst的方法。注意:下面的代码都没有经过测试
方法:文本复制
这可能是最简单的方法。编写一个脚本,迭代每个提交ID并在src中签出该提交,然后将文件从src复制到dst,git将它们添加到dst中,并运行git commit
。可以重新添加未更改的文件,因此此脚本非常简单。这假设/list of files
包含“有趣的”路径,repo位于/src
和/dst
中,有趣的提交修订ID位于/interest
中。(您必须编写die
;这是一个简单的shell函数。)如果不是每个提交中都存在路径,那么它可能会出现一些问题(如果路径只是一个子目录,则不是问题)。如果任何path
参数中有空格,它肯定会有问题,因为$(cat../list of path)
将在任何空格处拆分
while read rev; do
(cd src &&
git checkout -q $rev &&
git log -1 --pretty=format:%B > ../commit-msg) ||
die "failed to check out $rev in src"
(cd src && cp -R $(cat ../list-of-paths) ../dst/) ||
die "failed to copy files from src to dst"
(cd dst &&
git add -- $(cat ../list-of-paths) &&
git commit -q -F ../commit-msg) ||
die "failed to commit $rev in dst"
done < interesting
读取时;做
(cd src)&&
git签出-q$rev&&
git日志-1--pretty=格式:%B>。/commit msg)||
die“未能签出src中的$rev”
(cd src和cp-R$(目录../路径列表)…/dst/)||
die“未能将文件从src复制到dst”
(cd-dst)&&
git添加--$(目录../路径列表)&&
git commit-q-F../commit msg)||
die“未能在dst中提交$rev”
完成<有趣
Cherry在以下内容之后选择提交:cd“路径到路径”;GIT_DIR=“pat
GIT_DIR=
git rev-list --topo-order --reverse latest ^stopat -- path1 path2 ... pathN
while read rev; do
(cd src &&
git checkout -q $rev &&
git log -1 --pretty=format:%B > ../commit-msg) ||
die "failed to check out $rev in src"
(cd src && cp -R $(cat ../list-of-paths) ../dst/) ||
die "failed to copy files from src to dst"
(cd dst &&
git add -- $(cat ../list-of-paths) &&
git commit -q -F ../commit-msg) ||
die "failed to commit $rev in dst"
done < interesting