The Easy Way™
事实证明,这是一种非常普遍和有用的做法,Git 的霸主让它变得非常简单,但你必须拥有更新版本的 Git (>= 1.7.11 May 2012)。请参阅附录了解如何安装最新的 Git。此外,下面的演练中有一个真实示例。
-
准备旧的仓库
cd <big-repo>
git subtree split -P <name-of-folder> -b <name-of-new-branch>
注意:<name-of-folder> 不得包含前导或尾随字符。例如,名为subproject 的文件夹必须作为subproject 传递,而不是./subproject/
Windows 用户注意事项:当您的文件夹深度大于 1 时,<name-of-folder> 必须具有 *nix 样式的文件夹分隔符 (/)。例如,名为path1\path2\subproject 的文件夹必须作为path1/path2/subproject 传递
-
创建新的仓库
mkdir ~/<new-repo> && cd ~/<new-repo>
git init
git pull </path/to/big-repo> <name-of-new-branch>
-
将新的 repo 链接到 GitHub 或任何地方
git remote add origin <git@github.com:user/new-repo.git>
git push -u origin master
-
清理<big-repo> 内部,如果需要
git rm -rf <name-of-folder>
注意:这会将所有历史引用留在存储库中。如果您确实担心已提交密码或需要减小.git 文件夹的文件大小,请参阅下面的附录。
演练
这些是与上述相同的步骤,但遵循我的存储库的确切步骤,而不是使用<meta-named-things>。
这是我在节点中实现 JavaScript 浏览器模块的一个项目:
tree ~/node-browser-compat
node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator
我想将单个文件夹 btoa 拆分为单独的 Git 存储库
cd ~/node-browser-compat/
git subtree split -P btoa -b btoa-only
我现在有一个新分支 btoa-only,它只有 btoa 的提交,我想创建一个新的存储库。
mkdir ~/btoa/ && cd ~/btoa/
git init
git pull ~/node-browser-compat btoa-only
接下来,我在 GitHub 或 Bitbucket 或其他任何地方创建一个新的 repo,并将其添加为 origin
git remote add origin git@github.com:node-browser-compat/btoa.git
git push -u origin master
快乐的一天!
注意:如果您使用 README.md、.gitignore 和 LICENSE 创建了一个 repo,则需要先拉取:
git pull origin master
git push origin master
最后,我想从更大的仓库中删除该文件夹
git rm -rf btoa
附录
macOS 上的最新 Git
使用Homebrew获取最新版本的Git:
brew install git
Ubuntu 上的最新 Git
sudo apt-get update
sudo apt-get install git
git --version
如果这不起作用(您的 Ubuntu 版本非常旧),请尝试
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git
如果还是不行,试试
sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh
sudo ln -s \
/usr/share/doc/git/contrib/subtree/git-subtree.sh \
/usr/lib/git-core/git-subtree
感谢来自 cmets 的rui.araujo。
清除您的历史记录
默认情况下,从 Git 中删除文件实际上并没有删除它们,它只是提交它们不再存在。如果您想真正删除历史引用(即您提交了密码),您需要这样做:
git filter-branch --prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD
之后,您可以检查您的文件或文件夹是否不再显示在 Git 历史记录中
git log -- <name-of-folder> # should show nothing
但是,您不能将删除“推送”到 GitHub 等。如果你尝试,你会得到一个错误,你必须先git pull,然后才能git push - 然后你就会回到你的历史记录中。
因此,如果您想从“原点”中删除历史记录(即从 GitHub、Bitbucket 等中删除),您需要删除存储库并重新推送经过修剪的存储库副本。但是等等 - 还有更多! - 如果您真的担心删除密码或类似的东西,您需要修剪备份(见下文)。
使.git 更小
前面提到的删除历史命令仍然会留下一堆备份文件——因为 Git 非常友好地帮助您避免意外破坏您的存储库。它最终会在几天和几个月内删除孤立的文件,但它会将它们保留一段时间,以防您意识到您不小心删除了您不想删除的内容。
因此,如果您真的想清空垃圾以立即减小 repo 的克隆大小,您必须做所有这些非常奇怪的事情:
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune=now
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune
也就是说,我建议您不要执行这些步骤,除非您知道自己需要这样做 - 以防万一您确实修剪了错误的子目录,知道吗?推送存储库时不应克隆备份文件,它们只会在您的本地副本中。
信用