我们的Git存储库最初是一个大型SVN存储库的一部分,其中每个项目都有自己的树,如下所示:
project1/branches
/tags
/trunk
project2/branches
/tags
/trunk
显然,使用svn mv将文件从一个文件移动到另一个文件非常容易。但是在Git中,每个项目都在它自己的存储库中,今天我被要求将一个子目录从project2移动到project1。我是这样做的:
$ git clone project2
$ cd project2
$ git filter-branch --subdirectory-filter deeply/buried/java/source/directory/A -- --all
$ git remote rm origin # so I don't accidentally overwrite the repo ;-)
$ mkdir -p deeply/buried/different/java/source/directory/B
$ for f in *.java; do
> git mv $f deeply/buried/different/java/source/directory/B
> done
$ git commit -m "moved files to new subdirectory"
$ cd ..
$
$ git clone project1
$ cd project1
$ git remote add p2 ../project2
$ git fetch p2
$ git branch p2 remotes/p2/master
$ git merge p2 # --allow-unrelated-histories for git 2.9+
$ git remote rm p2
$ git push
但这似乎相当复杂。有没有更好的方法来做这类事情呢?还是我采取了正确的方法?
注意,这涉及到将历史合并到现有的存储库中,而不是简单地从另一个存储库的一部分创建一个新的独立存储库(如前面的问题中所述)。
我发现Ross Hendrickson的博客很有用。这是一种非常简单的方法,您可以创建应用于新回购的补丁。更多细节请参见链接页面。
它只包含三个步骤(复制自博客):
# Setup a directory to hold the patches
mkdir <patch-directory>
# Create the patches
git format-patch -o <patch-directory> --root /path/to/copy
# Apply the patches in the new repo using a 3 way merge in case of conflicts
# (merges from the other repo are not turned into patches).
# The 3way can be omitted.
git am --3way <patch-directory>/*.patch
唯一的问题是我不能一次性应用所有补丁
git am --3way <patch-directory>/*.patch
在Windows下,我得到了一个InvalidArgument错误。所以我不得不一个接一个地打补丁。
在我的例子中,我不需要保存我正在迁移的回购,也不需要保存任何以前的历史记录。我用不同的遥控器,截取了同一根树枝的补丁
#Source directory
git remote rm origin
#Target directory
git remote add branch-name-from-old-repo ../source_directory
在这两个步骤中,我能够让另一个回购的分支出现在同一个回购中。
最后,我设置这个分支(我从另一个回购导入)遵循目标回购的主线(所以我可以准确地区分它们)
git br --set-upstream-to=origin/mainline
现在它的行为就好像它只是我在同一次回购中推的另一个分支。
我发现Ross Hendrickson的博客很有用。这是一种非常简单的方法,您可以创建应用于新回购的补丁。更多细节请参见链接页面。
它只包含三个步骤(复制自博客):
# Setup a directory to hold the patches
mkdir <patch-directory>
# Create the patches
git format-patch -o <patch-directory> --root /path/to/copy
# Apply the patches in the new repo using a 3 way merge in case of conflicts
# (merges from the other repo are not turned into patches).
# The 3way can be omitted.
git am --3way <patch-directory>/*.patch
唯一的问题是我不能一次性应用所有补丁
git am --3way <patch-directory>/*.patch
在Windows下,我得到了一个InvalidArgument错误。所以我不得不一个接一个地打补丁。
对于类似的问题(尽管只针对特定存储库中的某些文件),这个脚本被证明是非常有用的:git-import
简短的版本是,它从现有的存储库中创建给定文件或目录($object)的补丁文件:
cd old_repo
git format-patch --thread -o "$temp" --root -- "$object"
然后应用到一个新的存储库:
cd new_repo
git am "$temp"/*.patch
详情请查阅:
文档化的来源
git format-patch
git是
下面的bash函数可以使用这种有用的方法。下面是一个用法示例:
gitcp <Repo1_basedir> <path_inside_repo1> <Repo2_basedir> . gitcp <Repo1_basedir> <path_inside_repo1>
gitcp ()
{
fromdir="$1";
frompath="$2";
to="$3";
echo "Moving git files from "$fromdir" at "$frompath" to "$to" ..";
tmpdir=/tmp/gittmp;
cd "$fromdir";
git format-patch --thread -o $tmpdir --root -- "$frompath";
cd "$to";
git am $tmpdir/*.patch
}
如果有关文件的路径在两个repo中是相同的,并且您希望只带来一个文件或一小组相关文件,一个简单的方法是使用git进行选择。
第一步是使用git fetch <remote-url>将从另一个repo提交到您自己的本地repo。这将使FETCH_HEAD指向从另一个repo提交的头;如果你想在你完成了其他的取回之后保留对该提交的引用,你可以使用git tag other-head FETCH_HEAD来标记它。
You will then need to create an initial commit for that file (if it doesn't exist) or a commit to bring the file to a state that can be patched with the first commit from the other repo you want to bring in. You may be able to do this with a git cherry-pick <commit-0> if commit-0 introduced the files you want, or you may need to construct the commit 'by hand'. Add -n to the cherry-pick options if you need to modify the initial commit to, e.g., drop files from that commit you don't want to bring in.
在此之后,您可以继续精选后续提交,在必要时再次使用-n。在最简单的情况下(所有提交都是你想要的,并且干净地应用),你可以在cherry-pick命令行上给出完整的提交列表:git cherry-pick <commit-1> <commit-2> <commit-3> ....