web-dev-qa-db-ja.com

Git 2.13以前に変更された複数のファイルのうち1つのファイルのみ隠しておく

ブランチ上の複数の変更されたファイルのうち1つだけを隠すにはどうすればいいですか?

2723
Rachel

警告

コメントで述べたように、これは段階的でも段階的でもなくすべてを隠し場所に入れます。 --keep-indexはスタッシュが完了した後にインデックスをそのままにします。後でスタッシュをポップすると、マージの競合が発生する可能性があります。


これはあなたが以前に追加していなかったすべてを隠します。保持したいものをgit addしてから実行してください。

git stash --keep-index

たとえば、古いコミットを複数のチェンジセットに分割したい場合は、この手順を使用できます。

  1. git rebase -i <last good commit>
  2. いくつかの変更をeditとしてマークします。
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. 必要に応じて修正してください。 git addに変更を忘れないでください。
  7. git commit
  8. git stash pop
  9. 必要に応じて、#5から繰り返します。
  10. git rebase --continue
1260
bukzor

git stash save -p "my commit message"を使うこともできます。このようにして隠し場所に追加する必要があるハンクを選択でき、ファイル全体も選択できます。 

あなたはそれぞれの塊に対していくつかのアクションを促されるでしょう:

   y - stash this hunk
   n - do not stash this hunk
   q - quit; do not stash this hunk or any of the remaining ones
   a - stash this hunk and all later hunks in the file
   d - do not stash this hunk or any of the later hunks in the file
   g - select a hunk to go to
   / - search for a hunk matching the given regex
   j - leave this hunk undecided, see next undecided hunk
   J - leave this hunk undecided, see next hunk
   k - leave this hunk undecided, see previous undecided hunk
   K - leave this hunk undecided, see previous hunk
   s - split the current hunk into smaller hunks
   e - manually edit the current hunk
   ? - print help
2868

Gitは基本的にすべてのリポジトリcontentとインデックス(そして1つまたは複数のファイルではない)を管理することを目的としているので、git stashは驚くことではありませんが対処します、 全作業ディレクトリ

実際、Git 2.13(2017年第2四半期)以降、 git stash Push を使用して個々のファイルを隠蔽することができます。

git stash Push [--] [<pathspec>...]

pathspecが 'git stash Push'に与えられると、新しいスタッシュはパス指定と一致するファイルについてのみ変更された状態を記録します

詳しくは " 特定のファイルへの変更を隠す "をご覧ください。

テストケース 自明です:

test_expect_success 'stash with multiple pathspec arguments' '
    >foo &&
    >bar &&
    >extra &&
    git add foo bar extra &&

    git stash Push -- foo bar &&   

    test_path_is_missing bar &&
    test_path_is_missing foo &&
    test_path_is_file extra &&

    git stash pop &&
    test_path_is_file foo &&
    test_path_is_file bar &&
    test_path_is_file extra

元の答え(下、2010年6月)は、隠したいものを手動で選択することでした。 

Casebash comments:

これ(stash --patchオリジナルの解決策)はいいですが、私は多くのファイルを修正したので、patchを使うのは面倒です。

bukzor 's answer (2011年11月に支持されました)は、
git add + git stash --keep-index
彼の答えを見て、支持してください。それは公式のものであるべきです(私の代わりに)。

そのオプションについて、 chhh はコメント内の代替ワークフローを指摘しています。

明確なステージングを取り戻すには、このようなスタッシュの後に "git reset --soft"を入力する必要があります。
明確なステージング領域で、一部の選択されたステージングされていない変更のみを含む元の状態に到達するために、インデックスをソフトにリセットして取得することができます。


(元の回答2010年6月:手動隠し場所)

それでも、git stash save --patchを使用すると、自分がしている部分的な隠蔽を実現できます。

--patchを使うと、HEADと隠される作業ツリーの間の差分からハンクを対話的に選択することができます。
stashエントリは、そのインデックス状態がリポジトリのインデックス状態と同じになるように作成されており、そのワークツリーには対話的に選択した変更のみが含まれています。選択した変更はワークツリーからロールバックされます。

ただし、完全なインデックス(既にインデックスが作成されている他のファイルが含まれている可能性があるため、必要なものではない可能性があります)と部分的なワークツリー(隠したいもののように見える)が保存されます。

