web-dev-qa-db-ja.com

「gitマージ」後もコミット履歴を保持する

2つの異なる機能(masterから作成された2つの異なるブランチ)で作業する場合、マージを続行するとコミット履歴がないので非常に不愉快です。

もっとよく説明します。 Branch-Aの作業が終了したら、それをmasterにマージします。そして、私がgit logBranch-Aで行ったすべてのコミットが表示されます。

代わりにBranch-Bで作業を終了し、master(その後Branch-Aは既にマージされています)、マージのコミットメッセージを指定する必要があります(最初のブランチでは何も尋ねられていません)。 masterにマージした後、git logBranch-Bのコミットが私のmasterブランチの履歴に表示されません

私が持っているとしましょう

**Branch A**

commit 09b2unfas9d781n2e
    Add more stuff

commit 8uj8masd89jas898a
    Add stuff

**Branch B**

commit 09b2unfas9d781n2e
    Add feature setting

commit 8uj8masd89jas898a
    Add feature

私は持っています

**Master**

commit 6hf6h8hd871udjkdn
Merge: 09b2un 34osd6
    Merge branch 'Branch-B' into master

commit 09b2unfas9d781n2e
    Add more stuff

commit 8uj8masd89jas898a
    Add stuff

commit 34osd62dhc91123j8
    I'm a previous commit from 'master'.
    The last one before branching...

一方で入手したいのようなもの:

**Master**

commit 09b2unfas9d781n2e
    Add feature setting

commit 8uj8masd89jas898a
    Add feature

commit 09b2unfas9d781n2e
    Add more stuff

commit 8uj8masd89jas898a
    Add stuff

commit 34osd62dhc91123j8
    I'm a previous commit from 'master'.
    The last one before branching...

...実行されたコミットの履歴をより正確に反映します。

2つのブランチのうちの1つだけから履歴を保持できる理由がわかりません。

マージされたコミットの実際の履歴を非表示/除外するmergeコミットなしですべてを明確に保つにはどうすればよいですか?

23
Kamafeather

最初のマージは早送りであり、2番目のマージは3者間マージのようです。

説明

Gitには、早送りと3方向の2つのバージョンのマージがあります。 (他のバージョンもありますが、ここではそうではありません。)デフォルトの動作では、可能な場合は早送りマージを行い、それ以外の場合は3方向マージを行います。

早送りマージ(この動作をオプション--ff-onlyで強制できます。これにより、早送りが不可能な場合にマージが失敗します)は、マージされているコミットの現在の位置がその歴史の中で枝。例えば:

A - B - C - D <-master
             \
              E - F - G <- branch-a

git merge(デフォルト設定)を実行すると、

A - B - C - D - E - F - G <- branch-a <-master

マージコミットがないため、マージコミットを編集することもできません。ただし、これが発生すると、他のブランチはマスターから分岐します(先に進むだけではありません)。

A - B - C - D  - E - F - G <-master
                  \
                   E1 - E2 <- branch-b

したがって、GitはマスターのポインターをGからE2に移動するだけでは、FおよびGで行われた変更を取り除くことができません。代わりに、3者間マージが発生し、2つの親を持つコミットが作成され、コミットメッセージも表示されます。これで、マスターをこのコミットに移動できます。 (この状況では、マスターとブランチBは同じコミットを指さないことに注意してください。

A - B - C - D  - E - F - G - H <-master
                  \       /
                   E1 - E2 <- branch-b

線形履歴が必要な場合は、リベースを使用する必要がありますが、他の誰かがブランチのコミットを見た場合は、この回答の範囲を超える問題が発生する可能性があることに注意してください。リベースの使用には、リベースとその後の早送りマージという2つのステップが含まれます。したがって、マージする代わりに、まずbranch-bgit rebase masterを実行しながら次のコマンドを実行します。これにより、古いコミットのコピーである新しいコミットが作成されます。つまり、同じ変更セット、作成者の情報とメッセージですが、新しいコミッター情報と親の履歴です。 (図ではコミットE1 'とE2'を呼び出して、それらが単なるコピーであることを示しています。)古いコミットは、ガベージコレクションされるまで存在しますが、reflogを確認しない限り、到達できません。)

A - B - C - D  - E - F - G <-master
                  \       \
                   E1 - E2 \ 
                            E1' - E2' <- branch-b

git checkout master; git merge --ff-only branch-bを実行すると、変更がマスターに早送りされるため、線形履歴が得られます。

A - B - C - D  - E - F - G - E1' -E2' <-master <- branch-b
32

rebaseの代わりに merge を使用します。 チュートリアル から:

リベースされたブランチのログを調べると、それは線形履歴のように見えます。最初に並行して発生した場合でも、すべての作業が連続して発生したように見えます。

Branch-Bは、fast-forwardを使用してmasterにマージすることはできません。このような場合、 three-way-merge が実行されます。

Gitはブランチポインターを前方に移動するだけでなく、この3者間マージの結果として新しいスナップショットを作成し、それを指す新しいコミットを自動的に作成します。これはマージコミットと呼ばれ、複数の親を持つという点で特別です。

線形履歴を保持するために、コミットをmasterにコミットする前に、常にリベースします。

5
Yan Foto