如何从git存储库中删除旧历史记录?

时间:2010-12-23 03:07:31

标签: git git-filter-branch

恐怕我找不到任何类似这种特殊情况的东西。

我有一个有很多历史的git存储库:500多个分支,500多个标签,可以追溯到2007年中期。它包含~19,500次提交。我们想在2010年1月1日之前删除所有历史记录,以使其更小更容易处理(我们会在存档库中保留历史记录的完整副本)。

我知道我想要成为新存储库的根目录的提交。但是,我不能找出正确的git mojo来截断repo以从那个提交开始。我猜是

的一些变种
git filter-branch

涉及移植物是必要的;也许有必要对待我们想要单独保留的200多个分支中的每一个,然后将回购补丁(我知道该怎么做)。

有没有人做过这样的事情?如果重要的话,我有git 1.7.2.3。

11 个答案:

答案 0 :(得分:102)

只需将新的根提交的父级graft创建为无父级(或空提交,例如存储库的真正根提交)。例如。 echo "<NEW-ROOT-SHA1>" > .git/info/grafts

创建移植后,立即生效;您应该能够查看git log并看到不需要的旧提交已经消失:

$ echo 4a46bc886318679d8b15e05aea40b83ff6c3bd47 > .git/info/grafts
$ git log --decorate | tail --lines=11
commit cb3da2d4d8c3378919844b29e815bfd5fdc0210c
Author: Your Name <your.email@example.com>
Date:   Fri May 24 14:04:10 2013 +0200

    Another message

commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted)
Author: Your Name <your.email@example.com>
Date:   Thu May 23 22:27:48 2013 +0200

    Some message

如果所有内容都符合预期,您只需执行一个简单的git filter-branch -- --all即可使其永久化。

执行 filter-branch 步骤后,

请注意:所有提交ID都已更改,因此使用旧repo的任何人都不得与使用新repo的任何人合并。

答案 1 :(得分:83)

发布回复可能为时已晚,但由于此页面是Google的第一个结果,它可能仍然有用。

如果您想在git仓库中释放一些空间,但又不想重建所有提交(rebase或者贪污),并且仍然能够从拥有完整仓库的人推/拉/合并,您可以使用git clone 克隆( - 深度参数)。

; Clone the original repo into limitedRepo
git clone file:///path_to/originalRepo limitedRepo --depth=10

; Remove the original repo, to free up some space
rm -rf originalRepo
cd limitedRepo
git remote rm origin

您可以通过以下步骤来浅显现有的回购:

; Shallow to last 5 commits
git rev-parse HEAD~5 > .git/shallow

; Manually remove all other branches, tags and remotes that refers to old commits

; Prune unreachable objects
git fsck --unreachable ; Will show you the list of what will be deleted
git gc --prune=now     ; Will actually delete your data

Ps:旧版本的git不支持克隆/推/拉/从浅层回购。

答案 2 :(得分:53)

这个method很容易理解并且运行正常。脚本($1)的参数是从您希望保留历史记录的提交的引用(标记,哈希,...)。

#!/bin/bash
git checkout --orphan temp $1 # create a new branch without parent history
git commit -m "Truncated history" # create a first commit on this branch
git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch
git branch -D temp # delete the temp branch

# The following 2 commands are optional - they keep your git repo in good shape.
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

注意旧标签仍然存在;所以你可能需要手动删除它们

评论:我知道这与@yoyodin几乎相同,但这里有一些重要的额外命令和信息。我试着编辑答案,但由于@ yoyodin的回答是一个重大变化,我的编辑被拒绝了,所以这里是信息!

答案 3 :(得分:47)

尝试使用此方法How to truncate git history

#!/bin/bash
git checkout --orphan temp $1
git commit -m "Truncated history"
git rebase --onto temp $1 master
git branch -D temp

此处$1是您要保留的提交的SHA-1,脚本将创建包含$1master之间所有提交的新分支,并删除所有旧历史记录。请注意,此简单脚本假定您没有名为temp的现有分支。另请注意,此脚本不会清除旧历史记录的git数据。在确认您确实要丢失所有历史记录后运行git gc --prune=all && git repack -a -f -F -d。您可能还需要rebase --preserve-merges,但要注意该功能的git实现并不完美。如果使用,请手动检查结果。

答案 4 :(得分:32)

作为重写历史记录的替代方法,请考虑在git replace中使用this article from the Pro Git book。讨论的示例涉及替换父提交以模拟树的开头,同时仍将完整历史记录保存为单独的分支以便妥善保管。

答案 5 :(得分:21)

