144

私たちは 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

編集

したがって、これはワークフローを壊すように思えます:

developer1 は myNewFeature に取り組んでいます developer2 は hisNewFeature に取り組んでいます 両方とも master をメイン ブランチとして使用します

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

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

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

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

4

6 に答える 6

98

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

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 ブランチから切り替える必要なく、リモートでの変更があるかどうかを確認できるためです。2 つ目は、隠していない/コミット済みの変更を上書きしないようにするための安全メカニズムです。また、master ブランチへのマージを早送りできない場合は、誰かがリモート マスターをリベースしたか (そのため、厳しく非難する必要があります)、または誤って 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

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

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

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

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

git branch 'my-name/devel-branch'

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

于 2013-02-28T19:44:13.357 に答える
60

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

ヒント: 上記は強制プッシュの正当な使用法です。公にアクセス可能なリポジトリの履歴を決して書き換えないでください。そうしないと、多くの人に嫌われます。

于 2013-02-28T18:39:22.243 に答える
31

ここで留意すべき主なことは、pull と rebase が舞台裏で何をしているのかということです。

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

リベースは、ブランチ以降のすべてのローカル変更をスタッシュし、ブランチをターゲットの最新のコミットに早送りし、変更を順番にアンスタッシュすることに似ています。

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

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

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

git push -f origin newfeature

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

git push origin :newfeature
git push origin newfeature

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

以下を利用することで、ほぼ常に git の GC にフォールバックできることを覚えておいてください。

git reflog

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

于 2013-02-28T18:52:20.740 に答える
2

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

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

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

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

于 2015-11-17T22:22:43.747 に答える
2

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

ああ、そして、人々があなたの dev ブランチに基づいていないことを確認したほうがいいです - 通常、履歴を書き換えているブランチを公開することは想定されていません (または、公開された履歴を書き換えないでください)。1 つの方法は、次のようなブランチ名を使用して、ブランチが時々 master にリベースされることwip/myNewFeatureを言及することです。wip

于 2013-02-28T18:39:12.180 に答える
2

私はMrCholoに同意します。トレバー・ノリスは、良い答えを更新して置き換えることを検討できるかもしれません。

git push -f origin devel0

git push --force-with-lease origin devel0
于 2018-11-29T14:33:28.413 に答える