Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在不同的git存储库中复制文件及其历史记录?_Git_Merge_Repository - Fatal编程技术网

如何在不同的git存储库中复制文件及其历史记录?

如何在不同的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>

我有一个项目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="<ProjectA/.git>"
git rev-parse --git-dir
还原git存储库

GIT_DIR=
(我将其中的一部分作为评论,但决定对此进行扩展。)

注意,在Git中,文件没有历史记录。提交是历史记录,提交有文件

例如,可能commit
a666666
具有文件
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