【问题标题】:How to move files from one git repo to another preserving history using `git format-patch`and `git am`如何使用`git format-patch`和`git am`将文件从一个git repo移动到另一个保存历史记录
【发布时间】:2015-03-03 11:40:55
【问题描述】:

问题

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

我在 SE 上找到了一种方法:How to move files from one git repo to another (not a clone), preserving history。 在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

我尝试了一些相关的东西,灵感来自How to create and apply a patch with 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 都告诉我“什么都不做”。补丁对象远非空。 顺便说一句,我不知道这是否相关,但补丁的创建和应用都是在分支中完成的。

【问题讨论】:

标签: git


【解决方案1】:

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

对于这么简单的事情,您不需要太多安全网。不过,作为参考,这就是我所做的几乎所有可能弄脏历史、命名空间或工作树的事情

# 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

filter-branch docs

你可以推送到任何你有 url 或路径的 repo,只需直接使用 url 而不是为 onesy-twosie 工作创建一个远程名称。推送和重命名:git push u://r/l sliced:branchnameinthatrepo


您希望从 cmets 中选择和重新定位子目录。这是一些相当简单的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 的工作原理,它还是很简单的。

作为提醒、回顾或介绍,视情况而定:

    1234563要求 repo 记住任何内容,你提供它类型和字节,它 (a) 存储它并 (b) 为你提供它的唯一名称。
  1. 索引只是一个列表,将路径名映射到那里的存储库内容。

  2. git read-tree 是检出、合并和重置的底层操作——它实际上并不在 repo 上操作,它使用的所有对象都已经存在。您将现有的树提供给它,它会将它们与索引中的内容结合起来(并且可以选择更新工作树,尽管这在这里无关紧要)以生成您想要的索引,或者至少让您更接近它。

    李>

上面的第一个读树是

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

你可以通过计算你给它的树的数量来确定git read-tree 将要做什么的基本性质。这是一个单树读取,用于添加到索引(edit: 顺便说一句,没有选项,1-tree git read-tree replaces the index)。此处添加的树位于被过滤的提交中的source/subdir,read-tree 将其全部添加到索引中,destination/subdir/ 添加到路径名的前面。

下一个读取树是两棵树读取,它为git checkout 执行索引(和工作树,如果你想在这里做任何事情)——它应用了原始树和目标树到索引。这里,原始树是$GIT_COMMIT,目标树git mktree &lt;/dev/null 是空树。所以操作是“在索引中找到原始树中的所有内容,并使所有这些条目看起来与目标树完全一样”,也就是“让它们全部消失”。上面添加的目标子目录不涉及,它不在原始树中,所以 read-tree 不会让它消失。

过滤器完成,filter-branch 提交新索引中的内容(存储库中已经存在的内容,记住),是时候进行下一次提交了。

read-tree docs。此链接跳过描述,这是故意的。不要读它。

【讨论】:

  • 创建“安全网”的技巧很棒。现在我可以玩弄过滤器分支了。谢谢(为此+1!)。
  • 但是我还没有管理推送,因为我的 sliced 中的内容应该转到目标存储库中的不同文件夹。
  • 感谢您的彻底编辑。我希望我能给你更多的支持 :-) 它确实解决了我的问题(我现在将我的文件移动到了正确的位置)。
  • 可以说它不能准确回答我的问题(format-patcham)。我正在权衡等待有关该方法的更多讨论,或者只是更改我的问题的标题并接受您的回答。
  • 谢谢。是的,你努力处理你面前的事情,并解释这种尝试把你带到了哪里。我不认为这种尝试是针对这种情况使用正确的工具。
【解决方案2】:

看起来您遇到的问题是某些文件存在于您尝试创建的两个存储库中,然后从补丁中创建它们。在您的示例中,这些是 README.md 和 .gitignore

使用 git-apply 应用补丁时,您可以使用 --exclude=&lt;path-pattern&gt; 忽略这些文件。见http://git-scm.com/docs/git-apply

【讨论】:

  • 有一个 ~/repo/org/mydir/README.md 但 ~/repo/dest/mydir/ 是一个新目录,因此是空的。但是,在 ~/repo/dest/ 中肯定有更高的 README.md
  • 感谢您提出建议 (+1)
猜你喜欢
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多