Can I Do a Fast-forward Merge in Git?

How to Find Out if You Can Do a Fast-forward merge in Git *without actually merging*

The title of this article should be "How to Find Out if I Can Do a Fast-forward merge in Git *without merging*, but that's really too long for a title.

I use Git constantly for all my projects. When I want to work on a new feature or a bug fix, I create a new branch and do the work there. I try to make all merges fast-forward merges because I hate dealing with merge conflicts. Sometimes, I'm not ready to do a merge, but want to check to see if a fast-forward merge is possible. In this article, we'll look at a quick, easy-to-remember, safe way of doing that.

MODX logo

My Git Workflow

You may or may not do things this way, but here's my method. I always have two permanent branches, master and dev. The master branch never changes unless I release a version. All new features and bug fixes ultimately end up in the dev branch (more on this in a bit). Whenever the dev branch is at a relatively stable point, I push it to GitHub.

When the dev branch is ready for release as a new version, I commit the config file with the new version number and the changelog on the dev branch with a commit message like this: Version to 1.2.1-pl -- released. Then, I merge the dev branch into the master branch, and push both branches to GitHub.

I generally do very little actual work in the dev branch, other than the update to the version and changelog. When I want to work on a new feature or a bug fix, I create a new branch like this:

git checkout -b bugfix

I work on the bug fix (or fixes) in the bugfix branch. When I'm finished, I do this:

git checkout dev
git merge --ff-only bugfix
git branch -d bugfix

That merges the fixes into the dev branch, and deletes the bugfix branch.

How Merge Conflicts Occur

Let's say I'm working on the UpgradeMODX extra. I create the bugfix branch, and do some work on a file called upgrademodx.class.php, fixing some, but not all of the bugs. I want to merge the ones I've fixed into the dev branch, so I do the first two steps above, then I forget to switch back to the bugfix branch. I take a break, and when I come back, I think I'm on the bugfix branch, but I'm not. I'm on the dev branch. I fix another bug in the same file. Then, I take another break, come back, and notice I'm on the dev branch. I switch to the bugfix branch and fix another bug in the same file.

At this point, the bugfix branch can't be merged without conflicts because there are different changes to the same file in both branches. Since I often do a more work than I should before merging and I hate dealing with merge conflicts, sometimes I don't want to do a merge, I just want to make sure that I haven't screwed up and that a clean, --ff-only merge will work. If it won't, the sooner I find out, the easier it will be to fix whatever is wrong.

See if a Fast-forward Merge is Possible

Unfortunately, git merge has no dry-run option. There are several suggested methods for finding out if a fast-forward merge is possible, but there are two problems with them. First, they're fairly complicated, which makes them difficult to trust. Second, I can never remember them.

Here's a method that always works and is much easier to remember. If you want to see if the bugfix branch can be merged into the dev branch with a --ff-only merge, do this:

git checkout dev
git checkout -b temp
git merge --ff-only bugfix
The temp branch created in the second line above is an exact copy of the dev branch. If it works there, the fast-forward merge is possible in the dev branch with no conflicts. Either way, you'll want to delete the temp branch:
git branch -d temp

For the Curious

One "official" method (the one I can never remember) looks like this:

git config --global alias.mergetest '!f(){ git merge --no-commit --no-ff "$1"; git merge --abort; echo "Merge aborted"; };f '
git mergetest branchname

Since I don't really understand what this is doing, I don't trust it not to make changes in my working directory.

Here's another one that is often recommended:

git merge-base --is-ancestor commit1 commit2

Unlike my method, this one requires that you use the SHA1 of the HEAD commit on each branch. It also, in theory, returns 0 or 1 and I can never remember which one means a fast-forward merge is possible. Worse yet, I've never been able to make it return anything and I'm not confident that I'll remember in which order to put the two commits.

Coming Up

In the next article, we'll look at some tips on comparing things in Git.

Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)

Comments (0)

Please login to comment.