This is a copy of an article I published at
I'm sending a copy here because I'm interested to know what other ways
there might be of handling this situation.


We often need to patch the software that we run in order to fix bugs
quickly rather than wait for an official release, or to add functionality
that we need. In many cases we have to maintain a locally-developed patch
for a significant length of time, across multiple upstream releases,
either because it is not yet ready for incorporation into a stable
upstream version, or because it is too specific to our setup so will not
be suitable for passing upstream without significant extra work.

I have been experimenting with a git workflow in which I have a feature
branch per patch. (Usually there is only one patch for each change we
make.) To move them on to a new feature release, I tag the feature branch
heads (to preserve history), rebase them onto the new release version, and
octopus merge them to create a new deployment version. This is rather
unsatisfactory, because there is a lot of tedious per-branch work, and I
would prefer to have branches recording the development of our patches
rather than a series of tags.

Here is a git workflow suggested by Ian Jackson which I am trying out
instead. I don't yet have much experience with it; I am writing it down
now as a form of documentation.

There are three branches:

upstream, which is where public releases live
working, which is where development happens
deployment, which is what we run

Which branch corresponds to upstream may change over time, for instance
when we move from one stable version to the next one.

The working branch exists on the developer's workstation and is not
normally published. There might be multiple working branches for
work-in-progress. They get rebased a lot.

Starting from an upstream version, a working branch will have a number of
mature patches. The developer works on top of these in
commit-early-commit-often mode, without worrying about order of changes or
cleanliness. Every so often we use git rebase --interactive to tidy up the
patch set. Often we'll use the "squash" command to combine new commits
with the mature patches that they amend. Sometimes it will be rebased onto
a new upstream version.

When the working branch is ready, we use the commands below to update the
deployment branch. The aim is to make it look like updates from the
working branch are repeatedly merged into the deployment branch. This is
so that we can push updated versions of the patch set to a server without
having to use --force, and pulling updates into a checked out version is
just a fast-forward. However this isn't a normal merge since the tree at
the head of deployment always matches the most recent good version of
working. (This is similar to what stg publish does.) Diagramatically,

     | \
     |  `A---B-- 1.1-patched
     |    \       |
     |     \      |
     |      `C-- 1.1-revised
     |            |
    2.0           |
     | \          |
     |  `-C--D-- 2.0-patched
     |            |
    3.1           |
     | \          |
     |  `-C--E-- 3.1-patched
     |            |
  upstream        |

The horizontal-ish lines are different rebased versions of the patch set.
Letters represent patches and numbers represent version tags. The tags on
the deployment branch are for the install scripts so I probably won't need
one on every update.

Ideally we would be able to do this with the following commands:

    $ git checkout deployment
    $ git merge -s theirs working

However there is an "ours" merge strategy but not a "theirs" merge
strategy. Johannes Sixt described how to simulate git merge -s theirs in a
post to the git mailing list in 2010.
So the commands are:

    $ git checkout deployment
    $ git merge --no-commit -s ours working
    $ git read-tree -m -u working
    $ git commit -m "Update to $(git describe working)"

Mark Wooding suggested the following more plumbing-based version, which
unlike the above does not involve switching to the deployment branch.

    $ d=$(git rev-parse deployment)
    $ w=$(git rev-parse working)
    $ c=$(echo "Update to $(git describe working)" |
          git commit-tree -p $d -p $w working^{tree})
    $ git update-ref deployment $c $d
    $ unset c d w

f.anthony.n.finch  <>
Forties, Cromarty: East, veering southeast, 4 or 5, occasionally 6 at first.
Rough, becoming slight or moderate. Showers, rain at first. Moderate or good,
occasionally poor at first.
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to
More majordomo info at

Reply via email to