スタッシュバッグ
救われたのは、私が「スタッシュバッグ」git stash
と呼んでいるものです。これは、「インデックス」コミット (ステージング領域) と「作業ツリー」コミットの 2 つの個別のコミットで構成されます。ワークツリー コミットは面白い種類のマージ コミットです。
適切に説明するために、ここでこれをもう一度描いてみましょう (はるかに長いバージョンについては、参照されている回答を参照してください)。簡単にするために、1 つのブランチと 3 つのコミットしかない小さなレポがあるとしA
ますC
。あなたは1つのブランチにいて、いくつかの変更を加えてから実行しますgit stash save
(または単にプレーンですgit stash
)。これはあなたが得るものです:
A - B - C <-- HEAD=master
|\
i-w <-- the "stash"
ここで、別のブランチを作成 (または別のブランチに切り替える) ことができますが、説明のために、そのスタッシュをそこに残し、より「通常の」コミットを行うとしましょうmaster
:
A - B - C - D - E <-- HEAD=master
|\
i-w <-- stash
ここでのポイントは、i
ndex とw
ork-tree のコミットのペアである「stash-bag」が、以前と同じコミットにまだ掛けられているということです。コミットは変更できません。これは stash-bag コミットにも当てはまります。
しかし、ここで、いくつかの変更を加えて (まだ on の状態で)、再度実行することで、新しいスタッシュを作成します。master
git stash save
古い収納袋はどうなりますか?「参照名」2は、 新しいstash-bagstash
を指すようになりました。しかし、古い隠し袋のコミットはまだそこにあります。「reflog」スタイル名が必要になりました。3stash@{1}
とにかく、あなたが今持っているのはこれです:
A - B - C - D - E <-- HEAD=master
|\ |\
i-w i-w <-- stash
.
-------------- stash@{1}
( を使用するgit stash drop
と、stash スクリプトは ref の reflog を操作して、ドロップされたstash
stash-bag の ID を削除するだけです。そのため、すべての「より高い」ものに番号が付け直されます。実際の stash-bag 自体は、次の でガベージ コレクションされgit gc
ます。 )
この次のビットは、何が起こっているのかを理解するための鍵です。
git が特定のコミットに名前を付ける必要があるときはいつでも、さまざまな方法でそれを行うことができます。
各コミットには「本当の名前」があります。これは、ご覧のとおり、大きく醜い SHA-1 ハッシュで、値は676699a0e0cdfd97521f3524c763222f1c30a094
. あなたはそれを書くことができます。常に同じコミットを意味します。コミットは決して変更できず、それはコミットの内容全体の暗号化ハッシュであるため、その特定のコミットが存在する場合、その値は常にその名前になります。
しかし、それは人々にとって良い名前ではありません。したがって、エイリアスがあります。ブランチ名やタグ名、 や などの相対名、HEAD
やHEAD~2
などの reflog スタイルの名前などHEAD@{yesterday}
ですmaster@{1}
。git rev-parse
(このような名前文字列をハッシュ値に変換するコマンド , があります。試してみてください: run git rev-parse HEAD
、git rev-parse stash
など。git のほとんどのものはgit rev-parse
、git rev-list
名前を SHA- 1 つの値。)
(リビジョンの命名方法の完全な説明については、gitrevisionsを参照してください。Gitはコミット以外にも SHA-1 を使用しますが、ここではコミットについて考えてみましょう。)
Git stash show、git show、および git diff
git show
OK、ついに、あなたのvsgit stash show
にたどり着くことができますgit diff
。これは、スタッシュで使用することになっgit stash show
ているものなので、最初に取り組みましょう。さらに、サブコマンドは、名前を付けたコミット (または、名前を付けなかった場合は、参照を介して見つかったコミット) が隠し場所のように見えること、つまり、これらの面白いマージ コミットの 1 つであることを確認します。git stash
stash
を実行するgit stash show -p
と、git は差分 ( -p
atch) を表示します。しかし、それは正確に何を示していますか?
隠し袋のある図に戻ります。各 stash-bag は、特定のコミットにぶら下がっています。上記の「メイン」スタッシュは commit からぶら下がりE
、stash@{1}
以前のスタッシュは からぶら下がっていC
ます。
何をするかgit stash show -p
というと、そのスタッシュの作業ツリー コミットでw
ある を、スタッシュがハングするコミットと比較します。4
もちろん、これは自分で行うことができます。commit をぶら下げているw
inと、 branch-name で名前を付けることができるcommitを比較したいとしましょう。したがって、次を実行できます。ここで、名前は (現在の) stash commitを参照し、 commitを参照するため、これは とまったく同じパッチを生成します。(そして、 inと commitを比較したい場合は、これら 2 つのコミットに名前を付けるように実行するだけで済みます。もちろん、単に.stash
E
E
master
git diff master stash
stash
w
master
E
git stash show -p stash
w
stash@{1}
C
git diff
git stash show -p stash@{1}
プレーンはgit show
どうですか?これはもう少し複雑です。 git show
コミットを喜んで表示し、参照を与えましたstash
(stash
それ自体、または reflog バリアントのいずれか)。これは有効なコミット ID でありw
、stash-bags の 1 つの作業ツリー コミットの 1 つに解決されます。ただし、マージコミットが表示git show
されると、動作が異なります。ドキュメントが言うように:
また、 によって作成された特別な形式でマージ コミットを表示しgit diff-tree --cc
ます。
コミットがコミットとの通常のマージであるとgit show stash@{1}
仮定すると、「結合された差分」が表示されます。結局のところ、これは通常のマージではありませんが、何を見ているかを知っていれば、結合された diffが実際に役立つ場合があります。以下のドキュメントを読んで、それがどのように機能するかを詳細に確認してください。w
C
i
w
--cc
git diff-tree
--cc
-c
... すべての親から変更されたファイルのみを一覧表示します。
の場合、 を実行する前にファイルを編集したstash
場合、-vs- diff が空になると、これらのファイルは出力に表示されません。git add
git stash
i
w
最後に、これは異なるork-tree コミットを比較するgit diff stash@{M} stash@{N}
よう求めているだけです。それがどれほどの意味を持つかは、比較対象によって異なります。これは、通常、スタッシュ バッグが取り付けられている場所によって異なります。git diff
w
1本当は 2 つまたは 3 つですが、2 つとして描きます。git stash save
(またはプレーンgit stash
、つまり) で2 つのコミットを取得しますgit stash save
。-u
または-a
オプションを追加して追跡されていないファイルまたはすべてのファイルを保存すると、3 つのコミットが得られます。これは stash の復元に影響しますが、git stash show
コマンドからの出力には影響しません。
2「参照名」は単なる名前であり、ブランチ名やタグ名のようなものです。参照名には多くの形式があります。ブランチとタグは、特別な目的を持つ単なる名前です。「リモート ブランチ」はこれらの参照の別の形式であり、「スタッシュ」も参照です。
実際、これは非常に特別なリファレンスHEAD
ではありますが、別のリファレンスにすぎません。ファイルを削除すると、git はリポジトリがもはやリポジトリではないと判断することは非常に重要です。HEAD
いくつかの特殊な例外 (<code>HEAD、ORIG_HEAD
、MERGE_HEAD
など) を除いて、参照はすべて文字列 で始まりますrefs/
。ブランチは で始まりrefs/heads/
、タグは で始まりrefs/tags/
、「リモート ブランチ」は で始まりrefs/remotes/
ます。言い換えれば、参照には「名前空間」があり、通常は名前空間で始まり、refs/
その下に別の単語を取得して、それらがどこにあるかを識別します。
stash 参照は綴られていますrefs/stash
(そしてそこで止まりrefs/stash/jimmy_kimmel
ます。何もないか、そのようなものはありません)。
3実際、これは実際に reflog を使用しています。これは、とりわけ、「メイン」のもの以外のスタッシュが期限切れrefs/stash
になる可能性があることを意味します。(幸いなことに、musiphil が指摘しているように、git 1.6.0 以降のデフォルトでは、これらは期限切れになりません。これを実現するには、有効期限を設定する必要があります。これは、おそらくあなたが望むものではありません。)
4接尾辞表記を使用してこれを行う巧妙な方法は、私の他の回答で詳しく説明されています。^
5i
これらの stash バッグの ndex-commitを見たい場合はどうしますか? あ、いい質問です!:-) stash スクリプトには適切な答えがありません。これらを確認する簡単な方法は、^2
サフィックスを使用して、各スタッシュの 2 番目の親 (i
コミット) に名前を付けることです。そして、追跡されていないファイルまたはすべてのファイルを含む 3 番目のコミットを含むスタッシュがある場合、それが 3 番目の親です。コミットw
は 3 つの親のマージのように見え、3 番目の親に到達しますstash^3
。ただしw
、これは通常のマージではないため、注意が必要です。おそらく、stash のすべての部分を確認する最も簡単な方法は、git stash branch
.