Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the behavior of the "cousins" options in git rebase --rebase-merges?

Tags:

git

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?

like image 923
void.pointer Avatar asked Jun 10 '19 15:06

void.pointer


People also ask

What is git rebase vs merge?

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 rebase in git?

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.

Why you should rebase instead of merge?

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 .

What is git rebase continue?

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.


1 Answers

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 Hgit 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.

like image 102
torek Avatar answered Oct 05 '22 10:10

torek