Branch specific gitignores for Bioconductor package documentation

3 minute read

For more background on this post, see this thread on the Bioc-devel mailing list. The short story is that I use Hadley Wickham pkgdown package to build a website for my packages and then publish it on GitHub.

The easiest is to create a ./docs package directory that contains the whole site and configure GitHub pages to use it directly to produce, for example, the MSnbase page.

The ./docs directory ends in the package’s source which, on one hand is nice as it simplifies tracking/committing of the site pages with the package itself, but, on the other hand, the site also ends up on the Bioconductor subversion server, where it doesn’t serve any purpose other than taking space (5.5M in the case above).

Ignoring site from package tarball

It is straightforward to exclude the site’s docs directory in the package tarball/zipfile by amending the .Rbuildignore file - adding docs will do the trick.

Excluding from svn

It is not straightforward, however, to ignore the docs directory on the Bioconductor hedgehog subversion server if you use git-svn to manage the GitHub and subversion repositories together.

Unfortunately, git doesn’t support branch-specific .gitignore files or directives. Using different .gitignore files for different branches requires a hack described here. Here’s how I have implemented it when documenting my Bioconductor packages with pkgdown.

Define files to ignore

Instead of have a single static .gitignore files, we are going to create as branch-specific files and one general file defining what to ignore. They all come in a new gitignores directory. I choose to name the general file all and the branch-specific ones using the branch name (devel below).

$ tree .gitignores
.gitignores
├── all
└── devel

Each file contains exactly what a .gitignore file would contain.

$ cat .gitignores/all 
Makefile
.gitignore
$ cat .gitignores/devel 
docs

Dynamic generation of .gitignore

When I’m in master, I want my .gitignore file to list files in .gitignores/all only. When I’m in devel, I want both files from .gitignores/all and .gitignores/devel to be listed in .gitignore. This can be achieved with a post-checkout hook, that will be triggered after each git checkout. Mine is currently pretty simple. I will always create a new .gitignore file from .gitignores/all and will append the content of a file in .gitignores/ that matches the branch name.

$ cat .git/hooks/post-checkout
#!/bin/bash
# Copy in .git/hooks/post-checkout and make it executable
branch=$(git rev-parse --abbrev-ref HEAD)
cat .gitignores/all > .gitignore
if [[ -f .gitignores/$branch ]]; then
    cat .gitignores/$branch >> .gitignore;
fi

In action

And …

$ git branch 
  devel
* master
  release-3.0
  release-3.1
  release-3.2
  release-3.3
$ cat .gitignore
Makefile
.gitignore
$ git checkout devel 
Switched to branch 'devel'
Your branch and 'bioc/master' have diverged,
and have 1754 and 12 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
$ cat .gitignore
Makefile
.gitignore
docs

I seems to work as expected.

I find this solution rather easy to implement. The major benefit is that once it is in place, I can forget about it and things should work irrespective of the docs directory.

Drawback

There is one drawback with this solution, however. When comparing the devel and master branches with git diff, the ignored files are still shown.

$ git branch
* devel
  master
  release-3.0
  release-3.1
  release-3.2
  release-3.3
$ git diff --name-only master | head
docs/articles/Bugs.md
docs/articles/Bugs.tex
docs/articles/Figures/MSnbase-io-in.png
docs/articles/Figures/MSnbase-io-in.tex
docs/articles/Figures/MSnbase-io-out.png
docs/articles/Figures/MSnbase-io-out.tex
docs/articles/Figures/itraqchem.pdf
docs/articles/Figures/msnset.png
docs/articles/Figures/plot2d-figure.png
docs/articles/Figures/plotDensity-figure.png

Other possibilities

Orphan branches

Robert M. Flight suggested to use the good old original orphaned gh-pages branch solution.

svn ignore property

If one doesn’t use git-svn and manages git and svn independently, then setting the svn ignore property with

% svn propset svn:ignore docs .

should work. It doesn’t when managing both together.

Edit

I suggest to add a header to .gitignores indicating that gitignore is generated automatically and any updates will be overwritten.

% cat .gitignores/all
# This is an automatically generated file. Ammend in .gitignores/ and
# read  http://lgatto.github.io/branch-specific-gitignore/ for details
Makefile
.gitignore

Edit 2

And to ignore the .gitignores directory completely, suffices to add it to the general excludes file. I prefer to keep it in git (but not svn, and ignore it when building the package bundle) to keep track from what I ignore.

$ cat .git/info/exclude
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
.gitignores