git stashから単一のファイル(またはファイルへの変更)を抽出するにはどうすればよいですか?


774

stashチェンジセットをポップすることなく、git stashから単一のファイルまたはファイルの差分を抽出できるかどうかを知りたいのですが。

誰かがこれについていくつかの提案/アイデアを提供できるでしょうか?

回答:


1131

のgitのstash manページあなたが(ちょうど「オプション」の説明の後、「ディスカッション」セクションで)読むことができます:

stashは、ツリーが作業ディレクトリの状態を記録するコミットとして表され、その最初の親は、stashが作成されたときのHEADでのコミットです。

したがって、スタッシュ(たとえばstash@{0}、最初/一番上のスタッシュ)をマージコミットとして扱い、次のように使用できます。

$ git diff stash@{0}^1 stash@{0} -- <filename>

説明:stash@{0}^1所定のスタッシュの最初の親を意味します。これは、上記の説明で述べたように、変更が隠されたコミットです。stash@{0}/ refs/stashはマージコミットなので、この形式の「git diff」(2つのコミット)を使用します。比較する親をgitに指示する必要があります。より不可解な:

$ git diff stash@{0}^! -- <filename>

動作するはずです(構文の説明については、「範囲の指定」セクションのgit rev-parseマンページを参照してくださいrev^!)。

同様に、git checkoutを使用して、スタッシュから単一のファイルをチェックアウトできます。

$ git checkout stash@{0} -- <filename>

または別のファイル名で保存するには:

$ git show stash@{0}:<full filename>  >  <newfile>

または

$ git show stash@{0}:./<relative filename> > <newfile>

(ここで、<完全なファイル名>は、プロジェクトのトップディレクトリに対するファイルの完全なパス名であることに注意してください(:からの相対と考えてくださいstash@{0}))。


stash@{0}シェル拡張から保護する必要がある場合があります。つまり、"stash@{0}"またはを使用します'stash@{0}'


8
これはかなりクールです...私があなたの答えを読むまで、私はstashがどのように機能するのか本当に理解していませんでした(それがgit-checkoutの追加につながりました)。stashを実行すると、gitは2つのコミットを保存します-1つはインデックスの状態用、もう1つは作業コピーの状態用で、インデックスと元のHEADの間のマージです。これは、スタッシュが存在するときに「gitk --all」でリポジトリを視覚化したときに見た奇妙なツリーを説明しています。
Pat Notz

4
ほとんどの場合、私はgit checkoutアプリケーションが自分がやりたいことを達成するための最良の方法だと思っています。しかし、私は好奇心が強く、git checkoutのmanページを再確認しました。ファイルを別の場所にドロップすることはできません。このへの参照があります:stackoverflow.com/questions/888414/...は
ダニー・

84
$ git checkout stash @ {0}-<filename>は非常に便利です、ありがとう
重力

43
このgit checkout方法では、スタッシュから正確なファイルがコピーされることに注意してください。この方法では、作業ディレクトリにあるファイルとはマージされませんgit stash apply。(つまり、スタッシュが作成されたベースから変更がある場合、それらは失われます)。
peterflynn 2013

4
ノートのためにそのgit stash applyファイルが作業ツリー内のファイルが上演されなければならないことを、隠したので、作業ツリーに変更されたファイルに変更をマージします。自動マージが機能するためには、作業コピーとマージされて隠されたコピーの両方で同じファイルを変更することはできません。最後に、stash applyは、アイテムをstashから削除しませんgit stash pop
Ville

46

git stash applyではなくを使用するgit stash popと、作業ツリーにスタッシュが適用されますが、スタッシュは保持されます。

これが完了したら、必要なファイルをadd/しcommitて、残りの変更をリセットできます。


2
特定のgit stash pop stash@{0}git stash list
スタッシュ

stashの他のファイルがマージの競合を引き起こす場合、gitは必要なファイルをコミットさせません:(
cambunctious

33

stashを含め、任意のブランチから変更を取得する簡単な方法があります。

$ git checkout --patch stash@{0} path/to/file

多くの部分にパッチを適用する場合は、ファイル仕様を省略できます。または、パッチ(パスではなく)を省略して、単一のファイルに対するすべての変更を取得します。複数ある場合0は、のスタッシュ番号に置き換えgit stash listます。これはのようなものdiffであり、ブランチ間のすべての違いを適用することを提案していることに注意してください。単一のコミット/スタッシュのみから変更を取得するには、をご覧くださいgit cherry-pick --no-commit


これはスタッシュから正確なファイルをコピーしますか、それともマージしますか?コピーの場合、スタッシュが作成されてから変更がある場合、それらは失われます。
Danijel

2
@Danijel読み取りgit help checkout--patchインタラクティブなマージを行い、シェルで承認したすべてのハンク(またはeパッチを適用することを選択した場合は保存したもの)を適用します。私が書いたように、「すべての変更」というように、パスだけでファイルが上書きされます。
ウォルフ2018年

1
わずかな改善: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' -実行git applydiffat stash@{4}すると、スタッシュとその親の間で変更されたファイルのみが使用されます。
マーク

25

簡潔な答え

ファイル全体を表示するには: git show stash@{0}:<filename>

差分を確認するには: git diff stash@{0}^1 stash@{0} -- <filename>


1
私は彼/彼女が特定のファイルの隠し場所を見ることに関心があるとは思わず、そのファイルをポップするだけです。
アマルゴビナス

1
これは私が探していたものです。次に、で置き換えdiffdifftool、お気に入りの外部差分を使用できます。
Peet Brits

19
$ git checkout stash@{0} -- <filename>

ノート:

  1. 「-」とファイル名パラメーターの後にスペース入れてください。

  2. zero(0)を特定のスタッシュ番号に置き換えます。stashリストを取得するには、以下を使用します。

    git stash list
    

JakubNarębskiの回答に基づく-短いバージョン


11

git show stash@{0}」(またはスタッシュの番号が何であれ、「git stash list」を参照)でスタッシュの差分を取得できます。1つのファイルのdiffのセクションを抽出するのは簡単です。


2
私のような頭脳にとってはさらにシンプルです。git show stash最上位の隠し場所(通常は唯一の隠し場所)を表示するために使用します。同様に、現在のブランチとスタッシュの差分をで表示できますgit diff head stash
ディズリー2013年

5

理解するのが最も簡単な概念は、最善ではないかもしれませんが、3つのファイルを変更し、1つのファイルを隠しておくことです。

git stashそれらをすべて隠しておく場合は、git stash applyそれらを元に戻しgit checkout f.c、問題のファイルを有効にリセットします。

そのファイルをunstashしたい場合は、a git reset --hardを実行してからgit stash apply再度実行します。git stash applyスタックからdiffをクリアしないます。


1

隠しておいたファイルを現在のバージョンとマージする必要がある場合は、diffを使用して以前の方法を使用します。それ以外の場合はgit pop、それらをアンスタッシュするgit add fileWantToKeepため、ファイルをステージングするために使用し、git stash save --keep-indexステージ上にあるもの以外のすべてをスタッシュするためにを実行する場合があります。この方法と以前のものとの違いは、ファイルをstashから「ポップ」することです。以前の答えはそれを維持するgit checkout stash@{0} -- <filename>ので、それはあなたのニーズに応じて行きます。


0

以下を使用して、スタッシュ内のファイルへの変更を作業ツリーに適用します。

git diff stash^! -- <filename> | git apply

git checkoutスタッシュを作成してからファイルに加えた変更が失われることがないため、これは一般的に使用するよりも優れています。


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