Do you use git? Then you probably know the basic commands like git pull, git merge and git rebase. These are pretty common, but also complex. Over the time, I have adopted few simple rules which help me to use them effectively.

Git pull considered harmful

You have probably noticed that sometimes your git pull generates automatic merge commits. They do not hold any useful information and if your repo is busy, your history can be literally flooded.

I like to keep my history linear and simple. That is why I recommend to set the default git pull configuration to fast-forward only (linear type of merge which does not create any commits).

With Git 2.0 and newer, you can just update your settings:

git config --global pull.ff only

Older versions do not have this option, but you can use an alias instead:

git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'

@{u}” is a shortcut which reffers upstream of the tracked branch.

Usage:

git up

Rebasing non-linear changes

When the fast-forward merge is not possible, the default git pull behavior would be a three-way merge. But in order to keep the history clean, rebase can be used.

You might have heard, that rebase is evil (git rebase hell), but as long as your rebased commits are only local, you should be safe.

Again, I recommend an alias:

git config --global alias.upr '!git remote update -p; git rebase -p @{u}'

Usage:

git upr

The git pull --rebase does a similar thing, but it currently doesn’t have an option to rebase merge commits, so you can end up with a slightly different history. Git rebase -p will try to replay merge commits and preserve your history.

Clean up your commits before publishing

Before you push your commits to the repository, it’s good to revise them.  You can run the git interactive rebase to squash your commits or modify commit messages.

An alias for the interactive rebase of unpushed commits:

git config --global alias.ri '!git rebase -i @{u}'

Usage:

git ri

The goal is to publish only clean and relevant commits, no experiments or fixing typos. Therefore I usually do the git rebase and push at the end of my programming sessions (typically at the end of the day), so I see all the commits in one place.

Keep in mind that interactive rebase does not preserve merge commits (combining interactive rebase and preserve merge is not recommended), so you might want to do it before you merge a new branch.

Three-way merge between branches

Three-way merge is a non-linear merge with conflict resolution. It should be always used when merging non-local branches:

  • Merge of feature branch to the master
  • When you are working on a feature in a branch and you would like to merge commits from master.

This type of merge generates the merge commit, which serves as a source of information about the merge (branches, commits, time and date, responsible user).

How to force a three-way merge:

git merge --no-ff the_other_branch

Replace the “the_other_branch” with a name of  the source branch for merge to your current branch.

Summary

  • Disable automatic three-way merge with git pull.
  • If you cannot pull with a fast-forward merge and your commits are only local, run the rebase with preserve merges enabled.
  • Use three-way merge for merging between branches or when updating you feature branch.
  • Before push, revise your commits and clean them with interactive rebase if needed.

Avoid

Never rebase any pushed or pulled changes (not branches, nor commits).

Want to know more?

Comments