web-dev-qa-db-ja.com

対話モードでの「git stash apply」

一連のファイルをスタッシュ(stash{0})そして私はgit applyjustこれらのファイルの一部/ハンク(通常インタラクティブモードとして知られています)。

出来ますか?

私が実行することが可能であることを見てきました

git stash save -p 'Stash name'

しかし、それはできないようです

git stash apply -p 'Stash name'

それを達成する方法を知っていますか?

32
Kamafeather

出来ますか?

はい、そうです!

git checkout -p stash@{0}

0stash@{0}を、適用するスタッシュのインデックスに置き換えることができる場所。

適用する隠し場所がnかわからない場合は、git stash listgit show -p stash@{n}を使用してください。

git stash drop stash@{n}は明らかにスタッシュを落とさないので、スタッシュがもう必要ないことがわかっている場合はgit checkoutを忘れないでください。

なぜ機能するのですか?

重要なのは、スタッシュが本質的に、タグとブランチのように 参照 から コミット であることを理解することです。

実際、それらは.git/refs/stashに格納され、スタッシュハッシュごとに1行です。

注意事項

以下のコメントで @ mgadda が言及されているように、git checkout -pはコミットと現在のワークスペースの違い全体を適用しようとします。

Git stashの場合、適用しようとしているstashが別のコミットに対して行われた場合、git checkout -p stash@{n}はコミットstash@{n}とコミットのすべての違いをインタラクティブに適用しようとします現在のワークスペース、異なるすべての親コミットを含みます。

たとえば、「多くのコミット前に」保存されたstashを現在のワークスペースに適用しようとすると、git checkout -p stash@{n}はstash固有の変更を適用するだけでなく、revertstashのベースとなっているコミットと現在のコミットの間に発生したすべての変更。

逆に、「未来から」スタッシュを適用しようとしている場合、つまり、スタッシュのベースとなっているコミットの前のコミットの数であるブランチにスタッシュを適用しようとすると、git checkout -p stash@{n}はすべてを適用しようとしますstash自体からの変更に加えて、現在のコミットと将来のコミットの間に発生した他の変更。

(ご参考までに、並列ブランチからのgit checkout -p stash@{n} stashは、現在のコミットと元の分岐ポイント間のすべての変更を元に戻そうとしますand分岐ポイント間のすべての変更も適用しますスタッシュの変更の他に、他のブランチ)。

回避策

いくつかの回避策がありますが、どれもすべての状況に最適ではありません。

    1. git checkout -p stash@{n}を実行するときに受け入れるパッチには十分注意してください。
    1. git stash popを実行する前に、git stashを実行してから、もう一度git checkout -p ...を実行してください。ただし、競合を回避するためにスタッシュを部分的に適用したい場合、これは実際には役に立ちません。その場合は、以下の解決策4を参照してください。
    1. Gitでサポートされているグラフィカルなdiffツール( meld など)を使用している場合は、git difftoolを使用して、必要な変更のみを「適用」することができます。

      • git difftool -d stash@{n} stash全体とそのすべてのファイルを比較するには

      • git difftool stash@{n} -- path/to/fileは単一のファイルを比較します

    1. (@ andrewの回答に基づく) デタッチされたヘッドで、関心のあるスタッシュの「親」コミットに戻り、スタッシュを適用し、必要な部分だけをインタラクティブに再スタッシュします興味があり、戻って小さいスタッシュを再適用します。

ステップバイステップ:

git checkout stash@{n}^  # notice the "^". 

# Now you're in a detached head in the parent commit of the stash.
# It can be applied cleanly:
git stash apply stash@{n}

# Now save only the diffs you're interested in:
git stash -p

# remove the rest of the old stash
git checkout -- .  # be careful or you could remove unrelated changes

# go back to the branch where you want to apply the smaller stash
git checkout <my previous branch>

# apply the smaller stash
git stash pop
46
LeoRochael

1つの可能な方法は、インデックスをリセットしてからinteractive addを使用することです

# 0. ensure there are no uncommitted changes
git status

# 1. apply a changeset as is
git stash apply stash@{n}
# ... fix or discard conflicts if any

# 2. reset the index 
git reset

# 3. interactively add the required chunks (except new files)
git add -p

# 4. stash all other changes
git stash save --keep-index "comment"
# 4. or just discards all other changes in the working tree
git checkout-index -f -a

# 5. commit
git commit -m "comment"

別の方法は、インタラクティブな追加の代わりにインタラクティブリセットを使用することです。

# 0. ensure the working tree does not have unstaged changes
git status

# 1. apply a changeset as is
git stash apply stash@{n}
# ... fix or discard conflicts if any

# 2. interactively exclude the unneeded chunks from the index 
git reset -p

# 3. stash all other changes
git stash save --keep-index "comment"
# 3. or just discards all other changes in the working tree
git checkout-index -f -a

# 4. commit
git commit -m "comment"
2
ruvim

変更をハンク(またはファイル)で適用する方法はないと思います。 stashを適用してから、不要な変更をインタラクティブにstashする必要があります(git stash save -p)。競合が心配な場合は、コミットされていない変更を最初に隠しておき、スタッシュを適用し、競合するハンクを隠してから、他のスタッシュを適用します。

2
Andrew