git stash --patch --no-keep-index

より良いフィットかもしれません。


--patchが機能しない場合は、手動プロセスで可能性があります。

1つまたは複数のファイルの場合、中間的な解決策は次のようになります。

  • gitレポジトリの外にそれらをコピーする
    (実際には、 eleotlecram興味深い代替案を提案しています
  • git stash
  • それらをコピーして戻す
  • git stash#今回は、欲しいファイルだけが隠されています
  • git stash pop stash@{1}#すべてのファイル修正を再適用します
  • git checkout -- afile#ローカルの修正の前に、ファイルをHEADコンテンツにリセットします

やや面倒なプロセスの終わりには、1つか複数のファイルが隠されることになります。

324
VonC

git stash -p(またはgit add -pと一緒のstash --keep-index)が面倒すぎる場合は、diffcheckoutおよびapplyを使用する方が簡単であることがわかりました。

特定のファイル/ディレクトリのみを「隠蔽」するには

git diff path/to/dir > stashed.diff
git checkout path/to/dir

その後

git apply stashed.diff
80
blueyed

このようにgit stash Pushを使用してください。

git stash Push [--] [<pathspec>...]

例えば:

git stash Push -- my/file.sh

2017年春にリリースされたGit 2.13以降で利用可能です。

58
sandstrom

3つのファイルがあるとしましょう 

a.rb
b.rb
c.rb

そして、あなたはb.rbとc.rbだけを隠したいがa.rbは隠したくない

あなたはこのようなことをすることができます

# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp" 

# then stash the other files
git stash save "stash message"

# then undo the previous temp commit
git reset --soft HEAD^
git reset

そして、これで終わりです! HTH。

45
venkatareddy

これを行う別の方法:

# Save everything
git stash 

# Re-apply everything, but keep the stash
git stash apply

git checkout <"files you don't want in your stash">

# Save only the things you wanted saved
git stash

# Re-apply the original state and drop it from your stash
git stash apply stash@{1}
git stash drop stash@{1}

git checkout <"files you put in your stash">

私が(もう一度)このページに来た後、私はこれを思いつきました、そして、最初の2つの答えが好きではありませんでした(最初の答えはただ質問に答えないし、私は-pインタラクティブモードで作業するのがあまり好きではありません).

考え方は@VonCがリポジトリの外でファイルを使うことを提案したのと同じです、あなたがどこかに欲しい変更を保存し、あなたの隠し場所に望まない変更を削除し、そして邪魔にならなかった変更を再適用します。しかし、私はgitスタッシュを「どこか」として使用しました(そして結果として、最後にもう1つステップがあります。スタッシュに入れた変更を削除するのは、邪魔にならないためです。

27
Jasper

アップデート(2/14/2015) - 私は衝突のケースをよりよく扱うためにスクリプトを少し書き直しました。これは.rejファイルではなくマージされていない衝突として提示されるべきです。


@ bukzorのアプローチの逆を実行する方が直感的にわかります。つまり、いくつかの変更をステージングしてから、ステージングされた変更のみを隠します。 

残念なことに、gitはgit stashを提供していません - インデックスのみ、またはそれに類似しているので、私はこれを行うためのスクリプトを作成しました。

#!/bin/sh

# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`

# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`

# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`

# get back to a clean state with no changes, staged or otherwise
git reset -q --hard

# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash

# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT

CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
    # If there are no conflicts, it's safe to reset, so that
    # any previously unstaged changes remain unstaged
    #
    # However, if there are conflicts, then we don't want to reset the files
    # and lose the merge/conflict info.
    git reset -q
fi

上記のスクリプトをパスのどこかにgit-stash-indexとして保存してから、git stash-indexとして呼び出すことができます

# <hack hack hack>
git add <files that you want to stash>
git stash-index

これで、隠し場所には、ステージングした変更のみを含む新しいエントリが含まれ、作業ツリーにはまだステージングされていない変更がすべて含まれます。

場合によっては、作業ツリーの変更がインデックスの変更に依存することがあるため、インデックスの変更を隠しておくと、作業ツリーの変更に矛盾が生じます。この場合、git merge/git mergetool/etcで解決できる通常のマージされていない競合が発生します。

23
JesusFreke

Gitでブランチを作成するのは簡単なので、一時的なブランチを作成して個々のファイルをチェックインするだけで済みます。

19
shangxiao

念のために、実際に 変更を破棄 git stashを使用するときはいつでも(そして一時的にそれを隠すためにgit stashを使用しないでください) 

git checkout -- <file>

[注意

そのgit stashは、分岐してものを実行するための、より速くて単純な代替手段にすぎません。

11
Devesh

次のコードをstashなどのファイルに保存します。使い方はstash <filename_regex>です。引数はファイルのフルパスの正規表現です。たとえば、/ b/c.txt、stash a/b/c.txtstash .*/c.txtなどを隠します。

$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml

ファイルにコピーするコード:

#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]

spawn git stash -p

for {} 1 {} {
  expect {
    -re "diff --git a/($filename_regexp) " {
      set filename $expect_out(1,string)
    }
    "diff --git a/" {
      set filename ""
    }
    "Stash this hunk " {
      if {$filename == ""} {
        send "n\n"
      } else {
        send "a\n"
        send_user "$filename\n"
      }
    }
    "Stash deletion " {
      send "n\n"
    }
    eof {
      exit
    }
  }
}
10
apricot

Gitリポジトリの外部にファイルをコピーするVonCの「中間的な」解決方法の問題は、パス情報を失うことです。

コピーではなくtarを使用するほうが簡単です(似たようなツールでもおそらく可能です)。

  • tar cvf /tmp/stash.tarパス/// some /ファイルパス/// some/other/file(...など)
  • gitチェックアウトパス/ to/some/fileパス/ to/some/other/file
  • git stash
  • tar xvf /tmp/stash.tar
  • など(VonCの「中間」提案を参照)
7
eleotlecram

これはSourceTreeを使用して3つのステップで簡単に行うことができます。

  1. 隠したくないものすべてを一時的にコミットします。
  2. Gitは他のすべてを追加してから隠します。
  3. Git resetを実行して一時的なコミットをポップし、一時的なコミットの前にコミットをターゲットにします。

SourceTreeでは、これをすべて数秒で実行できます。追加したいファイル(または個々の行)をクリックするだけです。追加したら、それらを一時的なコミットにコミットします。次に、チェックボックスをクリックしてすべての変更を追加し、次にstashをクリックしてすべてを変更します。変更が邪魔にならないようにして、コミットリストを見て、一時的なコミットの前にコミットのハッシュを書き留めてから、 'git reset hash_b4_temp_commit'を実行します。その直前にコミットします。今、あなたはあなたが隠したくないものだけを残しています。

7
Triynko

私はgit stash save --patchを使います。必要な操作をファイル全体に適用するためのオプションがあるため、対話性が面倒なことはわかりません。

コミットする前に自分のブランチに無関係な変更を加えたことがあるので、それを別のブランチに移動して別々にコミットしたい(masterのように)。私はこれをします:

git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...

最初のstashstash popは削除することができます、あなたがチェックアウトするとき、あなたはすべての変更をmasterブランチに引き継ぐことができますが、それは衝突がない場合に限ります。また、部分的な変更のために新しいブランチを作成しているのであれば、stashが必要になります。

競合も新しいブランチもないと仮定すると、単純化できます。

git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...

スタッシュも必要ありません...

6
void.pointer

これを簡単に行うことができます:

git stash Push "filename"

またはオプションのメッセージ付き

git stash Push -m "Some message" "filename"
6
vinodsaluja

ここでのすべての答えはとても複雑です...

これを「隠蔽」するのはどうでしょうか。

git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash

これはファイル変更をポップバックするものです。

git apply /tmp/stash.patch

1つのファイルを隠してそれを元に戻すのと同じ動作.

6

私はこれに関する答えとコメント、そして同様のスレッドをいくつか見直しました。 特定の追跡/未追跡ファイル を隠すことができるという目的には、次のコマンドはどれも正しくないことに注意してください。

  • git stash -p (--patch):追跡されていないファイルを除いて、手動でハンクを選択
  • git stash -k (--keep-index):全ての追跡された/追跡されていないファイルを隠して作業ディレクトリに保存する
  • git stash -u (--include-untracked):全ての追跡された/追跡されていないファイルを隠します
  • git stash -p (--patch) -u (--include-untracked):無効なコマンド

現在、追跡されている/追跡されていない特定のファイルを隠すことができる最も合理的な方法は、次のとおりです。

  • 隠したくないファイルを一時的にコミットする
  • 追加して隠す
  • 一時コミットをポップする

私は別の質問に対する答えとしてこの手順のための簡単なスクリプトを書きました そしてここでSourceTreeで手順を実行するための ステップがあります

3
ZimbiX

溶液

ローカルの変更点 

  • file_A(変更済み)がステージングされていません 
  • file_B(変更済み)はステージングされていません 
  • file_C(変更済み)がステージングされていません 

file_C の変更のみを含む隠し場所「my_stash」を作成するには、次のようにします。

1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop stash@#{1}

完了しました。


説明

  1. ステージング領域に file_C を追加します。
  2. "temp_stash"という名前の一時的な隠し場所を作成し、変更をfile_Cに保存します。
  3. file_Cの変更だけで、必要な隠し場所( "my_stash")を作成します。
  4. あなたのローカルコードに "temp_stash"(file_Aとfile_B)の変更を適用し、隠しファイルを削除します

何が起こっているのかを見るために、ステップの間に git status を使うことができます。

3
Alex 75

隠しておいた変更を含むメッセージを指定したくない場合は、ファイル名を二重ダッシュの後に渡してください。

$ git stash -- filename.ext

追跡されていない/新しいファイルの場合は、最初にステージングする必要があります。

このメソッドはgitバージョン2.13以降で動作します

2
sealocal
git add .                           //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash                           //stash the file(s)
git reset .                         // unstage all staged files
git stash pop                       // unstash file(s)
2
novice

単一のファイルを隠すにはgit stash --patch [file]を使います。

これはプロンプトに行きます:Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?aとタイプするだけで(このハンクを隠して、後でファイル内のすべてのハンクを隠します)、大丈夫です。

2
vnbrs

このような状況では、私はgit add -p(interactive)、git commit -m blah、そして必要なら残ったものを隠します。

2
J0hnG4lt

似たような状況。コミットし、それが問題ではないことに気付きました。

git commit -a -m "message"
git log -p

答えに基づいてこれは私を助けた。

# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually Push tu remote
git Push
1
David Hrbáč

2つのブランチを切り替えようとすると、この状況が発生します。

"git add filepath"を使用してファイルを追加してみてください。

後でこの行を実行 

git stash --keep-index

1

SourceTreeのみを使用して、コマンドラインで実行する方法がわかりません。ファイルAを変更し、ファイルBに2つの変更ハンクがあるとしましょう。ファイルBの2番目のハンクだけを隠して他のすべてをそのままにしたい場合は、次のようにします。

  1. すべてを上演する
  2. 作業コピーを変更して、ファイルAのすべての変更を元に戻します(たとえば、外部差分ツールを起動してファイルを一致させる)。
  3. ファイルBを2番目の変更だけが適用されているように見せます。 (例:外部差分ツールを起動して最初の変更を元に戻す)
  4. 「段階的な変更を保持」を使用して隠し場所を作成します。
  5. すべてをアンステージング
  6. 完了しました。
1

私が必要としているものであるという答えが見つからず、それは次のように簡単です。

git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash

これはちょうど1つのファイルを隠します。

0
Sebastian

1つの複雑な方法は、最初にすべてをコミットすることです。

git add -u
git commit // creates commit with sha-1 A

元のコミットにリセットしますが、新しいコミットからthe_one_fileをチェックアウトします。

git reset --hard HEAD^
git checkout A path/to/the_one_file

これでthe_one_fileを隠すことができます。

git stash

コミットした内容をファイルシステムに保存し、元のコミットに戻してクリーンアップします。

git reset --hard A
git reset --soft HEAD^

ええ、やや厄介な...

0
Martin G

素早い回答


Gitで特定の変更されたファイルを元に戻すには、次の行を実行できます。

git checkout <branch-name> -- <file-path>

これが実際の例です。

git checkout master -- battery_monitoring/msg_passing.py

0
Benyamin Jafari