Skip to content
Eric Nawrocki edited this page Dec 17, 2020 · 15 revisions

initial checkout

Infernal depends on HMMER and Easel, also at github. To clone an Infernal repository for the first time, and get it set up:

   $ git clone https://github.com/EddyRivasLab/infernal
   $ cd infernal
   $ git clone https://github.com/EddyRivasLab/hmmer
   $ (cd hmmer; git checkout tags/infernal-1.1.4)
   $ git clone https://github.com/EddyRivasLab/easel
   $ (cd easel; git checkout tags/infernal-1.1.4)
   $ autoconf

and to build:

   $ ./configure
   $ make
   $ make check      # optional: run tests

You're set up on the stable master branches for all three packages. To do any development, you need to work on the develop branch(es) for infernal, hmmer, and easel, generally by creating and merging feature branches. For information about our git workflow, read on.

git workflow

Infernal has switched to using a popular git workflow that's often just called "git flow". Go read the 2010 blog post by Vincent Driessen that describes it. We will use it with two differences:

  • How we manage having Infernal depending on HMMER and HMMER depending on Easel.

  • We don't mind having feature branches on origin.

In what follows, first we'll give concise-ish examples of the flow for normal development, making a release, and making a "hotfix". A summary of the principles and rationale follows the examples.

Normal development

Generally, for any changes you make to our code, you will make on a feature branch, off of develop. So first you create your branch:

   $ git checkout -b myfeature develop            

Now you work, for however long it takes. You can make commits on your myfeature branch locally, and/or you can push your branch up to the origin and commit there too, as you see fit.

When you're done, and you've tested your new feature, you merge it to develop (using --no-ff, which makes sure a clean new commit object gets created), and delete your feature branch:

   $ git checkout develop                     
   $ git merge --no-ff -m "Merges myfeature branch into develop" myfeature
   $ git branch -d myfeature
   $ git push origin --delete myfeature
   $ git push origin develop                  

Small features: single commits can be made to develop

Alternatively, if you're sure your change is going to be a single commit, you can work directly on the develop branch.

   $ git checkout develop                  
     # make your changes
   $ git commit
   $ git push origin develop               

Big features: keeping up to date with develop

If your work on a feature is taking a long time (days, weeks...), and if the develop trunk is accumulating changes you want, you might want to periodically merge them in:

   $ git checkout myfeature
   $ git merge --no-ff -m "Merges develop branch into myfeature" develop          

Making a release

To make a release, you're going to make a release branch of the code, and of any other repos it depends on. For example, for an Infernal release, you're going to make release branches in HMMER and Easel too. You assign appropriate version numbers to each, test and stabilize. When everything is ready, you merge to master and tag that commit with the version number; then you also merge back to develop, and delete the release branch.

For example, here's the git flow for an Infernal release, depending on HMMER and Easel. (This is just an outline to show the logic, see the 00README in the most recent release notebook for the complete list of what to do for a release, including testing.) Suppose Infernal is currently at 1.1.2, HMMER is currently at 3.2.1, and Easel is currently at 0.48. Suppose we decide this release will be Infernal 1.2, and it depends on some new features in HMMER so we need to make a new HMMER 3.2.2 release, but we can use the last stable Easel release as it is. Then first we go over to Easel and just make a tag:

   $ cd easel
   $ git checkout master
   $ git tag -a -m "Tags easel-0.48 for infernal-1.2 release" infernal-1.2
   $ git push origin infernal-1.2

then we go over to make a new release from HMMER3's develop branch:

   $ cd hmmer
   $ git checkout develop # only necessary if you're not already on develop
   $ git checkout -b release-3.2.2 develop
     # change version numbers to 3.2.2; also dates, copyrights
     #  configure.ac (*_DATE, *_COPYRIGHT, *_VERSION)
     #  LICENSE (Copyright dates)
   $ git commit -a -m "Version number bumped to 3.2.2"
     # do and commit any other work needed to test/stabilize H3 release

then go over and make a new release from Infernal's develop branch:

   $ cd infernal
   $ git checkout develop # only necessary if you're not already on develop
   $ git checkout -b release-1.2 develop
     # change version numbers to 1.2; also dates, copyrights:
     #  configure.ac (*_DATE, *_COPYRIGHT, *_VERSION)
     #  LICENSE (Copyright dates)
   $ git commit -a -m "Version number bumped to 1.2"
     # do and commit any other work needed to test/stabilize Infernal release.
     # See most recent release notebook 00README for instructions. 

