如何删除旧的 git 历史记录?

Posted

技术标签:

【中文标题】如何删除旧的 git 历史记录?【英文标题】:How to delete the old git history? 【发布时间】:2017-06-16 15:17:18 【问题描述】:

我有很多很多(2000+)次提交的 git 存储库,例如:

                 l-- m -- n   
                /
a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- k
                     \
                      x -- y -- z

我想截断旧的日志历史记录 - 从(例如)提交“f”开始但作为存储库开头的日志历史记录中删除所有提交。

怎么做?

【问题讨论】:

rebase 是改变历史的工具。 你想解决什么问题? 这有点像你在吹嘘那些 2000 多次提交。 听起来他觉得2000太多了,想解决一个问题。当这是一个假设时,我们不要指责=) 【参考方案1】:

为了不丢失一些历史;最好先复制您的存储库:)。我们开始吧:(<f> 是你想成为新根提交的提交 f 的 sha)

git checkout --orphan temp <f>      # checkout to the status of the git repo at commit f; creating a branch named "temp"
git commit -m "new root commit"     # create a new commit that is to be the new root commit
git rebase --onto temp <f> master   # now rebase the part of history from <f> to master onthe temp branch
git branch -D temp                  # we don't need the temp branch anymore

如果你有一个遥控器,你想拥有相同的截断历史;你可以使用git push -f警告这是一个危险的命令;不要轻易使用这个!如果您想确保您的上一个版本的代码仍然是相同的;你可以运行git diff origin/master。这应该不会显示任何变化(因为只有历史记录发生了变化;而不是文件的内容)。

git push -f  

以下 2 个命令是可选的 - 它们使您的 git 存储库保持良好状态。

git prune --progress                 # delete all the objects w/o references
git gc --aggressive                  # aggressively collect garbage; may take a lot of time on large repos

【讨论】:

听起来我需要,但每次我运行第三步(git rebase ...)我都会遇到冲突。正常吗? 不,这似乎不正常。您是否在第三步中包含了 &lt;f&gt; 部分(即创建临时分支的相同提交 sha)? @ChrisMaes,我也有冲突。我从提交消息中看到第三个命令尝试在 之前应用旧提交 我也遇到了冲突。这可能不适用于大型回购。 我也遇到了冲突..是否有任何强制变基【参考方案2】:

git clone 使用--shallow-since 选项为您的问题提供了可能的解决方案。如果自 f 以来只有少量提交并且计算它们没有问题,那么您可以使用 --depth 选项。

第二个选项 (--depth) 只克隆指定的分支。如果您需要其他分支,则可以将原始 repo 添加为远程并使用 git fetch 并检索它们。

当您对结果感到满意时,删除旧存储库并重命名新存储库以替换它。如果旧存储库是远程的,则在删除后重新创建它并从新存储库推送到它。

这种方法具有大小和速度的优势。新的 repo 仅包含您想要的提交,无需运行 git prunegit gc 来删除旧对象(因为它们不存在)。

【讨论】:

一个不错的选择。 +1 如果您想保留历史记录但仅在遥控器上,请不要执行最后一步。对于我的应用程序,这是最好的配置:我在遥控器上拥有臃肿的历史记录,以防万一我需要它,但本地克隆和更新很快,不会占用太多磁盘空间。 重新创建遥控器的建议对我不起作用:[remote rejected] develop -&gt; develop (shallow update not allowed) 我试图变得聪明,将浅层克隆推入新分支(而不是新起源)。但 GitHub 仍然记得“被删除”的历史。换句话说,我在起源上重新创建了一个分支,而不是整个起源,并且历史没有让步。这是为什么?为什么我必须重新创建原点? @MaximKamalov 这取决于你的新分支从哪里开始。如果它从当前的master 开始,那么它将继承master 的整个历史记录。使用 GUI Git 客户端查看历史记录和提交之间的关系。【参考方案3】:

对于那些与rebase --onto 发生大量合并冲突(和损坏的结果)的人,我想推荐这个使用git filter-branch 的脚本:

#!/bin/sh

cut_sha="$1"
branch="$2"

git filter-branch \
  --parent-filter "sed -e 's/-p $cut_sha[0-9a-f]*//'" \
  --prune-empty \
  -- $branch

git for-each-ref --format='%(refname)' refs/original | \
  while read ref
  do
    git update-ref -d "$ref"
  done

git reflog expire --expire=0 --all
git repack -ad
git prune

来源:https://github.com/adrienthebo/git-tools/blob/master/git-truncate

说明:

    将上述脚本保存到本地存储库根目录(可能为git-truncate.sh)。 查看您要截断的分支(可能是master)。 查看历史记录并找到您要切断的第一个(最新)提交 SHA(假设它是 2c75a32)并确保提交没有并行分支! 像这样运行它:$ ./git-truncate.sh 2c75a32 master。 (推力,如果有任何遥控器。)

重要提示:SHA 必须是分支的“一部分”,并且它必须是您要删除的第一个提交。不要通过您要保留的第一个提交(新的“存储库开始”提交)!

【讨论】:

以上是关于如何删除旧的 git 历史记录?的主要内容,如果未能解决你的问题,请参考以下文章

从旧的 Git 提交中删除私有信息

如何从 Git 历史记录中永久删除提交?

如何在选定点之前删除 git 历史记录

如何执行 git revert 并删除合并历史记录?

如何删除 Git 仓库中的历史提交记录

git删除所有提交历史记录