我有一个包含2个目录和多个分支的git仓库,我想拆分它们并创建所有分支
`-- Big-repo
|-- dir1
`-- dir2
Branches : branch1, branch2, branch3 ...
我想要什么
我想将dir1和dir2拆分为两个单独的repos并在两个存储库中保留branch branch1,branch2 ....
dir1
Branches : branch1, branch2, branch3 ...
dir2
Branches : branch1, branch2, branch3 ...
我尝试了什么:
我可以使用
将它们分成2个回购git subtree split -P dir1 -b dir1-only
git subtree split -P dir2 -b dir2-only
但是,分离后不会创建任何分支。
获得所有分支:
git checkout branch1 (in Big-repo)
git subtree split -p dir1 -b dir1-branch1
git checkout branch2 (in Big-repo)
git subtree split -p dir1 -b dir1-branch2
And push these branches to newly created repo.
这需要更多的手动工作,我相信可能有一种快速的方法来实现这一目标?
任何想法???
答案 0 :(得分:42)
git filter-branch
提供您想要的功能。使用--subdirectory-filter
选项,您可以创建一组新的提交,其中subDirectory
的内容位于目录的根目录。
git filter-branch --prune-empty --subdirectory-filter subDirectory -- --branches
以下是以安全的方式执行此操作的示例。您需要为将被隔离到其自己的仓库中的每个子目录执行此操作,在本例中为dir1
。
首先克隆您的存储库以保持隔离的更改:
git clone yourRemote dir1Clone
cd dir1Clone
要准备克隆的存储库,我们将重新创建所有远程分支作为本地分支。我们跳过以*
开头的那个,因为那是当前的分支,在这种情况下,由于我们处于无头状态,因此将读取(no branch)
:
# move to a headless state
# in order to delete all branches without issues
git checkout --detach
# delete all branches
git branch | grep --invert-match "*" | xargs git branch -D
要在本地重新创建所有远程分支,我们会查看git branch --remotes
的结果。我们跳过包含->
的那些,因为那些不是分支:
# get all local branches for remote
git branch --remotes --no-color | grep --invert-match "\->" | while read remote; do
git checkout --track "$remote"
done
# remove remote and remote branches
git remote remove origin
最后运行filter-branch
命令。这将创建与提交dir1
子目录的所有提交的新提交。所有触及此子目录的分支都将更新。输出将列出未更新的所有引用,对于完全不触及dir1
的分支就是这种情况。
# Isolate dir1 and recreate branches
# --prune-empty removes all commits that do not modify dir1
# -- --all updates all existing references, which is all existing branches
git filter-branch --prune-empty --subdirectory-filter dir1 -- --all
在此之后,您将拥有一组新的提交,这些提交在存储库的根目录中具有dir1
。只需添加您的遥控器来推送新提交,或者将它们全部用作新的存储库。
如果您关心存储库大小,则作为额外的最后一步:
即使更新了存储库的所有分支仍然具有原始存储库的所有对象,只能通过ref-logs访问。如果您想删除这些阅读how to garbage collect commits
一些额外的资源:
答案 1 :(得分:6)
这个脚本为我完成了这项工作:
#!/bin/bash
set -e
if [ -z "$3" ]; then
echo "usage: $0 /full/path/to/repository path/to/splitfolder/from/repository/root new_origin"
exit
fi
repoDir=$1
folder=$2
newOrigin=$3
cd $repoDir
git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D
for remote in `git branch --remotes | grep --invert-match "\->"`
do
git checkout --track $remote
git add -vA *
git commit -vam "Changes from $remote" || true
done
git remote remove origin
git filter-branch --prune-empty --subdirectory-filter $folder -- --all
#prune old objects
rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune
#upload to new remote
git remote add origin $newOrigin
git push origin master
for branch in `git branch | grep -v '\*'`
do
git push origin $branch
done