1

There is a question here which has an excellent answer, but a highly upvoted comment on the question says that for some projects the answer is not acceptable:

I quote the comment:

The surprising answer by @Olufemi seems to do what you want, except that as ChristianGosch notes in a comment, you end up with a "merge commit" on top of your branch, and "nothing to compare" will not appear. That seems unacceptable to many projects for which you want to make branches for them to pull. So is there really no way to do this most basic of contributor workflows in github without running arcane git commands on a personal computer? Or maybe I should just throw away my whole repo and re-fork every time I want to contribute?? – nealmcb Dec 7 '14 at 22:14

And the comment mentioned in the comment:

Another one: This works fine if you did that not before already, but afterwards there is the "merge commit" on top of your commit history. Thus "nothing to compare" will not appear. Instead one must use "Edit" button and manually interchange base and fork for this to work. – Christian Gosch Oct 23 '14 at 14:04

Other comments on that question indicates that a rebase in stead of a merge solves this issue.

My question is this "What exactly is the issue with having a merge commit and when would you want to avoid it?" Do these merge commits add up over time? Does it affect future "sync to base repository" actions?

And a second question: Since I just followed the steps in this answer and now do have this "merge commit" how can I fix it if it was an issue to me?

The Tahaan
  • 6,915
  • 4
  • 34
  • 54

1 Answers1

0

TL;DR

Merge commits can create histories like this:

A-->B-->C-->D------>N
 \           \     /
  X---------->M-->Y

Some people prefer linear histories over histories that results from merge commits:

A-->B-->C-->D-->X-->Y

In order to produce such linear histories, run git rebase <main repository branch> from the fork branch before running git merge <fork branch> in the main repository branch.

The problem

If you have a scenario like this:

A-->B-->C-->D    main repo
 \
  X              fork

and create a merge commit in order to keep the fork up to date, it will look like this:

A-->B-->C-->D    main repo
 \           \
  X---------->M  fork

When you then add another commit somewhere and merge it back, it will look like:

A-->B-->C-->D------>N  main repo
\            \     /
 X----------->M-->Y    fork

You would have multiple merge commits and all merge commits would be visible in the history.

Some repository maintainer prefer linear histories like:

A-->B-->C-->D-->X

over histories with merge commits like:

A-->B-->C-->D------>N  main repo
 \           \     /
  X---------->M-->Y    fork

Solution

If you want to prevent this, you could use rebase merges.

Let's start like this, again:

A-->B-->C-->D    main repo
 \
  X              fork

Rebasing would move X to the top (run git rebase <branch from main repo> in the fork):

A-->B-->C-->D     main repo
             \
              X'  fork

You can then directly fast-forward any commits to the main repo without merge commits.

A-->B-->C-->D-->X'

No advantage without disadvantages

If you rebase a branch, you cannot simply push to the branch but you need to force push.

If you do that, you will overwrite the branch with your history and other people working on that branch will be forced to checkout the branch again if they do not want to clone it, again.

For example, multiple people could work on that fork:

A-->B-->C-->D    main repo
 \
  X              fork, local copy of someone else

If you rebase it, it will look like this:

A-->B-->C-->D    main repo
|            \
|             X' fork
 \
  X              local copy of someone else

If that person pulls, it would result in another merge commit where a commit is merged with an identical commit:

A-->B-->C-->D       main repo
|            \
|             X'    fork
 \             \
  X-------------M   local copy of someone else

In order to prevent that, they need to pull with the --rebase option. The result will look like the fork afterwards:

A-->B-->C-->D    main repo
             \
              X' fork, local copy of someone else

This will even work if the person has worked on commits:

Before rebasing:

A-->B-->C-->D    main repo
|            \
|             X' fork
 \
  X-->Y          local copy of someone else

After rebasing (git pull --rebase):

A-->B-->C-->D       main repo
             \
              X'    fork
               \
                Y'  local copy of someone else
dan1st
  • 12,568
  • 8
  • 34
  • 67
  • I will need to spend some more time before I will fully grok it. In the mean time thank you for this, – The Tahaan Feb 18 '21 at 06:56
  • Basically, some maintainers prefer a linear history and merge commits (especially if something is merged and then merged back) would destruct this. In order to fix this, you can copy commits from the main repository and insert them before the new commits. Anyways, I have added a TL;DR. – dan1st Feb 18 '21 at 07:43