上流のプロジェクトフォースがマスターにプッシュされた後、どうすればgitサブツリーを修正できますか?


13

私はgitサブツリーを使用して実験しており、次の状況に遭遇しました。

私はgitサブツリーを使用して外部プロジェクトをリポに追加しました。プロジェクトの履歴を参照したり、後で上流プロジェクトに貢献したりするために、上流プロジェクトのすべての履歴を意図的に保持しました。

結局のところ、上流プロジェクトの別の貢献者が誤って大きなファイルをマスターブランチにプッシュしました。これを修正するために、上流プロジェクトは履歴を書き直し、強制的にマスターにプッシュしました。「monorepo」を作成するときに、このコミットを含めたので、それも削除したいと思います。

サブツリーの新しい履歴を反映するようにリポジトリを更新するにはどうすればよいですか?

私の最初の試みは、フィルターブランチを使用して、サブツリーとすべての履歴を完全に削除することでした。

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

古いバージョンのサブツリーが削除されたら、新しいアップストリームマスターを使用してサブツリーを再度追加できます。ただし、何らかの理由でコミット履歴がまだgitログ出力に表示されているため、これは機能しませんでした。

更新

最小限の再現可能な例を作成するための手順を書きました。

  1. 最初に空のgitリポジトリを作成します。

    git init test-monorepo
    cd ./test-monorepo
    
  2. 初期コミットを作成します。

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. 次に、外部プロジェクトのサブツリーを追加します。

    git remote add thirdparty git@github.com:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. monorepoにいくつかのコミットをします

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. 次に、git filter-branchを使用してサブツリーを削除してみます。

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. git logの出力を調べます。最初のコミットのみが表示されることを期待しています。

    git log
    

古いコミットを破棄するためにgit gc --prune = nowを試みましたか?古いバージョンのコミットへの参照はありますか?
Damiano

1
私はまだこれを試していませんが、git gc --prune=now表示されないコミットを削除するだけではありませんgit logか?
csnate

git branch -all(「古い」コミットの表示に使用していると思います)を使用すると、現在のブランチに関係のないコミットも表示されます。
ダミアーノ

1
実は、私はやっていなかったgit log、引数を、私はまだ古いコミットを参照してください。
csnate

git log --pretty --all --graphを投稿できますか?ちょうどあなたの状況を理解するには
ダミアーノ

回答:


0

あなたはすでにあなたの歴史の中で悪いコミットを得ており、続行する前にそれを取り除く必要があります

あなたが得たと仮定しましょうmaster(私が開始する何かを想定する必要があるので、私は本当に、一目であなたの枝を持っていない)最後の転用コミットして何もすることができていません

前のコミットにチェックアウトして、ブランチマーカーを1ステップ後退(またはXステップ後退)できます。これは、いずれの場合も無害であり、再度プルします。

例えば

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 マスターの親コミットをチェックアウトするために、gitはブランチから離れていることを警告します
  2. git branch master -f 現在のチェックアウトを再びマスターにすることを強制します。つまり、実際にマスターブランチを以前のコミット(またはX以前のコミット)に巻き戻します。ここから、アップストリームが強制したかどうかは関係ありません。通常に再開できます。必要に応じて上記の手順に戻り、上流から何も失うことなく、マスターを再度プルすることだけができます(これも読み取り専用である可能性があるため、このために何もプッシュしません)。
  3. git checkout master 私たちの「巻き戻し」マスターブランチになるために、私たちが踏んでいるのと同じコミットですが、代わりにブランチにいます
  4. git pullマスターを再度プルする(の有無にかかわらず--prune)、アップストリームが迂回された場合、ここからトラックに戻ります。そうでない場合は、同じであり、同じであり、想定されていなかった場合、おそらく上記の最初のステップに戻り、より多くのコミットを巻き戻すgit checkout master~5必要があります。

私はこれがうまくいくとは思いませんgit subtree
csnate

@csnateでは、サブリポジトリから以前のコミットをチェックアウトして、非常によく似た手順に従うことができます。MCVEを構築すると、stackoverflow.com
help / minimal

GitHubでサンプルリポジトリを作成してみます。
csnate

元の質問に問題を示す一連の手順を作成しました。
csnate

0
  1. リポジトリで、このリモートのコミットの履歴をクリーンアップします。

    git fetch upstream
    
  2. 自分のコミットの1つに大きなファイルを含むコミットがある場合は、この大きなファイルが参照されないように履歴を書き直してください

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

これらの2つのステップにより、大きなファイルはリポジトリ内のコミットによって参照されなくなります。
さらに、ある時点でgitがガベージコレクターを実行し、ダブリングブロブの有効期限の遅延に達したときに、ハードドライブから削除されます。


この大きなファイルをハードドライブからできるだけ早く削除する必要がある場合:

手動で実行

git gc --prune=now
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.