たとえば、git status
は次のようになります。
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: app/src/[....]
modified: app/src/[....]
new file: app/src/[....]
deleted: app/src/[....]
modified: app/src/[....]
modified: test/unit/[....]
modified: test/unit/[....]
new file: test/unit/[....]
deleted: test/unit/[....]
modified: test/unit/[....]
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: test/unit/[....]
Untracked files:
(use "git add <file>..." to include in what will be committed)
app/src/[....]/
app/src/[....]/
app/src/[....]/
(ファイル名を空白にしました)
自分が持っている変更だけをどのように隠しますかgit add
ed(つまり、ステージングされていない変更や追跡されていないファイルではなく、「コミットされる変更」)なので、代わりに別のブランチに転送できますか?
Gitの基本的なストレージメカニズムは「コミット」です。実際、git stash
が行うのは、やや変わったコミットをいくつか行うことだけです。したがって、 Nick Volynkinの答え は正しいものです。ただし、多少の拡張を使用する可能性があり、より簡単な(まあ、潜在的に簡単な)方法があります。
私はgit stash
の大ファンではありませんが、これを使用することに慣れている場合は、他の最も簡単な方法を次に示します。
git stash save
(別名git stash
)。これにより、2つのコミットが書き込まれます。1つは現在のインデックスに基づいており、もう1つはまだステージングされていないワークツリーファイルを保持するためのものです。 (untrackedファイルを保持する必要がある場合は、-u
フラグを追加してから、stashスクリプトでさらに3番目のコミットを追加できます。通常はただし、これらの追跡されていないファイルを作業ツリー内で追跡せずにそのままにしておくことができます。)これらのコミットはどのブランチにも存在せず、特別な「スタッシュ」参照にのみ存在します。その間、あなたはまだ「間違った」ブランチにいます。これを以下でwrongbr
と呼びます。
git checkout
これらを配置するブランチ。今、あなたは正しい枝にいます。
git stash apply --index
。これは、ステップ1で作成された特別なスタッシュコミットを使用しますが、スタッシュにはそのままにしておきます(apply
)。 --index
は非常に重要です。これは、stashスクリプトにインデックスファイルとステージングされていないファイルを分離しておくように指示します。つまり、ステージングされたファイルと以前に行ったステージングされていないセットアップ。
すべてがうまくいけば、あなたは今、あなたが望むブランチへの変更をgit commit
する立場にあります。以前にステージングされたファイルは再びステージングされ、ステージングされていないファイルはまだステージングされていません。これは、スタッシュを--index
でapply
-したためです。コミットはステージングされたファイルをコミットし、ステージングされていないファイルはステージングされないままにします。
これで、他の「間違った」ブランチ(最初に隠し場所を作成した場所)とgit stash apply
またはgit stash pop
に--index
の有無にかかわらず戻ることができます。ステージングされていないファイルをクリーンアップする必要がある場合があります(そうしても安全です。ファイルはまだ隠されています):git reset --hard
、次にgit checkout wrongbr
、次にgit stash pop
。 pop
はapply
の後にdrop
が続くことに注意してください:wanttodropステップ3のスタッシュ(スタッシュには元の変更されたがステージングされていないファイルの唯一のコピーがあります)、これがapply
そこにありますが、(おそらく)doは隠し場所を削除したいので、pop
を使用しても問題ありません。
ただし、ステップ3には大きな潜在的な落とし穴があります。つまり、スタッシュが正しく適用されない可能性があります。もしそうなら、あなたは他の方法を使わなければなりません。これが、私がstash
システムを本当に好きではない理由の1つです。ハードケースでは失敗し、stash
を使用しない場合に使用できるツールを知る必要があります。その場合、ほとんどの場合、これらのツールを使用できます...そして、それが確実に機能する場合の便利なショートカットとしてstash
を使用します。
背景:コミットは現在インデックスにあるものをすべて取得します— git ls-files --cached
は完全なコンテンツを表示し、git status
はこれを「興味深い」コンテンツに切り詰めて、さらに有用な情報を追加します—そしてコミットをそれら、必要なすべてのツリーオブジェクトなどが含まれます。新しいコミットの親コミットは、現在のコミットが以前のものでした。
別のブランチで新しいコミットを行う必要があります。これを行う1つの方法は、現在のブランチで今すぐ作成することです。次に、そのコミットを別のブランチの新しい別のコミットにコピーします。 「別のブランチで新しい別のコミットにコミットをコピーする」には、git cherry-pick
を使用できます。 git rebase
を使用できるのは事実です。内部では、git cherry-pick
自体を使用しています。しかし、rebase
は完全に適切なツールではありません。これは、大量のチェリーピッキング用に設計されており、コミットは1つだけです。最後に、git reset
を使用してブランチラベルを移動しますが、希望どおりではありません。あなたはそれを機能させることができますが、いくつかのより適切なツールがあります。
ただし、元の問題に戻りましょう。現在のインデックスを取得し、それを使用して新しいコミットを作成しますが、別のブランチにあります。これは、他に何もせずに今すぐ他のブランチに切り替えてから、新しいコミットを行うことができれば最も簡単です。
あなたができる可能性は高いです。 git checkout otherbranch
、次にgit commit
だけです。ここでは3つのケースが考えられます。
他のブランチはまだ存在していません。すごい! git checkout -b newbranch
を使用して、現在の場所から作成します。次にgit commit
。 「現在の場所」以外の場所から開始するように新しいブランチをリベースしたい場合を除いて、これで完了です。その場合は、新しいブランチでgit rebase
を使用します。ステージングされていないファイルを処理した後、後でそのリベースを実行できることに注意してください。
もう1つのブランチは存在し、幸運なことに、git checkout otherbranch
は正常に機能します。それを実行してコミットすれば、完了です。その後、ステージングされていないファイルに必要なブランチをgit checkout
できます。
最も厄介なケース:他のブランチは存在しますが、git checkout
は、コミットしていないものを上書きすることを通知します。
ケース3は、コミットまたはスタッシュする必要があるケースです。
ここで何をするかは、あなたが最も快適なものによって異なります。たとえば、最も簡単な代替方法として、上記の4ステップのstash
メソッドを試すことができます。
ただし、私自身は、「間違った」ブランチで今すぐコミットしてから、もう一度コミットして(または、git stash
を使用して)、ステージングされていないファイルを邪魔にならないようにします。これにより、rightブランチにgit cherry-pick
できるコミットが得られます。動作する可能性のあるシーケンスの例を次に示します。
git commit
コミットしますが、「間違った」ブランチにあります(以下の参照用に現在のブランチをwrongbr
と呼びましょう)。git stash save
は、ステージングされていない変更を保存します(または、-u
を使用すると、追跡されていないファイルも保存します)。git checkout
コミットを実行するブランチ(例:git checkout rightbr
)。git cherry-pick wrongbr
。これが成功すれば、良いです。そうでない場合は、必要に応じてファイルを編集して、マージの問題が発生した後にクリーンアップしてから、結果をgit commit
します。git checkout wrongbr
:ステップ4でコピーしたコミットを削除することでこれを修正します。git reset --hard HEAD^
:これにより、コピーしたコミットが削除されます。git stash pop
(または同じことを行うgit stash apply && git stash drop
、apply
バリアントは、単にdrop
スタッシュの前に結果を検査する機会を与えます)。ここでステップ4に注意してください:git cherry-pick
は名前付きコミット(単に間違ったブランチにあるcommit-we-wantを含むwrongbr
の先端)を取りますそれをその親と比較し、結果の差分を現在のブランチに適用しようとします。現在のブランチのファイルがwrongbr
の対応するファイルと大きく異なる場合、これは3方向マージを行う必要があるかもしれません。これは、rightbr
をチェックアウトして最初にコミットするという単純なケースで、複雑さが発生するのと同じ場所です。つまり、コミットする前にgit checkout rightbr
だけを実行しようとしたときに「最も厄介な」ケースが発生したため、この長いバージョンを実行しているため、修正が必要になる可能性があります。これにより、元の4ステップのstash
メソッドで問題が発生する可能性もあります。
すべてを隠しますが、インデックスは保持します(この隠し場所は(git add
から)ステージングされ、ステージングされていない編集になります):
git stash --keep-index
インデックスを隠します。これは、手順1で隠した後に残っているすべてです(これは、隠したいものです)。
git stash
手順1のスタッシュをすべてポップまたは適用(より安全)します(最新のものは常にstash@{1}
であるため、現在はstash@{0}
にあります)。
git stash apply stash@{1}
HEAD
からチェックアウトして、最初にインデックスに追加されたファイル(stash@{0}
内のファイル)を復元します。
git checkout HEAD ./path/to/files/to/reset ./another/path/to/other/file/to/reset
手順4で混乱した場合は、git reset HEAD --hard
を試してすべてのローカル変更を消去し、手順3からやり直してください。
それらのファイルをコミットしてから、コミットをリベースします。