リベース後にブランチにプッシュできません


131

gitを使用し、masterブランチとdeveloperブランチがあります。新しい機能を追加してから、コミットをマスターにリベースし、マスターをCIサーバーにプッシュする必要があります。

問題は、リベース中に競合が発生した場合、リベースが完了した後、リモートブランチをプルするまで、(Github上の)リモート開発者ブランチにプッシュできないことです。これにより、コミットが重複します。競合がない場合、期待どおりに動作します。

質問:リベースと競合の解決後、重複したコミットを作成せずにローカルおよびリモートの開発ブランチを同期するにはどうすればよいですか

セットアップ:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git push origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git push origin myNewFeature

//ERROR
error: failed to push some refs to 'git@github.com:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

// do what git says and pull
git pull origin myNewFeature

git push origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

編集

だからこれはワークフローを壊すように聞こえます:

myNewFeatureに取り組んでいるdeveloper1 hisNewFeatureに取り組んでいるdeveloper2はどちらも主ブランチとしてmasterを使用しています

developer2はmyNewFeatureをhisNewFeatureにマージします

developer1はリベースし、競合を解決してから、myNewFeatureのリモートブランチへのプッシュを強制します

数日後、developer2はmyNewFeatureを再びhisNewFeatureにマージします

これにより、他の開発者はdeveloper1を嫌いますか?


解決策ではなく単なる考えです。誰we?あなたはあなた以上のチームにいますか?they(私よりも多くのことを知っている人たちに)コードを共有する場合は、使用すべきではないと言うrebase。なぜあなただけやっていないgit pullgit merge
AdamT 2013

申し訳ありません、We =開発チーム
Matt

1
そうです、コードを共有しているときは、おそらくリベースしてはいけません。そのforceため、以下にリストされているような処理(プッシュ)が必要になる可能性があります
AdamT

申し訳ありませんが、彼らが言うときrewriting history、それはaですrebase
AdamT

彼が言ったように、誰かがマージすることが期待された場合を除きという問題があってはならない、彼自身ので、その開発ブランチ。
Learath2

回答:


93

まず、あなたと一緒に作業している人は、トピック/開発ブランチが共有開発用か、自分のブランチ用かを合意する必要があります。他の開発者はいつでもリベースされるため、私の開発ブランチにマージしないことを知っています。通常、ワークフローは次のとおりです。

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

次に、リモートで最新の状態を保つには、次のようにします。

 git fetch origin
 git checkout master
 git merge --ff origin/master

これを行う理由は2つあります。1つ目は、develブランチから切り替える必要なく、リモートの変更があるかどうかを確認できるためです。2つ目は、非保存/コミットされた変更を上書きしないようにするための安全メカニズムです。また、masterブランチにマージを早送りできない場合は、誰かがリモートマスターをリベースした(深刻な問題が発生する可能性がある)か、誤ってマスターにコミットして、最後をクリーンアップする必要があることを意味します。

次に、リモートに変更があり、最新のものに早送りした場合、リベースします。

git checkout devel0
git rebase master
git push -f origin devel0

他の開発者は、開発ブランチを私の最新のものからリベースする必要があることを知っています。

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

これにより、履歴がより明確になります。

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

気まぐれにコミットを前後にマージしないでください。重複したコミットが作成されて履歴を追跡できなくなるだけでなく、特定の変更による回帰を見つけることがほぼ不可能になります(そのため、そもそもバージョン管理を使用していますよね?)。あなたが抱えている問題は、これを実行した結果です。

また、他の開発者があなたの開発ブランチにコミットしているようです。これを確認できますか?

マージする唯一の時間は、トピックブランチがに受け入れられる準備ができたときmasterです。

余談です。複数の開発者が同じリポジトリにコミットしている場合は、開発者と開発者のブランチを区別するために、すべて名前付きブランチを使用することを検討する必要があります。例えば:

git branch 'my-name/devel-branch'

したがって、すべての開発者トピックブランチは、独自のネストされたセット内に存在します。


1
「また、他の開発者があなたの開発ブランチにコミットしているようです。これを確認できますか?」はい、そうです...
マット

また、別の問題についても注目していただきました。オフィスと家の間で働く。両方の場所でマージを行い、1日の終わりにプッシュを終了して、中断したところから再開できるようにします。次に、リベースするときが来ると、それらすべてのコミットが混乱を引き起こします。私は自分のブランチを1つのブランチとして扱い、リベースする必要があります
Matt

@Mattええ、これらの2つの問題は本当にワークフローを台無しにするでしょう。最初に、所有者だけが名前付きブランチにコミットできることを他の開発者に伝えます(たとえば、 'matt / devel')。どちらにせよ、2人の開発者が同じブランチにコミットするべきではありません。混乱を招くだけです。後者の場合、リベースと強制プッシュにより、2つの場所が最新の状態に保たれます。
Trevor Norris

