web-dev-qa-db-ja.com

gitリポジトリから古い履歴を削除するにはどうすればよいですか?

私はこの特定のシナリオのようなものを見つけることができなかったのではないかと心配しています。

2007年半ばまでさかのぼる500以上のブランチ、500以上のタグなど、多くの歴史を持つgitリポジトリがあります。 〜19,500件のコミットが含まれています。 2010年1月1日より前にすべての履歴を削除して、より小さく簡単に処理できるようにします(履歴の完全なコピーをアーカイブリポジトリに保持します)。

私は新しいリポジトリのルートになりたいコミットを知っています。ただし、そのコミットで開始するためにレポジトリを切り捨てる正しいgit mojoを見つけることはできません。私はいくつかのバリアントを推測しています

git filter-branch

グラフトを含む必要があります。また、別々に保持したい200以上のブランチのそれぞれを処理してから、レポにパッチを適用する必要があるかもしれません(何かdo方法を知っています)。

誰かがこのようなことをしたことがありますか?それが重要な場合、git 1.7.2.3があります。

182
ebneter

新しいルートコミットの親の 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 <[email protected]>
Date:   Fri May 24 14:04:10 2013 +0200

    Another message

commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted)
Author: Your Name <[email protected]>
Date:   Thu May 23 22:27:48 2013 +0200

    Some message

すべてが意図したとおりに見える場合は、単純なgit filter-branch -- --allを実行するだけで永続化できます。

BEWARE:filter-branchステップを実行した後、すべてのコミットIDが変更されるため、古いリポジトリを使用しているユーザーは、新しいリポジトリを使用しているユーザーレポ。

107
apenwarr

返信を投稿するのは遅すぎるかもしれませんが、このページはGoogleの最初の結果であるため、引き続き役立つ場合があります。

Gitリポジトリの一部の領域を解放したいが、すべてのコミット(リベースまたはグラフト)を再構築したくないが、それでも完全なリポジトリを持っている人からプッシュ/プル/マージできる場合は、- git cloneshallowclone(-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の古いバージョンは、浅いレポジトリからのクローン/プッシュ/プルをサポートしていませんでした。

89
Alexandre T.

この 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の回答が大幅に変更されたため、編集が拒否されたため、ここに情報があります!

55
Chris Maes

この方法を試してください 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実装は完全ではないことに注意してください。それを使用する場合、結果を手動で検査します。

48
yoyodyn

履歴を書き換える代わりに、 git replace のように Pro Git本の記事 =。ここで説明する例では、親のコミットを置き換えてツリーの開始をシミュレートしますが、完全な履歴を保持するための別個のブランチとして保持します。

32
Jeff Bowman

keepにしたい場合は、upstreamリポジトリを完全な履歴が、ローカルの小さなチェックアウトは、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の変更後のリモート拒否(浅い更新は許可されません) を参照してください。そのためには、接ぎ木に固執する必要があります。

21
koppor

私が何をしていたかを理解するために、いくつかの答えと他の情報を読む必要がありました。

1。特定のコミットより古いものをすべて無視する

ファイル.git/info/graftsは、コミットの偽の親を定義できます。コミットIDのみの行は、コミットに親がないことを示しています。直近の2000件のコミットのみに関心があると言いたい場合は、次のように入力できます。

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

git rev-parseは、現在のコミットの2000番目の親のコミットIDを提供します。上記のコマンドは、もしあれば、graftsファイルを上書きします。最初にあるかどうかを確認してください。

2。Git履歴を書き換える(オプション)

この移植された偽の親を実際の親にしたい場合は、次を実行します:

git filter-branch -- --all

すべてのコミットIDが変更されます。このリポジトリのすべてのコピーを強制的に更新する必要があります。

。ディスク領域のクリーンアップ

私は自分のコピーがアップストリームとの互換性を保ちたいので、ステップ2はしませんでした。ディスクスペースを節約したかっただけです。古いコミットをすべて忘れるには:

git Prune
git gc

代替:浅いコピー

別のリポジトリの浅いコピーがあり、ディスク領域を節約したい場合は、.git/shallowを更新できます。ただし、以前のコミットを指すものが何もないことに注意してください。したがって、次のようなものを実行できます。

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

浅い部分のエントリは、移植片のように機能します。ただし、移植片と浅瀬を同時に使用しないように注意してください。少なくとも、そこに同じエントリがないと、失敗します。

古いコミットを指す古い参照(タグ、ブランチ、リモートヘッド)がまだある場合、それらはクリーンアップされず、ディスクスペースを節約できません。

15
Maikel

rebaseまたはPushto 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ダッシュボードでこの問題を解決するには、「保護されたブランチ」からmasterブランチを削除する必要があります

enter image description here

その後、このコマンドを実行できます

git Push -f Origin master

または

git rebase --onto temp $1 master
2
HMagdy