Skip to content

Instantly share code, notes, and snippets.

@moraisaugusto
Last active June 4, 2020 14:35
Show Gist options
  • Save moraisaugusto/1fa02c49b6d9833fcdf665505595ac2e to your computer and use it in GitHub Desktop.
Save moraisaugusto/1fa02c49b6d9833fcdf665505595ac2e to your computer and use it in GitHub Desktop.
git fast forward vs no fast forward

Difference between a git fast forward and no fast forward

Initial Repository

Create an initial repository following the instructions below.

initial_repo.sh

#!/usr/bin/env sh

git init

# first commit
echo "initial repo" > initial.txt && git add initial.txt && git commit -m "initial repo"

# new branch
git checkout -b new-feature
echo "file a" > a.txt && git add a.txt && git commit -m "commit a"
echo "file b" > b.txt && git add b.txt && git commit -m "commit b"
echo "file c" > c.txt && git add c.txt && git commit -m "commit c"

Executing the script above, you will have a git structure like this one:

$ git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --all

* f7f8e5d - (HEAD -> new-feature) commit c (3 seconds ago) <Augusto Morais>
* 52db9e3 - commit b (3 seconds ago) <Augusto Morais>
* c4244c9 - commit a (3 seconds ago) <Augusto Morais>
* 2b19e95 - (master) initial repo (3 seconds ago) <Augusto Morais>

Merge with fast forward

Fast Forward is the default option for git merge

So, merging new-feature into master you will be this:

$ git checkout master
$ git merge 
* f7f8e5d - (HEAD -> master, new-feature) commit c (3 minutes ago) <Augusto Morais>
* 52db9e3 - commit b (3 minutes ago) <Augusto Morais>
* c4244c9 - commit a (3 minutes ago) <Augusto Morais>
* 2b19e95 - initial repo (3 minutes ago) <Augusto Morais>

Merge with no fast forward

No Fast Forward is not enabled by default and you have to pass this option to git merge command

So, merging new-feature into master you will be this:

$ git checkout master
$ git merge --no-ff -m "added new feature" 
* f7f8e5d - (HEAD -> master, new-feature) commit c (3 minutes ago) <Augusto Morais>
* 52db9e3 - commit b (3 minutes ago) <Augusto Morais>
* c4244c9 - commit a (3 minutes ago) <Augusto Morais>
* 2b19e95 - initial repo (3 minutes ago) <Augusto Morais>

Difference between each merge strategies

fast forward

$ git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --all

* f7f8e5d - (HEAD -> master, new-feature) commit c (12 minutes ago) <Augusto Morais>
* 52db9e3 - commit b (12 minutes ago) <Augusto Morais>
* c4244c9 - commit a (12 minutes ago) <Augusto Morais>
* 2b19e95 - initial repo (12 minutes ago) <Augusto Morais>

no fast forward

$ git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --all

*   0acabeb - (HEAD -> master) new-feature (14 seconds ago) <Augusto Morais>
|\
| * 389934e - (new-feature) commit 3 (20 minutes ago) <Augusto Morais>
| * 3dacbaf - commit 2 (20 minutes ago) <Augusto Morais>
| * 4d403b2 - commit 1 (20 minutes ago) <Augusto Morais>
|/
* a00eb72 - initial repo (20 minutes ago) <Augusto Morais>

Comments

The biggest difference between each strategy is the way that you will organize your history. As you can see, --no-ff creates an extra commit with "new-feature". Thus, you can easily check what is going on in your history and remove a new feature, e.g.:

git rebase -i 0acabeb~

this command will automatically get all commits from the new-feature.

Of course, you can remove a feature using thefast-forward strategy but for that, you need to pick up each commit individually and this can be a bit annoying.

git rebase -i f7f8e5d~3

note: ~3 refers to the last 3 commits including the f7f8e5d

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