すばらしい答えです。余談ですが、なぜ--forceフラグを使用するのですgit push -f origin devel0か?
のび太

2
@Nobita git pushが早送りできない場合(つまり、shaの履歴が一致しない場合)は、から生成された新しい履歴で以前の履歴を強制的に上書きする必要がありますgit rebase
Trevor Norris、

50

コミットをブランチの下に移動したので、プッシュを強制する必要があります。gitは、ブランチの先端にコミットを追加することを期待しています。git push -f origin myNewFeatureあなたの問題を修正します。

ヒント:上記はフォースプッシュの正当な使用法です。公にアクセス可能なリポジトリの履歴を書き換えることは絶対にしないでください。


1
これはワークフローを維持するための最適な方法です。
Syed Priom 2017年

1
どうも。このコマンドを使用して、リベースのローカルブランチを同じリモートブランチに強制しました。
wei

11
を使用する方git push --force-with-leaseが使用するよりもはるかに安全git push --force

git push --force-with-lease origin HEAD-ターゲットブランチが既にチェックアウトされていると仮定します
Lucaci Sergiu

31

ここで留意すべき主なことは、プルとリベースが舞台裏で行っていることです。

プルは基本的に2つのことを行います:フェッチとマージです。--rebaseを含めると、マージではなくリベースが実行されます。

リベースは、ブランチ以降のローカルの変更をすべて隠し、ブランチをターゲットの最新のコミットに高速転送し、変更を上から順番にアンスタックするのとほとんど同じです。

(これにより、リベースを実行するときに複数の競合解決プロンプトが表示される場合と、マージで取得できる1つの競合解決結果が表示される場合がある理由がわかります。コミットを保持するために、リベースされている各コミットの競合を解決する機会があります。 )

これはリライティング履歴であるため、リベースされた変更をリモートブランチにプッシュしたくはありません。たいていの場合、例外が常にあるので、決して強くありません。たとえば、特定の環境で動作するようにローカルリポジトリのリモートバージョンを維持する必要がある場合。

これには、強制的にリベースの変更をプッシュする必要がある場合があります。

git push -f origin newfeature

または、場合によっては、管理者が強制する機能を削除したため、削除して再作成する必要があります。

git push origin :newfeature
git push origin newfeature

どちらの場合も、リモートブランチで他の誰かがあなたと協力している場合は、自分が何をしているかを確実に知っている必要があります。これは、最初にマージと一緒に作業し、作業ブランチをマスターして削除する直前に、それらをより管理しやすいコミット形式にリベースすることを意味します。

ほとんどの場合、次の利点を活用することでgitのGCにフォールバックできます。

git reflog

すべてのリベース/コンフリクト管理で道に迷った場合、より安定した状態にリセットできるので、これは非常に大きなライフセーバーです。


上記の削除と再作成のオプションは私にはうまくいきました。私のリポジトリでは強制は許可されていません!
Simon Holmes

2

強制プッシュを実行する必要があります。 git push -f origin myNewFeature

ああ、そしてあなたは人々があなたの開発ブランチに何も基づいていないことを確認した方がいいです-通常、あなたはまったくあなたが履歴を書き換えているブランチを公開することになっているのではありません(あるいはむしろ一度公開された履歴を書き換えないでください)。1つの方法は、のようなブランチ名を使用wip/myNewFeatureし、wipブランチは時々マスターするためにリベースされることを言及することです。


使用する方git push --force-with-leaseが使用するよりもはるかに安全git push --force

@MrCholo Peopleは-f、通常の強制プッシュのようにgitが短いオプションを追加するまでこれを使用し始めません:)
ThiefMaster

ええ、私は自動スクリプトで使用しました

2

すでに与えられている一般的な答え- git push -f origin myNewFeatureリベースされた変更をプッシュするときに使用する-は良い出発点です。私はこの回答を書いて、ワークフローを壊すかどうかについての編集に対処します。

使用するgit pull --rebase ...(またはそのバリエーション)の後にリモートブランチへの強制プッシュを行うと想定している場合、この例のワークフローを中断するのはdeveloper2がにマージmyNewFeatureすることhisNewFeatureです。他の誰もそのブランチで作業していない限り、自分の機能ブランチをリベースできることは理にかなっているので、ブランチの領域を区別するルールが必要です。

これを回避するにはmaster、a)からのみマージするルールを確立するか、またはb)develop独自のmyNewFeatureブランチのベースとなる集合ブランチを作成し、からのみマージするルールを確立しますdevelopmasterその後、マイルストーンまたはリリース(またはそれ以外の場合はそれを設定する)に対してのみ予約developされ、他の機能ブランチに統合する準備ができたときに各機能をプッシュする場所になります。

これは、Gitflowワークフローの簡易バージョンと考えることができると思います。


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