web-dev-qa-db-ja.com

gitの段階的な変更のみをスタッシングする-可能ですか?

ステージングした変更だけを隠しておく方法はありますか?私が問題を抱えているシナリオは、ある時点でいくつかのバグに取り組み、ステージングされていない変更がいくつかある場合です。これらのファイルを個別にステージングし、.patchファイルを作成し、コードが承認されるまでそれらを隠しておきたいと思います。このようにして、承認されたら、(現在の)セッション全体を隠し、そのバグをポップしてコードをプッシュできます。

私はこれについて間違った方法で行っていますか?プロセスを単純化するためにgitが他の方法でどのように機能するかを誤解していますか?

255
MrDuk

はい、信じられないかもしれませんが、本当に可能ですDOUBLE STASH

  1. スタッシュする必要があるすべてのファイルをステージングします。
  2. git stash --keep-indexを実行します。このコマンドは、変更のALLstagedおよびunstaged)でスタッシュを作成しますが、ステージングされた変更は残します作業ディレクトリ内(まだステージングされた状態)。
  3. git stash save "good stash"を実行します
  4. これで、"good stash"ステージングファイルのみが追加されました。

Stashの前にステージングされていないファイルが必要な場合は、最初のstash(--keep-indexで作成されたもの)を適用するだけで、"good stash"に隠したファイルを削除できます。

楽しい

355

最新のgitでは、--patchオプションを使用できます

git stash Push --patch

また、gitは、stashに追加するかどうかをファイルの各変更について尋ねます。 yまたはnと答えるだけです

66
Eugen Konkov

現在ステージングされているもののみを隠し、他のすべてを残すスクリプトを作成しました。これは、無関係な変更をあまりにも多く開始し始めたときにすごいことです。目的のコミットに関係のないものをステージングして、それだけを隠してください。

(出発点のBartłomiejに感謝)

#!/bin/bash

#Stash everything temporarily.  Keep staged files, discard everything else after stashing.
git stash --keep-index

#Stash everything that remains (only the staged files should remain)  This is the stash we want to keep, so give it a name.
git stash save "$1"

#Apply the original stash to get us back to where we started.
git stash apply stash@{1}

#Create a temporary patch to reverse the originally staged changes and apply it
git stash show -p | git apply -R

#Delete the temporary stash
git stash drop stash@{1}
41
Joe

特定のバグの変更をコミットし、そのコミットとその前身からパッチを作成してみませんか?

# hackhackhack, fix two unrelated bugs
git add -p                   # add hunks of first bug
git commit -m 'fix bug #123' # create commit #1
git add -p                   # add hunks of second bug
git commit -m 'fix bug #321' # create commit #2

次に、適切なパッチを作成するには、git format-patchを使用します。

git format-patch HEAD^^

これにより、2つのファイルが作成されます:0001-fix-bug-123.patchおよび0002-fix-bug-321.patch

または、バグごとに個別のブランチを作成して、バグ修正を個別にマージまたはリベースしたり、うまくいかない場合は削除したりすることもできます。

6
knittl

このシナリオでは、問題ごとに新しいブランチを作成することを好みます。プレフィックスtemp /を使用しているので、後でこれらのブランチを削除できることがわかります。

git checkout -b temp/bug1

Bug1を修正するファイルをステージングしてコミットします。

git checkout -b temp/bug2

その後、必要に応じて各ブランチからコミットを選択し、プルリクエストを送信できます。

4
Shamps

同じことを達成するには...

  1. 作業するファイルをステージングします。
  2. git commit -m 'temp'
  3. git add .
  4. git stash
  5. git reset HEAD~1

ブーム。不要なファイルは隠されています。必要なファイルはすべて用意されています。

2
Michael

git stash --keep-indexは良い解決策です...削除されたパスで正しく機能しなかった点を除き、Git 2.23(Q3 2019)で修正されました

commit b932f6a (2019年7月16日)by Thomas Gummerer(tgummerer を参照してください。
浜野潤二-gitster- in commit f8aee85 、2019年7月25日)

stash--keep-indexで削除されたファイルの処理を修正

git stash Push --keep-indexは、インデックスとディスクの両方で、インデックスに追加されたすべての変更を保持することになっています。

現在、ファイルがインデックスから削除されると、これは正しく動作しません。
ディスク上で削除したままにする代わりに、**-keep-indexは現在ファイルを復元します。**

