Skip to content

Instantly share code, notes, and snippets.

@kuinak
Created March 11, 2020 18:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kuinak/1dc3e763b55103bbea933dd9f0ccccde to your computer and use it in GitHub Desktop.
Save kuinak/1dc3e763b55103bbea933dd9f0ccccde to your computer and use it in GitHub Desktop.

Why doesn't GitHub support the fast-forward merge strategy?

The fast-forward merge strategy is the default strategy employed by git when the base branch is the direct ancestor of the head branch.

For example:

~ % mkdir foo
~ % cd foo
~/foo % git init .
Initialized empty Git repository in /Users/ejp/foo/.git/
~/foo % touch README.md
~/foo % git add README.md
~/foo % git commit -m "add read me"
[master (root-commit) 5bc5067] add read me
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md
~/foo % git checkout -b topic
Switched to a new branch 'topic'
~/foo % touch topic
~/foo % git add topic
~/foo % git commit -m topic
[topic 84b57ff] topic
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 topic
~/foo % git log
commit 84b57ffd638e458198388dc2bc20ff807d12cbab (HEAD -> topic)
Date:   Wed Mar 11 10:16:45 2020 -0700

    topic

commit 5bc5067a81b3234bdb4b40495bc5f03ac7e87110 (master)
Date:   Wed Mar 11 10:16:19 2020 -0700

    add read me
~/foo % git checkout master
Switched to branch 'master'
~/foo % git log
commit 5bc5067a81b3234bdb4b40495bc5f03ac7e87110 (HEAD -> master)
Date:   Wed Mar 11 10:16:19 2020 -0700

    add read me
~/foo % git merge topic
Updating 5bc5067..84b57ff
Fast-forward
 topic | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 topic
~/foo % git log
commit 84b57ffd638e458198388dc2bc20ff807d12cbab (HEAD -> master, topic)
Date:   Wed Mar 11 10:16:45 2020 -0700

    topic

commit 5bc5067a81b3234bdb4b40495bc5f03ac7e87110
Date:   Wed Mar 11 10:16:19 2020 -0700

    add read me

After merging the topic branch to master, the commit SHA from the topic branch (84b57ff) remains the same.

However, if we were to push the branch to GitHub, create a pull request, and merge, we end up with different SHAs in our commit history:

~/foo % git reset HEAD^1
~/foo % rm topic
~/foo % git remote add origin git@github.com:kuinak/foo.git
~/foo % git push -u origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 890 bytes | 445.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:kuinak/foo.git
 * [new branch]
Branch 'master' set up to track remote branch 'master' from 'origin'.
~/foo % git checkout topic
Switched to branch 'topic'
~/foo % git push --set-upstream origin topic
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 919 bytes | 919.00 KiB/s, done.
Total 2 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'topic' on GitHub by visiting:
remote:
remote:
To github.com:kuinak/foo.git
 * [new branch
Branch 'topic' set up to track remote branch 'topic' from 'origin'.
~/foo % git log
commit 84b57ffd638e458198388dc2bc20ff807d12cbab (HEAD -> topic, origin/topic)
Date:   Wed Mar 11 10:16:45 2020 -0700

    topic

commit 5bc5067a81b3234bdb4b40495bc5f03ac7e87110
Date:   Wed Mar 11 10:16:19 2020 -0700

    add read me

At this point, I merged the PR using the "Rebase and merge" strategy: git-merge

~/foo % git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)
~/foo % git pull
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 0), reused 1 (delta 0), pack-reused 0
Unpacking objects: 100% (2/2), done.
From github.com:kuinak/foo
   5bc5067..51e7d9d  master     -> origin/master
Updating 5bc5067..51e7d9d
Fast-forward
 topic | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 topic
~/foo % git log
commit 51e7d9ddab01514848bad92edfa9bea2ac15a6fa (HEAD -> master, origin/master)
Date:   Wed Mar 11 10:16:45 2020 -0700

    topic

commit 5bc5067a81b3234bdb4b40495bc5f03ac7e87110
Date:   Wed Mar 11 10:16:19 2020 -0700

    add read me

After the merge on GitHub, the SHA in master is now 51e7d9d, whereas the same commit in the topic branch remains 84b57ff

The GitHub documentation makes note of this behavior:

The rebase and merge behavior on GitHub deviates slightly from git rebase. Rebase and merge on GitHub will always update the committer information and create new commit SHAs, whereas git rebase outside of GitHub does not change the committer information when the rebase happens on top of an ancestor commit.

I don't understand why they don't provide fast-forward as a merge strategy option.

Both GitLab and Bitbucket support the fast-forward merge strategy, and I confirmed that the commit SHAs do not change after merging.

GitLab:

GitLab

Bitbucket:

Bitbucket

@retr0h
Copy link

retr0h commented Mar 11, 2020

Squash and merge? TBH all the repos I create have sqush and merge as the default option, particularly useful when needing to cherry-pick.

@kuinak
Copy link
Author

kuinak commented Mar 11, 2020

@retroh Squash and merge removes the prior commit history and creates a squash commit.

If my base branch is A -> B -> C, and my head branch is A -> B -> C -> D -> E, I would like my base to look like A -> B -> C -> D -> E after merging, not A -> B -> C -> F (as Squash and merge would do) nor A -> B -> C -> F -> G (as Rebase and merge would do).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment