Git Stashをワークフローとして使用するのはアンチパターンですか?


25

最近、私と私のチームがGitをどのように使用し、ワークフローがどのように機能するかを調べてきました。現在、機能ブランチワークフローを使用していますが、うまく機能しているようです。

また、私たちのチームの何人かの個人がgit stashに基づくワークフローを使用しているのを見ました。ワークフローは次のようになります。

  • メインブランチで作業する(などmaster
  • 進行中にコミットする
  • 変更を取得するか、ブランチを切り替える必要がある場合は、コミットされていない変更をスタッシュにプッシュします
  • 更新が完了したら、変更をスタッシュからポップします。

このワークフローは、機能ブランチワークフローの代わりに使用されることに言及する必要があります。ここでの開発者は、ブランチを取得して作業する代わりに、単一のブランチでのみ作業し、適切と思われるスタックからプッシュ/ポップします。

実際、これは素晴らしいワークフローではないと思うので、この方法でgit stashを使用するよりも分岐が適切です。git stashの価値は緊急操作として見ることができますが、毎日の通常のワークフローで使用することはできません。

git stashを定期的に使用することはアンチパターンと見なされますか?その場合、発生する可能性のある特定の問題は何ですか?そうでない場合、利点は何ですか?


2
同僚にワークフローに問題があるかどうかを尋ねることができます。もしそうでなければ、私はそれが有害だとは思わないでしょう。
AlexFoxGill 14

@AlexGこれは有効なポイントです。私はここで質問をして、人々が見つけた「落とし穴」があるかどうかを確認しています。
joshin4colours 14

3
私がそれを正しく理解していればIf you need to get changes or switch branches, push your uncommitted changes onto the stash...- それはまさに隠し場所の目的です。

3
@MichaelT私のローカルブランチはすべてを許可します。無条件。
maaartinus

2
私のパターンは次のとおりです。-> git stashを使用しない->機能ブランチを使用する->「wip」のコミットメッセージで進行中の作業を保存する。->ブランチをインタラクティブにリベースして、wipを1つの意味のあるコミットに押しつぶしますローカルのプッシュされていない変更のみです。->リモートにプッシュ-> gitワークフローに合わせてマスターにマージ(およびプッシュ)します。
マイケルデュラント14

回答:


31

以下からのGit SCMブック

多くの場合、プロジェクトの一部で作業しているとき、物事は乱雑な状態にあり、他の何かで作業するためにブランチを少し切り替えたいと思います。問題は、後でこのポイントに戻ることができるように、半完了作業のコミットを行いたくないことです。この問題に対する答えは、git stashコマンドです。

Stashingは、作業ディレクトリのダーティー状態(つまり、変更された追跡ファイルとステージングされた変更)を取得し、いつでも再適用できる未完成の変更のスタックに保存します。

この説明を考えると、これはアンチパターンだと思います。Git Stashの非常に単純化された説明は、それがソース管理の「カットアンドペースト」であるということです。たくさんの変更されたファイルを取り出し、Gitの通常のブランチワークフローの外にある保持ペンで「隠して」、それらの変更を後日別のブランチに再適用します。

少し戻って、マスターコミットすることは、ここでのアンチパターンです。ブランチを使用します。それは彼らが設計されたものです。

それは本当にこれに要約します:

あなたは壁にネジを打ち込むことができ、それは写真を保持しますが、ドライバーを使用することはあなたがすべきことです。ドライバーがあなたのすぐそばに座っているときは、ハンマーを使用しないでください。

「壊れた」コードのコミットについて

以下は意見ですが、私は経験からこの意見に来ました。

早期にコミットし、頻繁にコミットします。必要なだけ壊れたコードをコミットします。ローカルコミット履歴を「保存ポイント」として表示し、何かをハックします。論理的な作業が完了したら、コミットを行います。確かにそれはすべてを壊すかもしれませんが、それらのコミットをプッシュしない限り、それは問題ではありません。プッシュする前に、コミットをリベースおよびスカッシュします。

  1. 新しいブランチを作成
  2. ハックハックハック
  3. 壊れたコードをコミットする
  4. コードを磨き、機能させる
  5. 作業コードをコミットする
  6. リベースとスカッシュ
  7. テスト
  8. テストに合格したらプッシュする

OPにとっては、このLinuxカーネルメッセージスレッドが興味深いかもしれません。OPのチームの一部のメンバーが同様の方法でGitを使用しているように聞こえるからです。

@RibaldEddieは以下のコメントで言った:

まず第一に、隠し場所は「分岐ワークフロー」の外にありません。なぜなら、隠し場所は隠し場所にすぎないからです。

(多くの人々の怒りを被るリスクがある)

ライナスは言った:

「git stash」を使用すると、複数の異なる隠されたものを持つこともできますが、それらは互いにキューに入れられません-それらは、ある時点で不便だったため、隠しておいたランダムな独立したパッチです。

@RibaldEddieが言おうとしていることgit stashは、機能ブランチワークフローで使用できるということです。これは事実です。git stash問題はそれを使用することではありません。これは、マスターへのコミットと使用の組み合わせですgit stashこれはアンチパターンです。

明確化 git rebase

@RibaldEddieのコメントより:

リベースはコピーペーストに似ており、さらに悪いことにコミットされた履歴を変更します。

(エンファシス鉱山)

ローカルのコミット履歴である限り、コミット履歴の変更は悪いことではありません。すでにプッシュしたコミットをリベースする場合、ブランチを使用している他の誰かを本質的に孤立させます。これは悪いです。

ここで、1日の間にいくつかのコミットを行ったとしましょう。一部のコミットは良好でした。いくつか...あまり良くない。git rebaseあなたのコミットを退治と一緒にコマンドがローカルのコミットの歴史をクリーンアップするための良い方法です。チームの共有ブランチのコミット履歴をクリーンに保つため、パブリックブランチへの1つのコミットにマージすると便利です。リベース後、再度テストする必要がありますが、テストに合格すると、いくつかのダーティなコミットの代わりに1つのクリーンコミットをプッシュできます。

クリーンなコミット履歴に関する別の興味深いLinuxカーネルスレッドがあります。

繰り返しますが、Linusから:

クリーンな履歴が必要ですが、それは本当に(a)クリーンと(b)履歴を意味します。

人々は自分のプライベートツリーをリベースできます(おそらくそうすべきです)(自分の仕事)。それはクリーンアップです。しかし、他の人々のコードは決してありません。それは「歴史を破壊する」

したがって、履歴部分はかなり簡単です。主要なルールは1つ、マイナーな説明は1つだけです。

  • 他の人々の歴史を決して破壊してはいけません。他の人が行ったコミットをリベースしてはいけません。基本的に、サインオフが設定されていない場合、制限はありません。リベースすることはできません。なぜなら、それはあなたのものではないからです。

    これは他の人々のコードではなく、他人の歴史に関するものであることに注意してください。彼らが電子メールで送られたパッチとしてあなたに物を送って、あなたが「git am -s」でそれを適用したなら、それは彼らのコードですが、それは あなたの歴史です。

    そのため、コミット自体がプライベートなものである限り、コードを記述していなくても、「git rebase」に夢中になります。

  • ルールの軽微な説明:ある公開サイトで履歴を公開すると、他の人がそれを使用している可能性があるため、明らかに個人の履歴ではなくなりました。

    それで、マイナーな明確化は、それが「あなたのコミット」だけではなく、それがあなたのツリーに対してプライベートであることでもあり、それをまだ押し出してアナウンスしていないということです。

...

「クリーン」な部分はもう少し微妙ですが、最初のルールは非常に明白で簡単です。

  • 自分の履歴を読みやすくする

    一部の人々は、頭の中で物事を先に解決し、間違いを犯さないことでこれを行います。しかし、それは非常にまれであり、私たちの残りの部分では、問題に取り組んでいる間に「git rebase」などを使用します。

    したがって、「git rebase」は間違っていません。しかし、それはあなた自身の非常にプライベートなgitツリーである場合にのみ正しいです。

  • がらくたをさらさないでください。

    つまり、まだ「git rebase」フェーズにいる場合は、プッシュしないでください。準備ができていない場合は、パッチを送信するか、一般の人々に一般に伝えないプライベートgitツリーを(「パッチシリーズの置換」として)使用します。

(エンファシス鉱山)

結論

最終的に、OPにはこれを行う開発者がいます。

git checkout master
(edit files)
git commit -am "..."
(edit files)
git stash
git pull
git stash (pop|apply)

ここには2つの問題があります。

  1. 開発者はマスターにコミットしています。これをすぐにロックします。本当に、これが最大の問題です。
  2. 開発者は、常に使用しているgit stashgit pull、マスターに、彼らは機能ブランチを使用する必要があるとき。

git stash特にプルの前に使用することには何の問題もありませんがgit stash、Gitに優れたワークフローがある場合、この方法で使用することはアンチパターンです。

git stashニシンの使用。それは問題ではありません。マスターにコミットすることが問題です。


4
うわー、これは正しくありません。まず第一に、隠し場所は「分岐ワークフロー」の外にありません。なぜなら、隠し場所は隠し場所にすぎないからです。コピーアンドペーストワークフローであるという考えは意味がありません。リベースはコピーペーストに似ており、さらに悪いことにコミットされた履歴を変更します。最後に、変更をプッシュするとすぐにバラバラになるため、進行中の作業を同僚と共有する必要があるとすぐに、ワークフローはまったく役に立ちません。これがどのように6つのアップ投票を持っているかは気が遠くなるでしょう。
RibaldEddie 14

8
@RibaldEddie:コミット履歴がローカルのコミット履歴である限り、コミット履歴のリベースと書き換えに問題はありません。これらのコミットをプッシュすると、コメントは正しいものになりますが、私の答えを読み直してください。「コミットをプッシュ、リベース、スカッシュする前に」と書かれています。これはローカルコミット履歴であり、完全に管理下にあります。
グレッグブルクハート14

1
@RibaldEddie:答えを明確にしました。いくつかのクリーンアップが必要でした。
グレッグブルクハート14

私自身の答えでもう少しコンテキストを提供します。
RibaldEddie

以下の私の答えを参照してください-マスターにコミットすることはアンチパターンですが、それは本当の問題ではありません。
RibaldEddie

7

私は個人的stashには、別のブランチへの変更を必要とする質問をする人のように、短い予期しない中断にのみ使用します。私は以前に隠し場所を忘れていたので、これを行います、そして、彼らはきれいに適用しません。機能ブランチでの定期的なコミットは忘れるのがはるかに難しく、マージが容易なので、今は壊れたコミットを行い、git reset HEAD~1後でそれを保持したくない場合はリベースを行う傾向があります。

ただし、分散バージョン管理の素晴らしい点は、共有リポジトリが標準を満たしている限り、自分のリポジトリで好みのワークフローを使用できることです。stash十分なトレーニングや代替手段の認識がないため、人々がワークフローを使用しているのではないことを確認しますが、まだ最適でないワークフローを選択した場合はそのままにします。


1

アンチパターンであるあなたの質問の部分は、単一の共有マスターブランチの使用だと思います。ただし、マスターブランチに加えて開発ブランチを含め、開発ブランチで独自のコンテキストスイッチを処理するためにスタッシュを使用する場合、それはアンチパターンではなく、ワークフローの一部を非常に厳密に反映しますEtsyやFacebookなどの組織で説明する。

そうは言っても、上記の@Greg Burghardtの答えは、いわゆるgitフローまたは機能ブランチのワークフローよりも少し好意的です。私は以前も同様の戦略を提唱していましたが、それが不必要な複雑さを追加し、セキュリティの誤った感覚を作り出すことに気付いた後、私はもはやしません。また、Subversionのような非分散型バージョン管理システムの時代からのホールドオーバーでもあります。

まず、GitはSubversionとは異なり分散型のバージョン管理システムであるため、開発者のローカルリポジトリは、本質的にコード自体の巨大なブランチです。個々の開発者がローカルで行うことは、破損したコードまたはバグのあるコードが共有リポジトリ内の共有ブランチにプッシュされない限り、他のチームメンバーに影響を与えません。

ただし、リベースコマンドは、リプレイされたコミットの1つにマージの競合がある場合、ブランチの履歴を損傷する可能性があります。http://ryantablada.com/post/the-dangers-of-rebasing-a-branchから

残りのリベースはスムーズに進み、テストはすべて合格したようです。PRが作成されます。

そして、commentsForAllPostsプロパティに依存するコードがさらに記述され、すべてが壊れます。しかし、誰に助けを求めに行くのでしょうか?git blameは、コード行がサーバー側のエンジニアによってのみ記述されており、彼が手を放したことを示しています。

これで、フロントエンドエンジニアは休暇中、病気休暇中、または誰が知っていますか。そのコードがどのように見えるべきかを誰も理解できません!

Rebaseは、子ブランチでのマージの競合がすべて削除され、元のコードが永久に失われるため、履歴を参照して問題の原因を見つけるチームの機能を無効にしました。

この同じマージ競合が発生し、マージが使用された場合、非難は、マージプロセス、親ブランチでのコミット、および子ブランチでのコミットでそのコード行が変更されたことを示します。3つの順列をいじり回すと、元の意図をコードベースに戻して、大量の頭が指を指すことなく動作するようになります。そして、あなたが本当に持っていたのは別のコミットだけでした

さらに、複数の分岐モデルでは、2つの分岐が相互に依存するコード変更を含むことはできません。それが避けられない場合、開発者は効率的に作業するためにさらに多くのブランチを調整する必要があります。

私が見る基本的なアンチパターンは、ブランチとスタッシュに関連するものではなく、かなり賢い人がしばらく話している種類の問題に関するものです:あなたはあなたのコードを使用してあなたのコードに自信がありますか?単体テストと優れたアーキテクチャ?開発者が変更について簡単に推論し、変更が何を行うかを理解できるように、コードに段階的な変更を加えることができますか?開発者は、新しいコードを一度実行して、実際に機能するかどうかを確認しますか?(はい、私は前にこれを見ました)。

それらの質問に対する答えがいいえの場合、実際にいくつのブランチを持っているかは重要ではありません。開発者は、コードが準備が整っており、実際に動作しておらず、実稼働に適していると言います。とにかくそのコードが本番に移行するときに役立ちます。


2
マージ解決に問題があることをリベースすることについてのあなたのコメントは正しくありません。リベースは、実際のマージと同じ種類のマージです。Gitは、内部でコミットをマージしているだけです。マージの競合をリベースおよび解決しても、コミット履歴に損傷を与えることはありません。マージの競合をリベースして不適切に解決すると、物事にダメージを与えます。これは通常のマージと同じように起こります。機能ブランチは複雑さを増すことに同意する必要がありますが、開発者が複数の無関係な変更を処理しなければならない場合、これは必要な複雑さになる可能性があります。
グレッグブルクハート14

マージは履歴を破壊する可能性があると言っているのですか?!ブランチが多すぎることを避けるための単なる正当化のようです!
RibaldEddie 14

1
マージは履歴を破壊できません。リベースとマージがどのように機能するかを誤解していると思います。マージの競合がトリガーされた場合、それを解決するのは人間次第です。人間が誤って解決した場合、Git(またはSVN、CVS、または{ここにソース管理を挿入})を責​​めることはできません。
グレッグブルクハート14

さて、あなたが言っていることはあなたが前に言ったこととある種の矛盾です。引用した記事を読みましたか?リベースが履歴を失う状況を理解していますか?
RibaldEddie

1
私は記事を読みました。「Keenでは、ほぼ毎コミット後にコードをプッシュしようとしています。」それは私には夢中に聞こえます。過度に大きなコミットを行っているか、まだ準備ができていないコードをプッシュしています。すべてのコミットをすぐに公開すると、リベースが問題を引き起こします。それは「医者、医者、これをやると痛い」という原則です。
キラレッサ14

1

git stashツールです。それ自体はパターンではなく、アンチパターンでもありません。ハンマーが道具であるように、それは道具です。ハンマーを使用して釘を打つことはパターンであり、ハンマーを使用してネジを打つことは反パターンです。同様に、git stash使用する正しいツールであるワークフローと環境、および間違っているワークフローと環境があります。

「全員がメインラインにコミットしてプッシュする」ワークフローは、リスクの高い変更がない場合に非常に合理的に機能するワークフローです。コードを持っている権威ある中央サーバーが1つあるsvn環境でよく使用されます。

ただし、Gitは1つの中央サーバーを廃止します。すべての開発者がを実行しているcommit場合pull(またはrebase、それに興味がある場合)、push常に大きな混乱を招く可能性があります。

最大の問題は、進行中の何かが壊れているために発生するものであり、優先度の高いバグに取り組む必要があります。これは、その作業を少し脇に置いて、最新のもの入手し、前の進行中の作業があなたがしようとしているビルドの問題を引き起こすことなく作業する必要があることを意味します。

このgit stashために、使用する適切なツールになります。

ただし、このワークフローの中心には大きな問題が潜んでいます。であるということである、すべてのバージョン管理枝の役割は、単一の分岐です。メインライン、開発、保守、蓄積、パッケージングは​​すべてマスターにあります。 これは問題です。(分岐へのこのアプローチの詳細については、高度なSCM分岐戦略を参照してください)

そして、はい、あなたはそれが素晴らしいワークフローではなく、それに問題があることを強調しました。ただし、問題はツールにありませんgit stash。問題は、役割または互換性のないポリシーの明確な分岐の欠如です。

git stashしかし、私は少しの間構築した状況があったときに使用したものであり、それが正しいものであるかどうかわからない粘着状態になった...それで私は私の変更を隠したそして、問題を解決するための別のアプローチを検討しました。それがうまくいった場合-素晴らしい、スタッシュにあるものを破棄して続行します。他の探査がより粘り気になった場合は、以前の変更にリセットし、スタッシュを再適用してその上で動作します。別の方法としては、コミット、チェックアウト、ブランチしてから、この新しいブランチで続行するか、戻ってリセットすることです。問題は、それをちょっと探求したいときに、それを歴史に入れる価値は本当にあるのか、ということです。

git stashアンチパターンではありません。git stash全員がマスターにコミットしている間に分岐する代わりとして使用することはアンチパターンですが-ではありませんgit stash

まだヒットしていない場合ビルド問題発生するまで待ってください。誰かが多くのファイルにアーキテクチャ上の大きな変更を加える必要がある場合(およびマージの競合)、またはこのために本番環境に漏れるテストされていない作業中のコードあなたに追いつくためのアンチパターン。

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