web-dev-qa-db-ja.com

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

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 '[email protected]: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を嫌うようになりますか?

111
Matt

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

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つの理由があります。最初に、develブランチから切り替える必要なく、リモートの変更があるかどうかを確認できるためです。第二に、隠されていない/コミットされた変更を上書きしないようにするための安全メカニズムです。また、マスターブランチへの早送りマージができない場合、誰かがリモートマスターをリベースしている(そのために厳しくむち打たれる必要がある)か、誤ってマスターにコミットして終わりをクリーンアップする必要があることを意味します。

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

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'

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

83
Trevor Norris

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

ヒント:上記はフォースプッシュの正当な使用法です。誰もがアクセスできるリポジトリで履歴を書き換えないでください。そうしないと、多くの人があなたを嫌います。

44
Learath2

ここで心に留めておくべき主なことは、pullとrebaseが舞台裏で行っていることです。

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

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

(これは、リベースを実行するときに複数の競合解決プロンプトが表示される理由と、マージで取得できる競合解決が表示される理由を説明しています。 )

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

これには、次のいずれかの力を使用して、リベースされた変更を時々プッシュする必要があります。

git Push -f Origin newfeature

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

git Push Origin :newfeature
git Push Origin newfeature

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

次を利用することで、ほとんどの場合、gitのGCにフォールバックできることを忘れないでください。

git reflog

すべてのリベース/競合管理で迷子になった場合、より安定した状態にリセットできるため、これは大きな命の恩人です。

28
Matthew Sanders

強制プッシュ、つまりgit Push -f Origin myNewFeatureを実行する必要があります

ああ、あなたは人々があなたの開発ブランチに何も基づいていないことを気にした方が良いです-通常、あなたはあなたが履歴を書き換えているブランチを公開することは想定されていません1つの方法は、wip/myNewFeatureなどのブランチ名を使用し、wipブランチが時々マスターにリベースされることに言及することです。

2
ThiefMaster

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

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

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

これは、Gitflowワークフローの単純化されたバージョンと考えることができると思います。

1
cosmicFluke

MrCholo に同意し、おそらく Trevor Norrisgood answer を更新することを検討できます

git Push -f Origin devel0

git Push --force-with-lease Origin devel0
0
Sylvain Lesage