Monthly Archives: October 2010

Using git fast-forward merging to keep branches in sync

Just to be clear, my last post was not prompted by any particular event or person.  The transition to git (from CVS) is new to pretty much everyone as evidenced by the numerous git related threads on fedora-devel.  I thought I’d contribute to the discussion by giving a simple outline of what to do and what not to do.  I’ll expand on my previous post here by walking through an example.  But first lets go through a bit of git theory.

Git supports two types of merges between branches: fast-forward merge and true merge.  One of the downsides of distributed revision control systems is that the relationships between branches can become quite complicated.  Fast-forward merges were created to avoid this difficult relationship where possible.  When doing a git merge, if only one of the two branches in the merge has changed, a fast-forward merge will occur.  If both sides have changes, than a true merge will occur.  Lets look at what this looks like in gitg:

First, we have a new package with two branches: master and f14 (for rawhide and Fedora 14 respectively).

> fedpkg clone foo
> cd foo
> gitg

Next, we add a line in the master branch and commit it:

> fedpkg switch-branch master
> echo “added a line” > x
> git add x
> fedpkg commit -m “added a line” # You may also push your changes at this point with -p
> gitg

Let’s make another change in master:

> echo “added another line” >> x
> fedpkg commit -a -m “added another line” # Note that -a replaces the git add step above (see git docs for the implications of this)
> gitg

Now, we want our changes made in master to show up in the f14 branch. We simply do:

> fedpkg switch-branch f14
> git merge master # Note that NO commit was necessary because there were no conflicts
> gitg

So far so good!  Our changes were merged and our history looks clean.  Lets back up, however, and do it the wrong way.  Rather than doing the merge, we will just manually add our changes to the f14 branch.  So instead of the previous step we do:

> fedpkg switch-branch f14
> echo “added another line” >> x
> fedpkg commit -a -m “added another line”
> gitg

You should notice that we have now two disparate commits, one in each branch.  We have now just broken the ability to do a fast-forward merge.  You should also notice that master has a change that is not in f14 (‘added another line’).  Let’s merge this change into f14 to see what happens:

> git merge master
Auto-merging x
CONFLICT (content): Merge conflict in x
Automatic merge failed; fix conflicts and then commit the result.

Yikes!  What before was a simple merge is now a conflict!  Ok, so lets resolve the conflict:

> vi x # Edit to resolve the conflict
> git add x # Mark the conflict as resolved
> fedpkg commit -m “merge from master”
> gitg

So now, with a bit more effort (that could have easily been avoided had we just used a fast-forward merge) we have the changes from master merge into f14 by using a true merge.  All set, right!? Not by a long shot.  To show what I mean by this, lets add a new commit to master:

> fedpkg switch-branch master
> echo “added a third line” >> x
> fedpkg commit -a -m “added a third line”
> gitg

Notice that master and f14 again have disparate commits.  This is because the true merge that occurred in the previous step involved a commit. So even though we have merged changes from master into f14, we have permanently broken the ability do do fast forward merges.  Let me prove my point:

> fedpkg switch-branch f14
> git merge master
> gitg

Again, because of the disparate commits in f14 and master, the git merge performed a true merge, resulting in a new commit on f14.  All is not lost however.  To repair this situation and bring back the ability to do a fast-forward merge we need to notice only one thing: master does not yet have a disparate commit.  So this time, lets do a merge from f14 into master rather than vice versa:

> fedpkg switch-branch master
> git merge f14
> gitg

Yay! f14 and master are in sync again!  Let’s add a change to master and see if we can get the fast-forward into f14 again:

> echo “added a forth line” >> x
> fedpkg commit -a -m “added a forth line”
> fedpkg switch-branch f14
> git merge master
> gitg

The merge was performed as a fast-forward merge and our faith in humanity has been restored!

