将子目录(已重命名!)分离到新的仓库中

时间:2011-07-09 22:56:58

标签: git git-filter-branch

我有一个存储库,我想将其中一个目录分成一个新的仓库。 This是一个开始的理想场所,但有一点需要注意:我想要分离的目录在某些时候被重命名。如果我使用目录的新名称来关注该帖子的解决方案,那么似乎我在重新命名之前丢失了历史记录。是否有任何想法可以让它在这种情况下发挥作用?

2 个答案:

答案 0 :(得分:9)

git filter-branch可以对提交范围进行操作;所以我们可以做的是分别过滤'之前'和'之后',并使用移植物将它们粘在一起:

git branch rename $COMMIT_ID_OF_RENAME 
git branch pre-rename rename~
## First filter all commits up to rename, but not rename itself
git filter-branch --subdirectory-filter $OLDNAME pre-rename
## Add a graft, so our rename rev comes after the processed pre-rename revs
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
## The first filter-branch left a refs backup directory. Move it away so the
## next filter-branch doesn't complain
mv .git/refs/original .git/refs/original0
## Now filter the rest
git filter-branch --subdirectory-filter $NEWNAME master ^pre-rename
## The graft is now baked into the branch, so we don't need it anymore
rm .git/info/grafts

如果您需要过滤多个分支或标记,这会稍微复杂一些;重命名之前的分支可以包含在第一个filter-branch中,而after之后的分支必须包含在第二个filter-branch中的^rename之前。

另一种选择是添加一个索引过滤器(或树过滤器),用于检查旧目录和新目录,并保留存在的目录。

由于您尚未提供测试存储库,因此以下是此方案的快速完整性检查脚本:

#!/bin/bash

set -u
set -e
set -x

rm -rf .git x y foo

git init
mkdir x
echo initial > x/foo
git add x/foo
git commit -m 'test commit 1'

echo tc2 >> x/foo
git commit -a -m 'test commit 2'

mv x y
git rm x/foo
git add y/foo
git commit -a -m 'test rename'

git branch rename HEAD

echo post rename >> y/foo
git commit -a -m 'test post rename'

git branch pre-rename rename~

git filter-branch --subdirectory-filter x pre-rename
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts

mv .git/refs/original .git/refs/original0

git filter-branch --subdirectory-filter y master ^pre-rename

rm .git/info/grafts

git log -u

如果此过程对您不起作用,那么您的存储库历史记录中可能还有一些您未描述的奇怪内容,例如隐藏在历史记录中的其他重命名。

答案 1 :(得分:0)

我们(Matthew Flatt和我)编写了一个程序来执行此操作:https://github.com/samth/git-slice