インデックスと作業ツリーを忠実に復元できる非オーバーレイモードで「git checkout」を使用して、この動作を修正します。
これにより、コードも簡素化されます。

追跡されていないファイルがインデックスで削除されたファイルと同じ名前を持っている場合、これは追跡されていないファイルを上書きすることに注意してください。

1
VonC

一度にいくつかのバグに取り組むことが絶対に必要ですか? 「一度に」とは、「複数のバグに対して同時にファイルを編集する」ことを意味します。あなたが絶対にそれを必要としない限り、私はあなたの環境で一度に一つのバグだけに取り組むだろうからです。そうすれば、ローカルブランチとリベースを使用できます。これは、複雑なスタッシュ/ステージを管理するよりもはるかに簡単です。

マスターがコミットBにいるとしましょう。今度はバグ#1に取り組みます。

git checkout -b bug1

今、あなたはブランチbug1にいます。いくつかの変更を行い、コミットし、コードレビューを待ちます。これはローカルなので、他の人に影響を与えることはなく、git diffsからパッチを作成するのに十分簡単なはずです。

A-B < master
   \
    C < bug1

今、あなたはbug2に取り組んでいます。 git checkout masterでマスターにbackします。新しいブランチgit checkout -b bug2を作成します。変更を行い、コミットし、コードレビューを待ちます。

    D < bug2
   /
A-B < master
   \
    C < bug1

あなたがレビューを待っている間に、他の誰かがmasterでE&Fをコミットするふりをしましょう。

    D < bug2
   /
A-B-E-F < master
   \
    C < bug1

コードが承認されたら、次の手順でマスターにリベースできます。

git checkout bug1
git rebase master
git checkout master
git merge bug1

これにより、次の結果が得られます。

    D < bug2
   /
A-B-E-F-C' < master, bug1

次に、プッシュし、ローカルのbug1ブランチを削除して、外に出ます。ワークスペースには一度に1つのバグがありますが、ローカルブランチを使用すると、リポジトリで複数のバグを処理できます。これにより、複雑なステージ/スタッシュダンスが回避されます。

コメント内のctoteの質問への回答:

バグごとにスタッシングに戻り、一度に1つのバグのみを処理できます。少なくとも、ステージングの問題を回避できます。しかし、これを試してみたところ、個人的には面倒です。隠し場所はgit logグラフでは少し乱雑です。さらに重要なのは、何かを台無しにした場合、元に戻せないことです。作業ディレクトリが汚れていて、スタッシュをポップした場合、そのポップを「元に戻す」ことはできません。既存のコミットを台無しにするのははるかに困難です。

git rebase -i

あるブランチを別のブランチにリベースすると、インタラクティブに実行できます(-iフラグ)。これを行うとき、各コミットで何をしたいかを選択するオプションがあります。 Pro Gitは、HTML形式でもオンラインで公開されている素晴らしい本であり、リベースとスカッシュに関する素敵なセクションがあります。

http://git-scm.com/book/ch6-4.html

便宜上、サンプルを逐語的に盗みます。次のコミット履歴があると仮定し、bug1をmasterにリベースおよびスカッシュします。

    F < bug2
   /
A-B-G-H < master
   \
    C-D-E < bug1

git rebase -i master bug1と入力すると、次のように表示されます

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

ブランチのすべてのコミットを単一のコミットにまとめるには、最初のコミットを「pick」のままにして、後続の「pick」エントリをすべて「squash」または単に「s」に置き換えます。コミットメッセージを変更する機会も得られます。

pick f7f3f6d changed my name a bit
s 310154e updated README formatting and added blame
s a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

ええ、つぶすのは少し苦痛ですが、隠し場所を多用するよりも、それをお勧めします。

1
Mike Monkiewicz

Mike Monkiewiczの回答に対するコメントから、より単純なモデルを使用することをお勧めします。通常の開発ブランチを使用しますが、マスターブランチで単一のコミットを取得するにはマージのスカッシュオプションを使用します。

git checkout -b bug1    # create the development branch
* hack hack hack *      # do some work
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
git checkout master     # go back to the master branch
git merge --squash bug1 # merge the work back
git commit              # commit the merge (don't forget
                        #    to change the default commit message)
git branch -D bug1      # remove the development branch

この手順の利点は、通常のgitワークフローを使用できることです。

0
Rudi