Now, this example has been a fairly simple one, however, with real-world uses this gets complicated fast.  This is all the more reason to make sure that you don’t break the ability to do fast-forward merges.  Let me show you a real world example (names removed to protect the innocent; click to enlarge):

  1. Notice that the packager imported as disparate commits.  This meant that merging was broken from the get-go.
  2. The result of #1 is that every time a change had to be made to a package it had to be merged by hand.  Further, there is no correlation between the commits, even though the contents of those commits were the same.
  3. The problem is resolved by merging every branch together.  Keep in mind that this was a time-consuming process since nearly every merge would have had a conflict which had to be manually resolved.
  4. The end result is that all branches are at the same HEAD and now fast-forwarding merging will work as normal.

In short, gitg (or other visualization tools) are your friend. If you have a graph in gitg that looks complicated, its probably because you’ve broken fast-forward merging and you can simplify your life by fixing it and working to make sure that disparate commits don’t happen again. The best development practice is to commit *all* changes into master, test them in rawhide and then merge them via fast-forward to the other branches.

Dear provenpackagers…

When making modifications to a package that you are not familiar with, please take a look at the structure of the git archive using a tool like gitg.  If you notice that the branches are kept in sync for a number of releases (ie rawhide, f14, f13, f12) using fast-forward merges, please don’t then proceed to commit to only one of the branches.  This is particularly true if f## branches are mirroring rawhide.  In this case, please commit to rawhide first and do a build there and test. Then use a git fast-forward merge to keep the rest of the branches in sync.  The wrong thing to do is to commit to one of the non-rawhide branches only.  This means rawhide does not have your fixes.  Even worse is to commit to each of the branches separately, as this makes git’s history incredibly hard to read and explicitly breaks fast-forward merging.  The exception to this rule of course is if a fix only applies to one branch.  In this case, you should look to see if the spec file already has %ifs for the dist tag.  If it does, you should copy this style instead of committing to a separate branch.  If all of this is still not possible or is not the best course of action, at least comment why you chose to make this change so that the maintainers can understand why a particular action was taken.

In short, git is a different tool than CVS and provides some remarkable features if you use it properly.  Please take a few minutes to understand exactly how git fast-forward merges work and why they are desirable when keeping branches in sync.  Thanks!

libgpod 0.8.0 in F13

I’ve just tagged libgpod 0.8.0 for F13 updates-testing.  This is the first step to an updated Banshee (1.8.0) in F13 as well as better iPhone/iPad support in the existing Rhythmbox.  I’d really like to get some testing on this, so please, if you are using updates-testing and have any Apple-brand device, please check to see that your device will successfully sync with Rhythmbox with the new libgpod.

Banshee 1.8.0 now in F14 updates-testing

Banshee 1.8.0 entered F14 updates-testing sometime yesterday.  This includes:

  • iPhone/iPad support
  • Amazon MP3 Store (money from the affiliate program goes to the GNOME Foundation!)
  • Miro Podcast Directory
  • Much, much, more…

In short, please test it and provide your feedback here.  There is a known issue of Apple devices not turning off the sync screen when the sync is complete.  I have a patch for this already and will put it into the next build.

iPhone and Banshee – part 2

In order to get iPhone support, Banshee must be built against several new packages which switch Banshee from using its HAL backend to the new gudev backend.  The latest libgpod has already been merged and you can test it in F14 updates-testing (leave feedback here: https://admin.fedoraproject.org/updates/libgpod-0.7.95-1.fc14).  I’ve also filed new package review requests for each of these four new dependencies:

  1. gudev-sharp
  2. gkeyfile-sharp
  3. gio-sharp
  4. gtk-sharp-beans

Once these packages are approved and added to Fedora, all that’s left is to rebuild Banshee against them.  So, if you have any interest in getting iPhone support in Banshee in Fedora, please review my packages. :)

Of course, if you are just interested in testing Banshee with your iPhone (or otherwise see the new hotness that is Banshee 1.7.6), you can always pull it from my repo: http://repos.fedorapeople.org/repos/npmccallum/banshee/fedora-14

Happy listening!