簡體   English   中英

如何從 git 存儲庫中刪除舊歷史記錄?

[英]How do I remove the old history from a git repository?

恐怕我找不到像這種特殊情況的任何東西。

我有一個 git 存儲庫,它有很多歷史:500 多個分支,500 多個標簽,可以追溯到 2007 年中期。 它包含約 19,500 次提交。 我們希望刪除 2010 年 1 月 1 日之前的所有歷史記錄,以使其更小且更易於處理(我們會將歷史記錄的完整副本保存在存檔存儲庫中)。

我知道我想要成為新存儲庫根的提交。 但是,我無法找出正確的 git mojo 來截斷 repo 以從該提交開始。 我猜一些變種

git filter-branch

涉及移植物是必要的; 可能還需要分別處理我們想要單獨保留的 200 多個分支中的每一個,然后將 repo 修補在一起(我確實知道該怎么做)。

有沒有人做過這樣的事情? 如果重要的話,我有 git 1.7.2.3。

也許現在回復已經太晚了,但由於這個頁面是 Google 的第一個結果,所以它可能仍然有幫助。

如果您想釋放 git 倉庫中的一些空間,但不想重建所有提交(rebase 或嫁接),並且仍然能夠從擁有完整倉庫的人那里推/拉/合並,您可以使用git克隆克隆( --depth參數)。

; 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

如何刪除所有 git 本地標簽?

Ps:舊版本的 git 不支持從/到淺存儲庫的克隆/推/拉。

只需將您的新根提交的父項移植到無父項(或空提交,例如存儲庫的真正根提交)。 例如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 都將發生變化,因此使用舊倉庫的任何人都不得與使用新倉庫的任何人合並。

這種方法很容易理解並且效果很好。 腳本 ( $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 答案的重大更改,我的編輯被拒絕了,所以這里是信息!

試試這個方法如何截斷git歷史

#!/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 實現並不完美。 如果您使用它,請手動檢查結果。

作為重寫歷史的替代方法,請考慮使用git replacePro Git book中的這篇文章中所述 所討論的示例涉及替換父提交以模擬樹的開始,同時仍將完整歷史記錄作為單獨的分支進行保管。

如果您想保留具有完整歷史記錄上游存儲庫,但要保留本地較小的結帳,請使用git clone --depth=1 [repo]進行淺克隆。

推送提交后,您可以執行

  1. git fetch --depth=1修剪舊提交。 這使得舊的提交及其對象無法訪問。
  2. git reflog expire --expire-unreachable=now --all 使所有舊提交及其對象過期
  3. git gc --aggressive --prune=all刪除舊對象

另請參閱如何在提交后刪除本地 git 歷史記錄? .

請注意,您不能將此“淺”存儲庫推送到其他地方:“不允許淺更新”。 請參閱更改 Git 遠程 URL 后遠程被拒絕(不允許淺更新) 如果你想這樣做,你必須堅持嫁接。

我需要閱讀幾個答案和一些其他信息來了解我在做什么。

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

淺層的進入就像嫁接一樣。 但注意不要同時使用嫁接和淺層。 至少,那里沒有相同的條目,它會失敗。

如果您仍有一些指向舊提交的舊引用(標簽、分支、遠程頭),它們將不會被清除,您也不會節省更多磁盤空間。

rebasepush to 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 儀表板中解決此問題,應從“受保護的分支”中刪除主分支

在此處輸入圖片說明

然后你可以運行這個命令

git push -f origin master

要么

git rebase --onto temp $1 master

這里有太多不是最新的答案,有些沒有完全解釋后果。 以下是使用最新的 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 然后,它會8365366回放所有提交過頂d10f750 最后master分支指針將更新為最后一次提交回放。

現在,如果您想推送這些截斷的 repo,只需執行git push -f

需要記住的幾件事(這些也適用於其他方法以及本方法): 標簽不會被轉移。 在保留提交 ID 和時間戳的同時,您將看到 GitHub 將這些提交顯示在像 Commits Commits on XY date這樣的一次性標題中。

幸運的是,可以將截斷的歷史記錄保留為“存檔”,稍后您可以將修剪過的 repo 與存檔 repo 結合起來。 為此,請參閱本指南

對於先前使用--depth克隆的現有存儲庫

git clone --depth=1 ...

做就是了

git pull --depth=1 --update-shallow

https://git-scm.com/docs/git-pull

在我的情況下,我想將一個存儲庫一分為二,保留歷史記錄,但從過濾掉新存儲庫的文件中清理日志歷史記錄。

這是解決方案:

PATHS=path_a path_b
git filter-branch -f --prune-empty --index-filter "git read-tree --empty                                                                                    
git reset \$GIT_COMMIT -- $PATHS " -- --all -- $PATHS

通過這種方式,我得到了一個包含完整提交日志歷史記錄的新倉庫,但僅限於我想要保留的路徑;

參考: https://stackoverflow.com/a/56334887/2397613

根據 BFG 工具的 Git 存儲庫,它“像 git-filter-branch 一樣刪除大的或麻煩的 blob,但速度更快——並且是用 Scala 編寫的”。

https://github.com/rtyley/bfg-repo-cleaner

  1. 刪除 git 數據,rm .git
  2. git初始化
  3. 添加一個 git 遙控器
  4. 強推

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM