将许多子目录分离成一个新的单独的Git仓库
这个问题是基于Detach子目录到单独的Git仓库
而不是分离一个单独的子目录,我想分离一对夫妇。 例如,我目前的目录树看起来像这样:
/apps /AAA /BBB /CCC /libs /XXX /YYY /ZZZ
我想这个:
/apps /AAA /libs /XXX
git filter-branch
的--subdirectory-filter
参数将不起作用,因为它在第一次运行时除去给定目录的所有内容。 我认为对所有不需要的文件使用--index-filter
参数会起作用(尽pipe很乏味),但是如果我尝试多次运行它,我会收到以下消息:
Cannot create a new backup. A previous backup already exists in refs/original/ Force overwriting the backup with -f
有任何想法吗? TIA
而不是必须处理一个子shell和使用ext glob(如kynanbuild议),试试这个更简单的方法:
git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- apps/AAA libs/XXX' --prune-empty -- --all
你为什么要多次运行filter-branch
? 你可以在一次扫描中完成所有的工作,所以不需要强制执行(注意你需要在你的shell中启用extglob
才能工作):
git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd apps/!(AAA) libs/!(XXX))" --prune-empty -- --all
这应该摆脱不需要的子目录中的所有变化,并保持所有的分支和提交(除非它们只影响修剪后的子目录中的文件,凭借--prune-empty
) – 没有重复提交等问题。
在这个操作之后,不需要的目录将被列为未被跟踪的git status
。
$(ls ...)
是必要的st extglob
由您的shell而不是使用sh
内置eval
(其中extglob
不可用)的索引filtereval
。 请参阅如何在git中启用shell选项? 进一步的细节。
在这里回答我自己的问题…经过大量的试验和错误。
我设法使用git subtree
和git-stitch-repo
。 这些说明基于:
- 用git子树共享项目之间的代码 – http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/
- 工作的正确工具:git-stitch-repo – http://ifup.org/2009/02/07/the-right-tool-for-the-job-git-stitch-repo/
首先,我把我想保留的目录放到他们自己的单独的存储库中:
cd origRepo git subtree split -P apps/AAA -b aaa git subtree split -P libs/XXX -b xxx cd .. mkdir aaaRepo cd aaaRepo git init git fetch ../origRepo aaa git checkout -b master FETCH_HEAD cd .. mkdir xxxRepo cd xxxRepo git init git fetch ../origRepo xxx git checkout -b master FETCH_HEAD
然后我创build一个新的空的存储库,并导入/缝合最后两个到它:
cd .. mkdir newRepo cd newRepo git init git-stitch-repo ../aaaRepo:apps/AAA ../xxxRepo:libs/XXX | git fast-import
这创build了两个分支, master-A
和master-B
,每个分支持有一个拼接仓库的内容。 把它们和清理结合起来:
git checkout master-A git pull . master-B git checkout master git branch -d master-A git branch -d master-B
现在我不太清楚这种情况是怎么发生的,但是在第一次checkout
和pull
,代码奇迹般地融入了主分支(对于这里所发生的事情的任何了解都是值得赞赏的!
一切似乎都按预期工作,除了如果我查看newRepo
提交历史logging,当变更集影响到apps/AAA
和libs/XXX
时,重复。 如果有办法删除重复,那么这将是完美的。
手动步骤与简单的git命令
计划是将各个目录分成自己的回购站,然后将它们合并在一起。 下面的手动步骤并没有使用通俗易懂的脚本,而是易于理解的命令,并且可以帮助将额外的N个子文件夹合并到另一个单独的存储库中。
划分
假设您的原始回购是: original_repo
1 – 拆分应用程序:
git clone original_repo apps-repo cd apps-repo git filter-branch --prune-empty --subdirectory-filter apps master
2 – 拆分库
git clone original_repo libs-repo cd libs-repo git filter-branch --prune-empty --subdirectory-filter libs master
继续如果你有超过2个文件夹。 现在你将有两个新的和临时的git仓库。
通过合并应用程序和库来征服
3 – 准备全新的回购:
mkdir my-desired-repo cd my-desired-repo git init
而且你将需要至less做一个提交。 如果以下三行应该跳过,您的第一个回购将立即出现在您的回购的根目录下:
touch a_file_and_make_a_commit git add a_file_and_make_a_commit git commit -am "at least one commit is needed for it to work"
随着临时文件提交,后面的部分中的merge
命令将按预期停止。
4 – 先合并应用程序回购:
git remote add apps-repo ../apps-repo git fetch apps-repo git merge -s ours --no-commit apps-repo/master git read-tree --prefix=apps -u apps-repo/master git commit -m "import apps"
现在你应该看到你的新存储库中的应用程序目录。 git log
应该显示所有相关的历史提交信息。
5 – 以相同的方式合并libs回购:
git remote add libs-repo ../libs-repo git fetch libs-repo git merge -s ours --no-commit libs-repo/master git read-tree --prefix=libs -u libs-repo/master git commit -m "import libs"
继续如果你有两个以上的回购合并。
参考: 用git合并另一个仓库的子目录
使用“混帐拆分”git扩展名
git splits
是一个bash脚本,它是git branch-filter
一个包装git branch-filter
,基于jkeating的解决scheme ,我创build了一个git扩展。
这是完全适合这种情况。 对于你的错误,尝试使用git splits -f
选项来强制删除备份。 由于git splits
在一个新的分支上运行,它不会重写你当前的分支,所以备份是无关紧要的。 请参阅自述文件以获取更多详细信息,并确保将其用于您的回购副本(以防万一!) 。
- 安装
git splits
。 -
拆分目录到本地分支
#change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
#split multiple directories into new branch XYZ git splits -b XYZ apps/AAA libs/ZZZ#change into your repo's directory cd /path/to/repo #checkout the branch git checkout XYZ
#split multiple directories into new branch XYZ git splits -b XYZ apps/AAA libs/ZZZ -
在某处创build一个空的回购。 我们假设我们在GitHub上创build了一个名为
xyz
的空回购,其path为:git@github.com:simpliwp/xyz.git
-
推到新的回购。
#add a new remote origin for the empty repo so we can push to the empty repo on GitHub git remote add origin_xyz git@github.com:simpliwp/xyz.git #push the branch to the empty repo's master branch git push origin_xyz XYZ:master
-
将新创build的远程仓库克隆到新的本地目录中
#change current directory out of the old repo cd /path/to/where/you/want/the/new/local/repo #clone the remote repo you just pushed to git clone git@github.com:simpliwp/xyz.git
我写了一个gitfilter来解决这个问题。 它有git_filter的奇妙名字,位于github这里:
https://github.com/slobobaby/git_filter
它基于优秀的libgit2。
我需要分裂一个大型的存储库提交了许多提交(~100000)和基于git filter-branch的解决scheme花了几天的时间来运行。 git_filter需要一分钟来做同样的事情。
是啊。 在后续调用filter-branch
强制使用-f
标志覆盖备份以覆盖该警告。 :)否则,我认为你有解决scheme(即,一次根除filter-branch
根除一个不需要的目录)。
按照消息build议,删除refs / original中.git目录下的备份。 目录是隐藏的。