For Git v2.22, the following information regarding the --rebase-merges
option can be found on the git rebase documentation page:
By default, or when no-rebase-cousins was specified, commits which do not have
<upstream>
as direct ancestor will keep their original branch point, i.e. commits that would be excluded by git-log's --ancestry-path option will keep their original ancestry by default. If the rebase-cousins mode is turned on, such commits are instead rebased onto<upstream>
(or<onto>
, if specified).
Unfortunately, the detailed documentation sections at the bottom of that page do not show any examples of the no-rebase-cousins
or rebase-cousins
options to --rebase-merges
. I'm also not too familiar with git log --ancestry-path
(I never use it), so that example doesn't help my understanding at all.
Can someone explain, with examples, the behavior of the rebase-cousins
parameters to the --rebase-merges
option?
Git Merge Vs Git Rebase:Git merge is a command that allows you to merge branches from Git. Git rebase is a command that allows developers to integrate changes from one branch to another. In Git Merge logs will be showing the complete history of the merging of commits.
What is git rebase? Rebasing is the process of moving or combining a sequence of commits to a new base commit. Rebasing is most useful and easily visualized in the context of a feature branching workflow.
But, instead of using a merge commit, rebasing re-writes the project history by creating brand new commits for each commit in the original branch. The major benefit of rebasing is that you get a much cleaner project history. First, it eliminates the unnecessary merge commits required by git merge .
For each change you make, you'll need to perform a new commit, and you can do that by entering the git commit --amend command. When you're finished making all your changes, you can run git rebase --continue . Git then gets to the reword 4ca2acc command.
This is probably best done by example.
Suppose you have:
...--o--*--o--o <-- main
\
\ C--D
\ / \
A--B G--H <-- branch
\ /
E--F
You want to rebase branch
onto main
, with --rebase-merges
. The enumeration of main..branch
lists commits A
through H
. OK, the goal is obvious: Git should copy commits A-B-(C-D/E-F)
to new commits to make A'
, B'
, etc., then run a new git merge
to make G'
, and finally copy H
to make H'
, all of which come after the tip of main instead of coming after commit *
. You end up with:
C'-D'
/ \
A'-B' G'-H' <-- branch
/ \ /
/ E'-F'
/
...--o--*--o--o <-- main
\
\ C--D
\ / \
A--B G--H [abandoned]
\ /
E--F
But suppose you have instead:
...--o--*--o---o <-- main
\ \
\ A--B---F--G <-- branch
\ /
C--D--E
You run git checkout branch; git rebase --rebase-merges main
. The enumeration, main..branch
, lists commits A-B-F-G
and C-D-E
too.
Which commits do you want copied? Do you want to keep C-D-E
as they are, or copy them? You do want to re-perform the merge that produced F
, merging your new copy B'
with something, but is that with E
, or is that with E'
, the new copy of E
?
The option allows you to avoid copying C-D-E
, which aren't in the ancestry path from *
to H
—git log --ancestry-path main..branch
will exclude them—or to copy these "cousin" commits anyway. The default is to exclude them from the copying process, giving:
A'-B'---------F'-G' <-- branch
/ /
...--o--*--o---o <-- main /
\ \ /
\ A--B---F--G / [abandoned]
\ /_________/
C--D--E
The rebase-cousins
option includes them in the copying process, and puts C'
, the copy of C
, after main
, giving:
C'-D'-E'
/ \
/ \
/ A'-B'-----F'-G' <-- branch
|/
...--o--*--o---o <-- main
\ \
\ A--B---F--G [abandoned]
\ /
C--D--E
Note that if there are branch names pointing to any of C
, D
, or E
, they won't be moved, regardless of which option you choose.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With