git - 如何使用 `git format patch` 和 `git am` 将文件从一个 git repo 转移到另一个保留的历史

  显示原文与译文双语对照的内容
93 4

问题

我想将文件夹( 。子文件夹包含文件) 从一个存储库移动到另一个存储库,保留历史记录。

我找到了一个关于SE的方法 如何将文件从一个 git-repo 移动到另一个( 不是克隆),保留历史记录。 和关于 blog.neutrino.es的不同想法。 这是我想在这里讨论的最后一个。

尝试解决方案


mkdir/tmp/mergepatchs


cd ~/repo/org


export reposrc=myfile.c #or mydir


git format-patch -o/tmp/mergepatchs $(git log $reposrc|grep ^commit|tail -1|awk '{print $2}')^..HEAD $reposrc


cd ~/repo/dest


git am/tmp/mergepatchs/*.patch



如果我正确理解,想法是假设我们将提交提交,并重新导入它的他存储库。

错误

在执行 git am/tmp/mergepatchs/*.patch 时收到这里错误消息:


Applying: Initial commit


error:. gitignore: already exists in index


error: README.md: already exists in index


Patch failed at 0001 Initial commit


The copy of the patch that failed is found in:


/Users/myuser/repo/org/.git/rebase-apply/patch


When you have resolved this problem, run"git am --continue".


If you prefer to skip this patch, run"git am --skip" instead.


To restore the original branch and stop patching, run"git am --abort".



为了理解更好的流程,我首先尝试了一个( 而不是整个目录) 文件。 git am ( 例如 ) 之后发生了"无"。 没有新文件,git status 不报告任何更改。 为什么会这样?

然后我尝试:


INITCOMMIT=$(git rev-list --parents HEAD | egrep"^[a-f0-9]{40}$")


git format-patch -1 -o/tmp/mergepatchs ${INITCOMMIT}



但是得到了与之前相同的错误消息。

为什么修补程序失败?

编辑 1

我尝试了一些关联,从激发了如何创建和应用一个带有Git的补丁。

~/repo/org 中:


$ git format-patch --root HEAD --stdout myfile.c>/tmp/mergepaths/01.patch



~/depo/dest 中:


$ git apply --stat/tmp/mergepaths/01.patch 


 0 files changed


$ git apply --check/tmp/mergepaths/01.patch 


$ git am </tmp/mergepaths/01.patch 



statcheck 都告诉我"无"将被完成。 面片对象远离空。 顺便说一下,我不知道这是否相关,但是创建和应用都是在分支中完成的。

时间: 原作者:

118 2

有一个像这样的手术工具,git filter-branch

对于这种简单的事情,你不需要一个安全网络。 但是,这就是我如何进行更多可以能脏坏历史或者命名空间或者worktree的方法


# make a throwaway sandbox to play in:


git clone -s./tmp/deleteme


cd!$


git checkout -b sliced



# do it


git filter-branch --subdirectory-filter your/subdir



# and if the result looks good:


git push origin sliced



筛选器分支文档

而且,你可以推到任何你有url或者路径,只是直接使用网址,而不是为twosie工作做远程的NAME 。 要按下并重命名: git push u://r/l sliced:branchnameinthatrepo

从你希望同时选择和重新定位子目录的注释中。 这是个相当简单的git read-tree 工作。 读取树操作索引,因此你需要索引筛选器。 对于智慧,这个是:


git filter-branch --index-filter '


 git read-tree --prefix=des/ti/nation/$GIT_COMMIT:source/subdir


 git read-tree -m $GIT_COMMIT `git mktree </dev/null`


'



如果你回忆了git的工作方式,尽管它不熟悉它。

作为提醒或者简介或者介绍,可能是:

存储库是一个对象存储区: by类型和惟一的NAME ( 又名 SHA1 ) 请求任何内容,请求 repo 记住任何内容,你将输入它的类型和字节,并将它输入到你的惟一 NAME 。

索引只是一个列表,映射到存储库内容的路径。

git read-tree 是签出和合并并重置--的基础操作,它实际上没有在 repo 上运行,所有对象都已经存在。 你将它们提供给现有树,它将它们与索引( 还可以更新 worktree,尽管这在这里是不相关的) 中的内容结合起来,或者至少让你一步一步。

上面的第一个读取树是


 git read-tree --prefix=destination/subdir/$GIT_COMMIT:source/subdir



你可以通过计算你给它多少树来确定 git read-tree 要做什么的基本性质。 这里是一个树,用来添加到索引中( 编辑 : ,没有选项,1-tree git read-tree 替换了索引 。 这里处添加的树位于被筛选的提交位置,并且读树将所有的source/subdir 添加到路径名前面的索引中。

下一个读树是两棵树,它为 git checkout --作了索引( 如果你想在这里做任何事) 工作,它将原始树和目标树的差异应用到索引中。 这里,原始树是 $GIT_COMMIT,目标树 git mktree </dev/null 是空树。 所以操作是"在索引中查找原始树中的所有内容,并使所有这些条目看起来与目标树完全一样",这里是"让他们都离开"。 上面添加的目标subdir不参与,它不在原始树中,所以读取树不会使它消失。

过滤器的完成,过滤器分支提交了新索引( 有关 repo 中已经存在的内容的) 中的内容,是下一个提交的时间。

读取树文档这里链接跳过描述,即故意。 不要读。

原作者:
78 1

看起来你所拥有的问题是,在这两个存储库中存在某些文件,然后从补丁中创建它们。 在你的示例中,这些是 README.md 和. gitignore 。

当应用patch应用补丁时,你可以使用 --exclude=<path-pattern> 忽略这些文件。 请参见 http://git-scm.com/docs/git-apply

...