[V 站有 git 大神吗? ]删除仓库的某个时间点之前的历史记录,减少.git 目录大小。 救命啊啊。

2016-08-08 09:48:05 +08:00
 Yancey
安卓仓库。有很多 commits 和分支。想删除某个时间点之前的所有 commits 减少.git 目录大小,找了很多办法。感觉只有 grafts+ filter-brnach 靠谱。不过还是遇到很多问题、
1.要截断的 commits 之前有很多分支。。用 filter-branch 不会删除这些分支,怎么解决?
2.这个仓库是公开仓库。很多人已经 clone 在本地。所以截断操作应该是在服务器还是本地?我试过在本地更改,但是推不到服务器上。如果在服务器操作,怎么将本地的改动变为最小?

示意图如下:
12411 次点击
所在节点    git
56 条回复
skydiver
2016-08-08 14:13:37 +08:00
如果误添加了大文件导致,可以用楼上 @fy 这种方法

如果要彻底修改历史, rebase -i 就行了,保留第一个,保留现在的,中间的都 fixup
AnyOfYou
2016-08-08 14:23:06 +08:00
官方的用来管理 Android 源码下众多 git 仓库的 repo 工具, init 的时候可以指定 branch 。
这个 repo 实际就是一堆 python 脚本。 init 后到会把 subcmds 下载到本地。你可以看其 sync 的实现并修改。
AnyOfYou
2016-08-08 14:25:13 +08:00
另外, init 的时候可以直接指定 --depth 。
Yancey
2016-08-08 14:28:23 +08:00
@skydiver 几百个 branch 几千个 commits 怎么 rebase -i 不行吧
SourceMan
2016-08-08 15:21:30 +08:00
楼主没说规模,我这边几个 G 的算什么程度?
Yancey
2016-08-08 15:35:12 +08:00
@SourceMan 我这边磁盘小。。编译的时候拉十几个工程也是几个 G
skydiver
2016-08-08 15:35:26 +08:00
@Yancey 为什么不行?麻烦一点儿而已
402124773
2016-08-08 17:05:38 +08:00
7.2G .git
也没见过提出这个需求。
哈哈
wweir
2016-08-08 18:50:42 +08:00
不知道是否有更直接的操作方式
只知道 squash 命令可以压缩大量 commit 为一个

结合楼主的需求,也许结合 rebase 可以实现相应功能。

我们这边的做法是,在下一次大重构之前,拷出所有有用的代码为一个新的 repo 。老代码就自己慢慢滚下去,直到成为一个历史档案
jimages
2016-08-08 22:56:46 +08:00
这笔记本太熟悉了。渡边本。
msg7086
2016-08-08 23:10:17 +08:00
修改历史一定会导致 commit hash 变动,亲你不会连这点知识都没有吧……
sodatea
2016-08-09 00:47:15 +08:00
@Yancey git clone --single-branch 的体积也仍然无法接受么?
tinyproxy
2016-08-09 08:44:22 +08:00
@Yancey 一个建议,资源文件等大体积的不要入库,传到某云存储去,通过一个 configure 脚本下载回来就好了
yuankui
2016-08-09 08:51:46 +08:00
@lijianying10 这个方法不错~
mrsatangel
2016-08-09 09:40:21 +08:00
`root -> A -> B -> C -> newRoot -> D `
也就是想要将 newRoot 之前的 commit 对象全部删除。

在`.git/info/`下建立`grafts`文件,在其中输入`newRoot`对象的 SHA1 值,保存。此时使用`git log`命令应该只能看到`newRoot`的 commit 记录。
之后使用`git filter-branch`使这个新建的 root 生效.

注意,这个 chop 操作可能会导致出现一个新的 detached 的 branch ,为当前的这个 branch 新建一个临时的 branch:`git branch tmp`,然后将 tmp branch 推送到远程的 repo 里想要更新的 branch (如 master ):`git push <remoteRepoName> tmp:<remoteBranchName>`,此时远程 repo 里面的**&lt;remoteBranchName&gt;**已经将**newRoot**之前的所有 commit 对象删除。
Yancey
2016-08-09 11:14:58 +08:00
@mrsatangel 感谢。你的方案可行。

我原本以为本地截断后,不能强行推送到远端。原来是可以的。

不过你提到
“为当前的这个 branch 新建一个临时的 branch:`git branch tmp`,然后将 tmp branch 推送到远程的 repo 里想要更新的 branch (如 master ):`git push <remoteRepoName> tmp:<remoteBranchName>`,此时远程 repo 里面的**&lt;remoteBranchName&gt;**已经将**newRoot**之前的所有 commit 对象删除。”

感觉这个 tem branch 是多余的吧。直接强推截断的 master 就可以的。


另外对你的答案补充下;
假如你有如下的分支结构图



现在想从"57dd13f even"这个点截断。保留这个点上面的所有分支和 commit
首先需要 git push origin :test 将 test 分支删除。也就是说截断点以下的所有都删除。
再者 将截断点以上的所有分支都在本地有追踪分支 git checkout -b new origin/new

之后就执行

“在`.git/info/`下建立`grafts`文件,在其中输入`newRoot`对象的 SHA1 值,保存。此时使用`git log`命令应该只能看到`newRoot`的 commit 记录。
之后使用`git filter-branch`使这个新建的 root 生效. ”


最后执行
将本地所有分支都强推到远端一遍。
本例就是 git push --force origin master:master 和 git push --force origin new:new


哦对了,还要删除 original 文件夹保存的临时记录
rm -r .git/refs/original/


最后效果:





其实这样的好处还有一个就是,所有 clone 这个仓库的本地仓库都可以执行一个相同的脚本。这样就不用大家都重新 clone 了,本地的 branch 和没有推送的 commit 也可以保留。


不知道理解对不对。可以再讨论。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/297802

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX