これはすでに回答されているようですが、もう少し追加させてください。警告: にバグレットがありgit stashます。
git stashを使用せずにor git stash save(デフォルトではsaveこれらは同じものです) を実行する-pと、stashスクリプトはgit-coreディレクトリに存在し、その場所は git のインストールによって異なり/usr/libexec/git-coreます/usr/local/libexec/git-core。または場合によっては 3) 親コミット。順番に、これらのコミットは次のとおりです。
- 現在のインデックス
-uまたは、追跡されて-aいないファイル、さらには無視されたファイル(およびgit clean作業ディレクトリからそれらを捨てるためにも使用されます)
- 現在の作業ディレクトリと
HEADコミットの間の差分に基づく作業ディレクトリ (これがバグレットのソースです。以下を参照してください)。
refs/stash次に、これらのコミットの最後の作業ディレクトリ コミットを指すように設定します。このコミットの親は次のとおりです。
stash^(最初の親)としての HEAD コミット
stash^2(2 番目の親)としてのインデックス コミット
- 未追跡/無視されたコミット
stash^3(存在する場合) (3 番目の親)。
このスタッシュには、実際には、スタッシュ時に配置されていたすべてが含まれていますが、「スタッシュ前の状態」を使用git stash pop --indexまたは復元する場合に、バグレットが最もよく表示されます。git stash apply --index(git stash apply以下でpopは のみを使用しますが、applyその後に . が続きdropます。)
さて、あなたが指摘したように、実行する前にいくつかのことを慎重にステージングしたとしても、git stash apply実行すると多くのファイルが得られます。これは、別のブランチなどをチェックアウトした場合や、実行前にいくつかのファイルをステージングした場合など、作業ディレクトリの状態に関係なく、このようにこれらの変更をマージする方がはるかに簡単だからです。(実際には、git のマージ コードを使用して作業ディレクトリの変更を取り込みます。)changes not staged for commitgit stash savegit stash applygit stash apply
git stash apply --indexただし、を実行するとstash、スクリプトは最初に、元の. (まだ何もステージングされていない場合は、元の状態に戻ります。) それができると仮定して、同様に (再びマージ メカニズムを使用して) 作業ディレクトリを設定しようとします。インデックスを適切に設定できない場合は、インデックスに対して何もせず、 なしで再試行することを提案します。save--index
ここで、バグレットの出番です。たとえば、basefile何も変更していない というファイルから始めるとします。変更を加えて、これをステージングします。
$ cat basefile
base
$ git status --short
$ echo add to basefile >> basefile; git add basefile
しかし、作業ディレクトリのコピーにHEADリビジョンからの変更を加えないようにすることにしました。
$ ed basefile
21
2d
w
5
q
$ git status --short
MM basefile
ここで注意が必要な点は、インデックスで変更され、次に work-dir で再度変更されることですが、2 回目の変更でコミットbasefileの内容に戻ります。HEADを実行するgit stash saveと、stash スクリプトは誤ってインデックスバージョンを進行中のバージョンであるかのように記録します。
ここで agit stash apply --indexを実行すると、次のようになりますgit status --short。
$ git stash save
Saved working directory and index state WIP on master: 94824e1 initial
HEAD is now at 94824e1 initial
stash created
$ git stash apply --index
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: basefile
#
$ git status --short
M basefile
ここで、git はインデックスのバージョンをインデックスに復元し、作業ディレクトリのバージョンをインデックスのバージョンと同じものに設定しています。
$ cat basefile
base
add to basefile
stash スクリプトの修正は一言だけの変更ですが、今のところ誰も気に入っていないようです。おそらく問題は、stashを なし --indexで適用すると、インデックスの変更 (余分な行add to basefile) が何もないものと効果的に結合されるため、work-directory バージョンに余分な行が含まれることです。ただし、インデックスと作業ディレクトリの両方のバージョンが異なる場合の動作とは一致しません。
$ git stash drop
Dropped refs/stash@{0} (61c83c866bc522c58df62320b77e647ffd28aa95)
$ echo base > basefile
$ git status --short
$ echo add to basefile >> basefile
$ git add basefile
$ ed basefile
21
2c
different change
w
22
q
$ git status --short
MM basefile
$ git stash save
Saved working directory and index state WIP on master: 94824e1 initial
HEAD is now at 94824e1 initial
$ git stash apply
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: basefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$ cat basefile
base
different change
ここでは、インデックスとワーク ツリーの変更を「一緒につぶす」ことによって変更しますが、適用せずに適用すると、ワーク ツリーの変更のみ--indexが回復されます。
(幸いなことに、apply代わりにpopを使用しているので、ここで考えを変えることができます:
$ git reset --hard HEAD
HEAD is now at 94824e1 initial
$ git stash apply -q --index
$ git status --short
MM basefile
index と work-dir のバージョンを見ると、 の両方のバージョンが表示されますbasefile。)
(stash スクリプトの修正は、次の行を次のように変更HEADすることです。$i_tree
git diff --name-only -z HEAD -- >"$TMP-stagenames" &&
118 行目あたり。これを git メーリング リストに投稿したところ、... コオロギが出てきました。:-) )