问题描述
我目前正在开发本地存储库,我想在GitHub上公开共享(部分)。到目前为止,我已经完成了什么:
git checkout dev # dev is the current development branch of my local repository
git branch public # create a new branch from dev for the public repo
git checkout public
git remote add public git@github.com # add the public repo as a new remote
git push -u public public:master # push local 'public' branch to 'master' branch of 'public' remote
但是,此推送失败,因为我的存储库包含一些相当大的子目录。所以我着手清理它:
git rm -r --cached external # remove large subdirectory 'external'
git rm -r --cached ... # repeat for other large subdirectories
然后,我将上述所有子目录也都包含在.gitignore
中并提交。现在,对git ls
的调用仅显示少量文件,这些文件的总大小最多为几MB,而对git status
的调用则没有显示未提交或未跟踪的文件。但是git push
仍然失败,这显然是因为分支的历史记录中仍包含大型子目录。
从历史记录中清除文件的正确方法似乎是使用git filter-branch
命令,但是此命令附带了很多警告,我不想弄乱目录中的整个存储库处理。
git rm
从public
分支(仅public
分支)的历史记录中用{{1}}删除的子目录?
由于该分支不可能再合并到其他分支中,因此我最后只需删除所有历史记录就可以了。其他分支仍应保持原样
解决方法
从某种意义上说,git中并不真正存在分支:它们只是指向特定提交的指针,从那里指向导致该提交的历史记录。因此,您的存储库可能看起来像这样,如图所示:
+-- E --- F <- main branch
/
A --- B --- C --- D
\
+-- G --- H <- public branch
如果大型文件存在于提交A,B,C和D中的任何一个中,那么根据定义,它们存在于主分支和公共分支的历史中。
要重写历史记录,必须在刚添加这些文件时创建新的提交。您可以使用git-filter-repo工具,如下所示:
git filter-repo --invert-paths --path '/directory/to/delete' --refs public
我们假设文件是在提交B中首先添加的;我们现在可能会遇到这样的事情:
+-- B --- C --- D -- E --- F <- main branch
/
A
\
+-- B2 --- C2 --- D2 --- G2 --- H2 <- public branch
这似乎是您想要的,但它不再是一个分支的好用-如果您曾经尝试将main
中的任何内容合并到其中,那么您将得到以下结果:
+-- B --- C --- D -- E --- F ----- X <- main branch with new feature
/ \
A \
\ \
+-- B2 --- C2 --- D2 --- G2 --- H2 --- M <- public branch with merge commit
提交B的原始版本(包含我们的大文件)现在又回到分支历史中了,与新提交B2一样 。
因此,与其担心哪个分支包含和不包含文件,不如简单地为存储库复制一个新名称并使其好像这些文件从未存在一样容易。存储库历史记录中的任意位置。
git filter-repo --invert-paths --path '/directory/to/delete'
这将重写所有您的提交,并提供全新的历史记录:
+-- E2 --- F2 <- main branch
/
A2 --- B2 --- C2 --- D2
\
+-- G2 --- H2 <- public branch