私はこれと同じ不可解な質問に出くわしました。一連のシーケンシャルコミットからの変更を1つのコミットに変換したかったのですが、一連のスカッシュでインタラクティブなリベースを使用すると、マージの競合が発生し、イライラしていました。少し前のことで、今は最小限の例で再現することができませんでした。いずれにせよ、私はそれを解決する方法を知っているので、ここに行きます:
投稿で求められたことを実行する2つの異なる方法を紹介します。1つは、実行していることを正確に明確にするため、不格好ですが「怖くない」方法です。もう1つは、エレガントでgit
コマンドのみを使用するが、git
もう少しあなたの理解を信頼するために。
設定
idA
初期状態としてコミットIDがidB
あり、最終状態としてコミットIDがあり、その間に他のコミットがたくさんあるとします。中間のコミットをすべて潰したいという事実は、初期状態から最終状態にどのように移行したかを気にしないことを意味します。つまり、ポイントからポイントに移動するコミットが必要なだけidA
ですidB
。
idB
それが現在に対応していると仮定してHEAD
、それがあなたのmaster
ブランチでもあるとしましょう。squashed
と同じ作業ツリーの内容をmaster
持つが、コミットIDの後にコミットが1つしかない、という新しいブランチを作成しますidA
。
解決策1
git checkout master
(すでにオンになっている可能性がありますmaster
)
bash
またはファイルエクスプローラーを使用して、作業ツリー全体を別の場所にコピーします。ディレクトリを省略してください.git
。これは、ほとんどのオペレーティングシステムのデフォルトの動作です。したがって、明確にするために、リポジトリフォルダを開き、すべてを選択し、コピーして、デスクトップまたは任意の場所にある新しいフォルダに貼り付けます。
git checkout -b squashed idA
squashed
最新のコミットとしてで呼び出される新しいブランチを作成idA
し、それを現在のブランチにします。
- (ステップ2で別の場所に置いた)内容をリポジトリフォルダーに貼り付け
master
ます。ファイルエクスプローラーから要求された場合は、変更されたすべてのファイルを置き換えるように指示します。
- リポジトリのトップレベルで、
git add .
次にgit commit
。新しいコミットには、からidA
に移行するすべての変更が含まれますidB
。
解決策2
git branch squashed idA # make a new branch called `squash` with `idA` as its latest commit
git checkout master # master is "idB" in this case.
git symbolic-ref HEAD refs/heads/squashed
git commit
そして、voilà。symbolic-ref
HEADをブランチの先端に移動するために使用するsquash
と、作業ツリーの状態と新しいHEADの場所との間の一連の差分が計算されてステージングされます。
git
これは「危険な」「低レベル」のハッキングであるとの懸念に応えたいと思います。それがどのように機能するかについて、あなたが安心できるように十分に説明しようと思います。あなたの.git
フォルダは、バージョン管理されたすべてのファイルの内容が存在する場所です。その中の2つのフォルダーは、、objects
およびrefs
です。このrefs
フォルダーには、ブランチの名前とそれに対応するコミットをgitに通知するファイルが含まれています。.git/refs/heads/master
したがって、たとえばを開くと、への最新のコミットのコミットIDが表示されmaster
ます。このobjects
フォルダーには、2文字の16進名を持つサブフォルダーにある一連のファイルが含まれています。オブジェクトは、パッチ、コミット、ファイル全体など、いくつかの異なるものにすることができます。.git
また、フォルダの最上位にはindex
ファイルがあります。これは、インデックスファイルの内容に関するすばらしい投稿です。現在の議論で知っておく必要があるのは、インデックスファイルがobjects
、現在のブランチとコミットの各ファイルの最新のコミットされたバージョンに対応するオブジェクト(フォルダー内)を示していることです。
そのような背景に対して、ソリューションの機能は次のとおりです。symbolic-ref
コマンドは、作業ツリーに触れることなく、ブランチではなくブランチにgit
いることを「突然」通知します。つまり、あなたのファイルはすべてあなたが知っていて愛している状態に対応していますが、これはコミットされていない変更の束と同じように見えます(つまり、ファイルはすべてのファイルの現在チェックアウトされたバージョンがのバージョンであることを指定します、そしてこれは作業ツリーの変更が測定される基準です)。実際、あなたを状態に導く正確な変化。これはまさにソリューション1が行うことです。この場合、方法のためsquash
master
master
git
idA
index
idA
idB
symbolic-ref
が実装されている場合、前述の変更はすべてすでにステージングされている(つまりgit add
、-ed)ので、実行する必要があるのはですgit commit
。これについては「危険」なことは何もありません。なぜなら、それは変化しないか、追跡しているmaster
もののいずれかだからです。というフォルダに新しいファイルを作成し、その新しい結合されたコミットに対応するフォルダに1つの新しいファイルを作成しました。あなたはあなたがそれを残したところにすぐそこにいます、あなたは同じ内容でより短いコミット履歴で呼び出された新しいブランチを持っています。何が起こっているのかわからない場合は、できるので安心してください。そのままにしておくとすぐに表示されます。objects
git
refs
squashed
objects
master
squashed
git checkout master
squashed
あなたがあなたの新しいものとして採用したいならmaster
、あなたは先に進んでそして
git branch -m master old-master
git branch -m squashed master
そして、すべての不要なコミットがとして保存された古いブランチが作成されold-master
、必要master
なものになります。
お役に立てれば!