There are a number of different ways to grab changes from a remote Git repository and bring them into your local repository. The most common way is to simply do a pull. By default this will do a ‘fetch-and-merge‘, but you can configure this to do a ‘fetch-and-rebase‘ instead. You can also do an explicit ‘fetch and merge’ or ‘fetch and rebase’. There are a number of good articles on the difference between merge and reabase. Alex Blewitt covered this on his Git Tip-of-the-week series.
I prefer the fetch-and-rebase approach, and in this tutorial I’m going to show you how to use a Rebase Workflow for Git using EGit, the Eclipse Git Plugin. There are lots of good reasons for using a rebase workflow when your ready to push your changes to a remote repository. Rebase keeps a linear history. Instead of seeing merge nodes each time someone had to integrate their changes, you get on ordered list of commits that constitute the repository. It also helps with using tools like git bisect.
Assume we have this very simple Hello, World program that we’ve cloned.
Add assume we’ve added (and committed) a goodbye message[Note: For those of you coming from a CVS background, with Git you do the commit first and then worry about integrating it. Don’t try to pull changes before you commit]. Now we are ready to push this to a remote repository (say GitHub, or Eclipse.org).
We will receive a “rejected – non-fast-forward” error. This is because we have two different streams of changes that we are both trying to modify to the master branch in the same remote repository. Since someone else already pushed their changes, we need to manually integrate ours. We start by performing a fetch operation. Eclipse (EGit actually) will decorate our project to show that the two branches have diverged.
These decorations show that we have 1 outgoing change (the up arrow), and the remote repository has 2 incoming changes (the down arrow). We can also see this graphically in our history view.
Here you can see that the origin/master has two changes (commits: dd8f05a and ceb6ae8) and we have one (commit: 824a3f0). You can review these changes by reading the commit messages or even looking at the changesets for each one. Now, if we want to put our commit on top of the remote ones, we can choose the first commit in the view (commit: dd8f05a), right-click and choose rebase:
If there are conflicts you’ll need to work through the standard interactive rebase tool. Once everything is in place you’ll have a nice linear history. You will also notice that the two commits (ceb6ae8 and dd8f05a) are still there, however, your commit has changed. This is because you re-wrote history to put your commit (994ecf7) on top. This is ok as long as you have never shared your commit with anyone else before. Now you can proceed to push your changes to the remote repository.
By doing a fetch-and-rebase you won’t end up with merge tags each time a different committer pushes changes.