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

How to delete the old git history?

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

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

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

怎么做?

为了不丢失一些历史;最好先复制您的存储库 :)。我们开始:(<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

如果您有一个遥控器,您希望在其中拥有相同的 t运行 分类历史记录;你可以使用 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 clone using the --shallow-since option. If there is only a small number of commits since f and there is no trouble counting them then you can use the --depth 选项为您的问题提供了可能的解决方案。

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

当您对结果感到满意时,删除旧存储库并重命名新存储库以替换它。如果旧存储库是远程的,那么 re-create 删除后将其从新存储库推送到其中。

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

对于那些与 rebase --onto 有很多合并冲突(和损坏的结果)的人,我想推荐这个使用 git filter-branch:

的脚本
#!/bin/sh

cut_sha=""
branch=""

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

说明:

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

重要提示:SHA 必须是分支的 "part",并且它必须是您要删除的第一个提交。不要通过您要保留的第一个提交(新的 "beginning of repository" 提交)!