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

问题描述 投票:0回答:5

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

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

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

如何做?

git git-rewrite-history
5个回答
62
投票

为了不丢失一些历史;最好先获取您的存储库的副本:)。我们开始吧:(

<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

21
投票

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

第二个选项 (

--depth
) 仅克隆指定的分支。如果您需要其他分支,您可以将原始存储库添加为远程并使用
git fetch
并检索它们。

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

这种方法具有规模和速度的优势。新的存储库仅包含您想要的提交,无需运行

git prune
git gc
来删除旧对象(因为它们不存在)。


4
投票

对于那些使用

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

使用说明:

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

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


2
投票

无需变基,来自此链接

    git checkout --orphan tmp-master # create a temporary branch
    git add -A  # Add all files and commit them
    git commit -m 'Add files'
    git branch -D master # Deletes the master branch
    git branch -m master # Rename the current branch to master
    git push -f origin master # Force push master branch to Git server

清理仓库:

# Local master tracks origin/master
git branch --set-upstream-to=origin/master master 
git gc --aggressive --prune=all # remove the old files

1
投票

回想一下,Git 提交是一个快照。快照是独立的;它 不需要父母提供任何信息。说到父母,这些 快照链接到零个或多个父级。并且根提交没有 父母。

如果您希望存储库从提交开始

f
那么您可以更改 提交(使用 git-replace(1))有 no 父母。

git replace --graft f

现在

f
(通过其替换引用)将没有父母。 [1]

如果您想让此更改永久存在,那么您需要重写 整个历史从

f
开始。您可以使用第三方工具来完成此操作 git-filter-repo(1)。 [2]

(请注意,以下命令(带有

--force
)应被视为not 是您可以撤消的操作 - 确保它是您想要的。)

git filter-repo --force

注释

  1. git(1) 默认情况下尊重这些替换。使用
    --no-replace-objects
    作为
    git
    的参数,以便不使用它们,例如
    git --no-replace-objects log
  2. 已弃用的内置 git-filter-branch(1) 提到这是一个 替代方案
© www.soinside.com 2019 - 2024. All rights reserved.