Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between `git merge` and `git merge --no-ff`?

Using gitk log, I could not spot a difference between the effect of git merge and git merge --no-ff. How can I observe the difference (with a git command or some tool)?

like image 305
user1162226 Avatar asked Jan 30 '12 18:01

user1162226


People also ask

What is no FF in git merge?

The Git merge --no-ff command merges the specified branch into the command in the current branch and ensures performing a merge commit even when it is a fast-forward merge. It helps in record-keeping of all performed merge commands in the concerning git repo.

What is the difference between git merge?

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 a non Fast forward merge?

A non-fast-forward merge is a merge where the main branch had intervening changes between the branch point and the merge back to the main branch. In this case, a user can simulate a fast-forward by rebasing rather than merging. Rebasing works by abandoning some commits and creating new ones.

What are the different types of git merge?

Git merging combines sequences of commits into one unified history of commits. There are two main ways Git will merge: Fast Forward and Three way. Git can automatically merge commits unless there are changes that conflict in both commit sequences.


2 Answers

Graphic answer to this question

Here is a site with a clear explanation and graphical illustration of using git merge --no-ff:

difference between git merge --no-ff and git merge

Until I saw this, I was completely lost with git. Using --no-ff allows someone reviewing history to clearly see the branch you checked out to work on. (that link points to github's "network" visualization tool) And here is another great reference with illustrations. This reference complements the first one nicely with more of a focus on those less acquainted with git.


Basic info for newbs like me

If you are like me, and not a Git-guru, my answer here describes handling the deletion of files from git's tracking without deleting them from the local filesystem, which seems poorly documented but often occurrence. Another newb situation is getting current code, which still manages to elude me.


Example Workflow

I updated a package to my website and had to go back to my notes to see my workflow; I thought it useful to add an example to this answer.

My workflow of git commands:

git checkout -b contact-form (do your work on "contact-form") git status git commit -am  "updated form in contact module" git checkout master git merge --no-ff contact-form git branch -d contact-form git push origin master 

Below: actual usage, including explanations.
Note: the output below is snipped; git is quite verbose.

$ git status # On branch master # Changed but not updated: #   (use "git add/rm <file>..." to update what will be committed) #   (use "git checkout -- <file>..." to discard changes in working directory) # #       modified:   ecc/Desktop.php #       modified:   ecc/Mobile.php #       deleted:    ecc/ecc-config.php #       modified:   ecc/readme.txt #       modified:   ecc/test.php #       deleted:    passthru-adapter.igs #       deleted:    shop/mickey/index.php # # Untracked files: #   (use "git add <file>..." to include in what will be committed) # #       ecc/upgrade.php #       ecc/webgility-config.php #       ecc/webgility-config.php.bak #       ecc/webgility-magento.php 

Notice 3 things from above:
1) In the output you can see the changes from the ECC package's upgrade, including the addition of new files.
2) Also notice there are two files (not in the /ecc folder) I deleted independent of this change. Instead of confusing those file deletions with ecc, I'll make a different cleanup branch later to reflect those files' deletion.
3) I didn't follow my workflow! I forgot about git while I was trying to get ecc working again.

Below: rather than do the all-inclusive git commit -am "updated ecc package" I normally would, I only wanted to add the files in the /ecc folder. Those deleted files weren't specifically part of my git add, but because they already were tracked in git, I need to remove them from this branch's commit:

$ git checkout -b ecc $ git add ecc/* $ git reset HEAD passthru-adapter.igs $ git reset HEAD shop/mickey/index.php Unstaged changes after reset: M       passthru-adapter.igs M       shop/mickey/index.php  $ git commit -m "Webgility ecc desktop connector files; integrates with Quickbooks"  $ git checkout master D       passthru-adapter.igs D       shop/mickey/index.php Switched to branch 'master' $ git merge --no-ff ecc $ git branch -d ecc Deleted branch ecc (was 98269a2). $ git push origin master Counting objects: 22, done. Delta compression using up to 4 threads. Compressing objects: 100% (14/14), done. Writing objects: 100% (14/14), 59.00 KiB, done. Total 14 (delta 10), reused 0 (delta 0) To [email protected]:me/mywebsite.git    8a0d9ec..333eff5  master -> master 



Script for automating the above

Having used this process 10+ times in a day, I have taken to writing batch scripts to execute the commands, so I made an almost-proper git_update.sh <branch> <"commit message"> script for doing the above steps. Here is the Gist source for that script.

Instead of git commit -am I am selecting files from the "modified" list produced via git status and then pasting those in this script. This came about because I made dozens of edits but wanted varied branch names to help group the changes.

like image 33
Krista K Avatar answered Sep 17 '22 13:09

Krista K


The --no-ff flag prevents git merge from executing a "fast-forward" if it detects that your current HEAD is an ancestor of the commit you're trying to merge. A fast-forward is when, instead of constructing a merge commit, git just moves your branch pointer to point at the incoming commit. This commonly occurs when doing a git pull without any local changes.

However, occasionally you want to prevent this behavior from happening, typically because you want to maintain a specific branch topology (e.g. you're merging in a topic branch and you want to ensure it looks that way when reading history). In order to do that, you can pass the --no-ff flag and git merge will always construct a merge instead of fast-forwarding.

Similarly, if you want to execute a git pull or use git merge in order to explicitly fast-forward, and you want to bail out if it can't fast-forward, then you can use the --ff-only flag. This way you can regularly do something like git pull --ff-only without thinking, and then if it errors out you can go back and decide if you want to merge or rebase.

like image 125
Lily Ballard Avatar answered Sep 21 '22 13:09

Lily Ballard