Upgrading Moodle with Git
Background
I've been working on a new deployment of Moodle for Lancaster University for the past two years or so. Our project started out with Moodle 2.1, and we upgraded for our initial pilot to Moodle 2.2.Since then, we've upgraded from Moodle 2.2 to 2.3; and we're now planning the upgrade from 2.3 to 2.5.
We manage all of our upgrades with git, and our deployment using Debian packages.
I've been asked a couple of times to write about our upgrade methodology and reasoning so hopefully others will find this useful.
We use a variety of git features, but new features are added to git all the time which change our deployment methodology from time-to-time. At present we use:
- branches
- tags
- multiple remotes
- merges
- cherry-picks
- rebase
In addition to the git side of things, we also make use of Redmine for issue tracking.
Branches, Tags, and Remotes
We have quite a few of these, but they really do make our life easier. Git is a fantastic tool, and if used to it's full extent, having a lage number of branches actually makes your life much easier, and less complicated. Having multiple remotes helps to separate various concerns too so you can ensure that it's harder to inadvertantly publish your institution's IP.Branches
In summary, we have one branch per feature, hack, or change in core Moodle - no matter how small. These are named in a (hopefully) sensible naming scheme to help identify them from one another easily and quickly. The name describes the project/customer (usually LUVLE in our case), the version, the type of the change, and the frankenstyle name for that change. For some changes, we have an optional short name to describe the branch further. Our naming scheme works out as:
{customer}-{major-version}-{change type}-{frankenstyle}[-{shortname}]
Where we have several related features which must co-exist and cannot
be used without one another, we use a custom frankenstyle name of
set_{name}.
As an example, these are some fo the branches for our impending Moodle 2.5.0 upgrade:
LUVLE-2.5-feature-mod_ouwiki
LUVLE-2.5-feature-block_panopto
LUVLE-2.5-feature-local_luassignment
LUVLE-2.5-feature-set_bigbluebuttonbn
LUVLE-2.5-hack-mod_resource-singlefiles
By having each feature in it's own branch, we're able to develop, and test that branch entirely in isolation.
In the rare cases that we are working with a feature which needs a minimum release version which includes a minor increment (e.g. 2.3.1), we check out from that tag instead, but we try to avoid this to make things simpler.
In addition to all of the feature and hack branches, we also have a range of testing and deployment branches. Generally, we have a main test branch which contains the same branches as our deployment environment. This is updated frequently when we want to test an upgrade to a whole branch in combination with the rest of our installation, or to test an upgrade to Moodle. Meanwhile, we typically only have a single deployment branch - LUVLE-2.5-deployment. This is to avoid any confusion and potential for dropped branches.
Tags
Similarly Tags are great too - we tag for each of our releases. Tags offer a few really handy features. Obviously, they can just be used to jump between version of Moodle; but we can also use them to compare a particular file, or directory with a previous release to see how things have changed. For development, this can be invaluable.Again, we have a pretty defined naming policy for tags:
{ourname}-moodle-{customer-name}_v{moodle-version}-{local-release}
As an example we have some of the following:
lu-moodle-lu_v2.3.4-0
lu-moodle-lu_v2.3.4-7
lu-moodle-lu_v2.5.0-0
git diff lu-moodle-lu_v2.3.4-0 enrol/lusi/lib.php
Remotes
As I mentioned before, one great reason for multiple remotes is to give you a separation of concerns. There are times where you don't wish to push some of your branches to the public, other times where you're working on bug fixes you don't really need to push to an internal repository, and all manner of other reasons besides.I have the following remotes to make my life easier:
- origin - git.moodle.org/moodle.git - my main upstream;
- integration - git.moodle.org/integration.git - the moodle.org integration branch. Useful when fixing issues that crop up during integration;
- public - github.com/andrewnicols/moodle.git - the repository I push any bug fixes and new features for the community to; and
- cis - ciggit.lancs.ac.uk/moodle.git - our main internal repository.
The process
When a new release of Moodle comes out, we've typically taken a bit of laborious approach to things. Whilst there are a lot of steps, I feel that in the long run they've been less frustrating than trying to resolve any merge conflicts; and we've saved time trying scratching heads trying to work out where this change, or that whitespace conflict came from.Initial set-up
Once we've checked out a new branch for every single feature, and hack, we begin to bring them all together. That's nice and easy when you're just starting out - just git merge a lot:And hey-presto... we should have our Moodle 2.5 installation ready for testing and deployment. Once we're happy with our installation, we usually then create a deployment branch from that testing branch.
Grabbing a fix from upstream
We frequently come across issues which have already been fixed in upstream Moodle, or which we ourselves have helped to fix. Sometimes we also backport features from a newer branches onto our production branch if we really really want it.We do all of this with the fantastic git cherry-pick command which allows you to pick a commit, or a number of commits, and apply them to your current branch.
Updating our local branches
For updating one of our feature branches, we simply make our changes to that specific branch, and then merge them back in again:Upgrading Moodle - Minor releases
In reality, a minor update to Moodle is just the same as an update to one of our local branches. If anything, it's probably simpler:Upgrading Moodle - Major releases
This is where things get much more complicated, and where the number of steps and the complication rapidly increases. That said, in my opinion they also reduce the confusion later on.Externally provided code
We start by grabbing the latest version of the externally provided plugins and starting brand new branches for them. There's usually very little point in keeping the history for those branches as it doesn't contain any of the upstream commit messages.Local branches which need updating
For our local branches, we want to preserve this history of our changes. We also want to remove any confusion with merges to newer versions to keep the history as clear as possible.To do so, we use the wonderful
git rebase --onto
command.
With a normal rebase command, git takes every commit since your branch diverged from the new upstream, and attempts to replay each of them on top of the new head.
The --onto tells rebase where to take the commits from for the re-application. That's to say, that if you only have one commit since you branches from the tag, it grabs that commit, and immediately tries to replay on top of the target version. Ordinarily, it would attempt to reapply your commit on top of every other commit.
That's it. It's really simple, but it needs to be done for each and every branch that you have.
Finally, once all branches have been updated, we merge them into a new testing branch and begin our testing phase.
Tracking things
In order to make sure that we don't lose track of anything, or forget a branch during an upgrade, we make use of our issue tracking software Redmine.When we start to put a version together, for example Moodle 2.2, we create a new task for the next upgrade - in this case, 2.3.
As we include each of our feature branches, we create a new subtask under the 2.3 task.
When we came to upgrading to Moodle 2.3, we then go through each of those subtasks and make any relevant notes from the upgrade process. We also create a new task for the subsequent upgrade (e.g. Moodle 2.5).
If we are no longer including a branch because it is now redundant or we have decided to change the functionality offered, we also note this in the relevant issue.
This all helps to ensure that we don't forget an issue and that we keep a record of all changes.
Bpost Tracking Gone are the days when clients simply come and by in neighborhood stores. Today more clients are excited about purchasing in mass, shopping on the web, and paying for a conveyance administration to send their things directly in their front entryway.
ReplyDeleteBpost Tracking Number