如果您希望保持 上游存储库完整历史记录,但是本地较小的结帐,请使用{{1}进行浅层克隆}。

推送提交后,您可以执行

  1. git clone --depth=1 [repo]修剪旧提交。这使得旧提交及其对象无法访问。
  2. git fetch --depth=1。使所有旧提交及其对象失效
  3. git reflog expire --expire-unreachable=now --all删除旧对象
  4. 另见How to remove local git history after a commit?

    请注意,您无法将此“浅”存储库推送到其他位置:“不允许浅层更新”。见Remote rejected (shallow update not allowed) after changing Git remote URL。如果你想这样做,你必须坚持嫁接。

答案 6 :(得分:13)

我需要阅读几个答案和其他一些信息才能理解我在做什么。

<强> 1。忽略早于某个提交的所有内容

文件.git/info/grafts可以为提交定义假父母。只有一个提交ID的行,表示提交没有父级。如果我们想说我们只关心最近的2000次提交,我们可以输入:

git rev-parse HEAD~2000 > .git/info/grafts

git rev-parse为我们提供了当前提交的第2000个父级的提交ID。如果存在,上面的命令将覆盖移植文件。先检查一下是否存在。

<强> 2。重写Git历史记录(可选)

如果你想让这个嫁接的假父母成为真正的父母,那么运行:

git filter-branch -- --all

它将更改所有提交ID。需要有力地更新此存储库的每个副本。

第3。清理磁盘空间

我没有完成第2步,因为我希望我的副本与上游保持兼容。我只是想节省一些磁盘空间。为了忘记所有旧提交:

git prune
git gc

替代方案:浅色副本

如果您有另一个存储库的浅层副本并且只想保存一些磁盘空间,则可以更新.git/shallow。但要小心,没有任何东西指向之前的提交。所以你可以运行这样的东西:

git fetch --prune
git rev-parse HEAD~2000 > .git/shallow
git prune
git gc

浅入口就像贪污一样。但要注意不要同时使用移植物和浅层。至少,在那里没有相同的条目,它将失败。

如果您仍然有一些旧的引用(标记,分支,远程头)指向较旧的提交,它们将无法清理,您将无法节省更多磁盘空间。

答案 7 :(得分:2)

rebase 推送 head / master 时,可能会发生此错误

remote: GitLab: You are not allowed to access some of the refs!
To git@giturl:main/xyz.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git@giturl:main/xyz.git'

要在git仪表板中解决此问题,请从&#34;受保护的分支&#34;

中删除master分支

enter image description here

然后你可以运行这个命令

git push -f origin master

git rebase --onto temp $1 master

答案 8 :(得分:1)

这里有太多答案不是最新的,有些还不能完全解释后果。这是我使用最新的git 2.26整理历史记录的方法:

首先创建一个虚拟提交。该提交将作为截断的仓库中的第一个提交。您需要这样做,因为此提交将保存您保留的历史记录的所有基本文件。 SHA是您要保留的提交的上一个提交的ID(在本示例中为8365366)。字符串“ Initial”将显示为第一次提交的提交消息。如果您使用的是Windows,请在Git Bash命令提示符下键入以下命令。

# 8365366 is id of parent commit after which you want to preserve history
echo 'Initial' | git commit-tree 8365366^{tree}

以上命令将打印SHA,例如d10f7503bc1ec9d367da15b540887730db862023

现在只需键入:

# d10f750 is commit ID from previous command
git rebase --onto d10f750 8365366

这将首先将所有提交时8365366的文件放入虚拟提交d10f750中。然后它将在d10f750顶部的 之后的 8365366中播放所有提交。最终master分支指针将更新为上一次播放的提交。

现在,如果您想推送这些截断的存储库,只需执行git push -f

要记住的几件事(这些方法适用于其他方法以及此方法):不会传输标签。保留提交ID和时间戳后,您会看到GitHub以一次性Commits on XY date标题的形式显示这些提交。

幸运的是,可以将截断的历史记录保留为“存档”,以后您可以将回切后的存储库与归档存储库一起加入。为此,请参见this guide

答案 9 :(得分:-2)

您可以使用下面提到的jar [下载]和命令删除目录,文件以及与目录或文件相关的整个历史记录

bfg.jar文件: https://rtyley.github.io/bfg-repo-cleaner/

git clone --bare repo-url cd repo_dir java -jar bfg.jar --delete-folders folder_name git reflog expire --expire = now --all&amp;&amp; git gc --prune = now --aggressive git push --mirror repo_url

答案 10 :(得分:-10)

  1. 删除git数据,rm .git
  2. git init
  3. 添加一个git remote
  4. 强制推送
相关问题