Now proceed with the rest of the release process for Infernal (see 00README in most recent release e-notebook). We do this before merging the HMMER release branch updates we just made (version number etc.) back to master and develop, in case there's some change we need to make in the HMMER release branch based on what we find during the testing described in the release 00README.

When you're finished with the 00README steps, we then merge the release branches as follows:

   $ cd hmmer
   $ git checkout master
   $ git merge --no-ff -m "Merges release-3.2.2 branch into master" release-3.2.2
   $ git tag -a -m "Tags 3.2.2 release" hmmer-3.2.2
   $ git push origin hmmer-3.2.2
   $ git tag -a -m "Tags hmmer 3.2.2 for infernal-1.2 release" infernal-1.2    # This records that Infernal 1.2 release depends on HMMER 3.2.2
   $ git push origin infernal-1.2
   $ git push
     # Now merge release branch back to develop...
   $ git checkout develop
   $ git merge --no-ff -m "Merges release-3.2.2 branch into develop" release-3.2.2
   $ git push
   $ git branch -d release-3.2.2
   $ git push origin --delete release-3.2.2

and finally, we do the same pattern on Infernal itself:

   $ cd ..
   $ git checkout master
   $ git merge --no-ff -m "Merges release-1.2 branch into master" release-1.2 
   $ git tag -a -m "Tags infernal 1.2 release" infernal-1.2
   $ git push origin infernal-1.2
      # Now merge release branch back to develop...
   $ git checkout develop
   $ git merge --no-ff -m "Merges release-1.2 branch into develop" release-1.2 
   $ git push
   $ git branch -d release-1.2
   $ git push origin --delete release-1.2

Dependencies always have a tag for their own release (Easel 0.2.4), and may have additional tags for packages that depend on them (HMMER 3.2.2 bundles Easel 0.2.4? Then there's a hmmer-3.2.2 tag pointing to that Easel commit object).


Fixing bugs: "hotfix" branches

If you need to fix a critical bug and make a new release immediately, you create a hotfix release with an updated version number, and the hotfix release is named accordingly: for example, if we screwed up Infernal 1.2, hotfix-1.2.1 is the updated 1.2.1 release.

A hotfix branch comes off master, but otherwise is much like a release branch.

   $ cd infernal
   $ git checkout -b hotfix-1.2.1 master                 
     # bump version number to 1.2.1; also dates, copyrights
   $ git commit -a -m "Version number bumped to 1.2.1"

Now you fix the bug(s), in one or more commits. When you're done, the finishing procedure is just like a release:

    $ git checkout master              
    $ git merge --no-ff -m "Merges hotfix-1.2.1 branch into master" hotfix-1.2.1
    $ git tag -a infernal-1.2.1
    $ git checkout develop              
    $ git merge --no-ff -m "Merges hotfix-1.2.1 branch into develop" hotfix-1.2.1
    $ git push
    $ git branch -d hotfix-1.2.1
    $ git push origin --delete release-1.2


Summary of main principles

There are two long-lived Infernal branches: origin/master, and origin/develop. All other branches have limited lifetimes.

master is stable. Every commit object on master is a tagged release, and vice versa.

develop is for ongoing development destined to be in the next release. develop should be in a close-to-release state. Another package (e.g. Infernal) may need to create a release of a downstream dependency (e.g. HMMER or Easel) at short notice. Therefore, commit objects on develop are either small features in a single commit, or a merge of a finished feature branch.

We make a feature branch off develop for any nontrivial new work -- anything that you aren't sure will be a single commit on develop. A feature branch:

  • comes from develop
  • is named anything informative (except master, develop, hotfix-* or release-*)
  • is merged back to develop (and deleted) when you're done
  • is deleted once merged

We make a release branch off develop when we're making a release. A release branch:

  • comes from develop
  • is named release-<version>, such as release-1.2
  • first commit on the hotfix branch consists of bumping version/date/copyright
  • is merged to master when you're done, and that new commit gets tagged as a release
  • is then merged back to develop too
  • is deleted once merged

We make a hotfix branch off master for a critical immediate fix to the current release. A hotfix branch:

  • comes from master
  • is named hotfix-<version>, such as hotfix-1.2.1
  • first commit on the hotfix branch consists of bumping version/date/copyright
  • is merged back to master when you're done, and that new commit object gets tagged as a release.
  • is then merged back to develop too
  • is deleted once merged