Write LilyPond Code for Version Control

LilyPond – as a plain text input language – is accessible for version control. That’s a Good Thing, although it’s not as widely known as would be desirable. In this post I will make a few suggestions on how to prepare one’s LilyPond code in order to make most out of versioning. I’d appreciate any additions or discussion in the comments.

One Line is One Entity

The basic processing unit for version control is one line of source code. It performs its magic by comparing source code files line by line. Therefore the first practice to follow is to place only one coherent entity on each line of source code. It is also a general recommendation to write the code for one measure on one line, but when you want to benefit from version control this is actually a requirement. Consider the following code fragment:

5music = \relative c { \key g \major \clef bass
6  c4 d e d | f2 a4. g16 f | e2. c4 | c'1 |
7  b4.( a8 g4) b-> | c2 c, | a' g4-- fis-- | g1\fermata }
8

Of course that isn’t very good coding style – it’s somewhat crowded and confusing. But maybe the code was written for brevity and less scrolling.
But what if we decided to make some little modifications and add them as a commit to our versioned repository? The displayed changes between the two versions are quite hard to interpret. Who can ‘spot the differences’ the fastest? 😉

-music = \relative c { \key g \major \clef bass
-  c4 d e d | f2 a4. g16 f | e2. c4 | c'1 |
+music = \relative c { \key c \major \clef bass
+  c4 d e d | f2 a4. g16 f | e2. c4-| | c'1 |
   b4.( a8 g4) b-> | c2 c, | a' g4-- fis-- | g1\fermata }

Now let’s rewrite the original example putting each entity in a single line:

05music = \relative c { 
06  \key g \major 
07  \clef bass
08  c4 d e d | 
09  f2 a4. g16 f | 
10  e2. c4 | c'1 |
11  b4.( a8 g4) b-> | 
12  c2 c, | 
13  a' g4-- fis-- | 
14  g1\fermata 
15}
16

If we now apply the same modifications as before and commit them the diff will be much more expressive:

 music = \relative c { 
-  \key g \major 
+  \key c \major 
   \clef bass
   c4 d e d | 
   f2 a4. g16 f | 
-  e2. c4 | c'1 |
+  e2. c4-| | c'1 |
   b4.( a8 g4) b-> |

We have efficiently narrowed down the modifications to one command (the \key) and one measure each, simply by making the code more readable in the first place. But there is one more aspect to that example that leads us to the next topic:

Provide Barnumbers – Everywhere

Although we can immediately spot the modified measure in the previous diff example we don’t know right away which measure is affected. Well, it is always a good practice to offer \barNumberChecks or barnumber comments as often as possible, but with version control this becomes even more important. Consider the following commit diff which you might get as the result of a peer’s revision:

   c2 c, | % 114
-  a' g4-- fis-- | %115
+  a' g4-.-- fis-.-- | %115
   g1\fermata %116

At a glance you can comprehend what your partner did and where to spot it in the score.

So under all circumstances try to provide a measure number within the typical range of a diff display, say at least every five lines. But it is definitely best to have a measure number in each and every line.

Make Changes as Explicit as Possible

While I would defend the previous suggestions in any discussion, the third and last topic of this post is more a matter of personal preference. I find it useful anyway.

Whenever I apply a change that uses a considerable number of characters and/or qualifies as an entity in its own right I try to put that modification in its own line of source code. Since it is a good practice to start each measure on a new line, I use indentation to make my intentions clear. In the following example I’ll insert a \shape command, indent the tweak and the rest of the measure, and then start the next measure on a new line:

05music = \relative c { 
06  \key c \major 
07  \clef bass
08  c4 d e( d | % 110
09  f2 a4.) g16 f | % 111
10  e1\fermata %112
11}

% is modified to

05music = \relative c { 
06  \key c \major 
07  \clef bass
08  c4 d 
09       \shape Slur #'((0 . 0)(1 . 0)(0 . -1)(0 . 0))
10       e( d | % 110
11  f2 a4.) g16 f | % 111

For my eyes the modified source code is equally intuitive as the result of the modification viewed through a diff:

 music = \relative c { 
   \key c \major 
   \clef bass
-  c4 d e( d | % 110
+  c4 d 
+       \shape Slur #'((0 . 0)(1 . 0)(0 . -1)(0 . 0))
+       e( d | % 110
   f2 a4.) g16 f | % 111
   e1\fermata %112
 }

These are three simple ideas on how to make LilyPond input files behave better with version control. Of course they aren’t cut in stone, nor is this a comprehensive list. But generally it will pay off to have version control’s behaviour in mind when laying out LilyPond source files.

15 thoughts on “Write LilyPond Code for Version Control

  1. Reedmace Star

    For several reasons I dislike the idea of adding measure number comments to every line.

    Firstly, copy-and-paste becomes cumbersome, because measure number comments of pasted lines need to be adapted manually.

    Secondly, any change to your score that affects measure counting beomes a nightmare. Not a problem as long as you only faithfully copy static sources, but you might be engraving an arrangement or a composition that you need to refine over time. Add another two measures to the introduction? Notate that passage in the middle with a 12/8 time signature instead of 6/8? Join two movements with previously independent measure counting?

    A trivial, one-measure change might require adapting lots and lots of line number comments all over the project, and even if you manage to sort of automate this using clever editor features, the diff for that commit will definitely not look pretty.

    Reply
    1. Urs Liska

      OK, I admit that I’m exclusively thinking in terms of editing static sources. And I think your concerns are valid with other kinds of scores that are still evolving compositions.
      But on the other hand I would say that then it is even more important to write the code so I can use the commits to easily navigate the code.

      Do you have any suggestions on this?

      Reply
      1. Reedmace Star

        “Location comments” are useful, I agree, but I would not put one in every measure. Depending on the complexity of the score, I found a frequency of something like one in four to eight measures sufficient to quickly identify your position.

        By the way I like to put them on lines of their own, like little headings. That makes them easier to edit when you copy and paste: it is usually quicker to just delete a whole line and rewrite it than to navigate to the correct position at the end of another line and delete and rewrite just the comment part.

        Raw diff output may not look quite as useable as with your examples, but I would consider that an excessively low common denominator anyway. In a graphical side-by-side comparison tool like kompare, not even your first example should look too bad.

        What to write into those comments, if not measure numbers? Since I most frequently work with vocal music of some sort, my favourite is to quote the relevant part of the lyrics (first verse, if there are several) sung at that time. For example:

        %% gayaiteru kono kisetsu ni mune ga mune ga odoru no
          c8 bes a bes16 c ~ c4 r8 c,16 c |
          c'=''4 bes a g |
          r8 e f c' r e, f c' |
          e,8 f g f8 ~ f4 r |
          \bar "||"
        
          %% (instrumental)
          s1*4
          \bar "||"
        
          %% Tomaranai dokidoki wa hajimari no aizu / Sa-
          r8 c c c  d c ~ c4 |
          r8 c c c  d c ~ c4 |
          r8 f f f  e f4 e8 ~ |
          e8 d c4 r4. c8 |
        
        Reply
        1. Dave Bellows

          That’s largely how I do it as well. I compose directly to Lilypond and put the bar number on a line of its own every 4 or so measures depending on the complexity of the piece. I’ll also often add structural information like “development”, “part B”, etc. This makes it easier to edit multiple measures without having to look up bar numbers in the score — you know what’s going on musically so you can find the spot you need pretty quickly based on the structural information. Not to mention you can easily search (e.g., C-x recapitulation if using Emacs) for the section if you don’t feel like scrolling.

          Reply
    2. Janek Warchoł

      I agree with Reedmace Star that adding barnumbers as comments in each line may introducee a lot of problems – not only you have to edit them all if the numbering changes for whatever reason, but also these changes will totally pollute your commit diffs.

      I believe that barnumbers should be displayed by the editor, just like every decent text editor displays the line numbers of the source file. Of course, determining the current barnumber in LilyPond source file is not an easy task…

      Reply
  2. Ian Hulin

    I do use one line per bar (measure) and add the bar-number comment to the end-of-line.
    Yes it is a pain, but I use Fresobaldi as my source editor of choice and have a couple of snippets bound to Alt-B (for single bar line) and alt-| (for multi-line rests).
    I, too have found adding the text of lyrics useful.
    Obviously everyone’s mileage may vary – you may used Emacs, vi, JEdit or gedit to type in your scores, but another win, along with Urs’ original point about version control, is this:
    you get what you and your source thinks the line number is from the diagnostic if something screws up with the compilation.
    That’s really useful if you’ve got a large work with loads of parts and several movements and lots of “<>”” parallel music blocks.
    I’m not religious about having one bar/measure per source line, but every source line ends with either

    | % bar nn
    or
    | % bars nn – nn
    

    Other good rules to use are
    Always explicitly state the length of the first note on a source line.

    \relative c{
    \key c \major
    c4 d8 e f4. g8 | % bar 01 – yes I know we don’t strictly need to the 4 on the first c
    a4 b c16 d e f g8. a16 | b8 c8 c4 d a, g | % bars 02 – 03
    c,1 \bar|.” % 04 – the end
    }
    

    Cheers,
    Ian

    Reply
    1. Urs Liska

      Yes, explicitly specifying the length of the first note in a line is a very good thing, too. I didn’t mention it because it isn’t really directly related to versioning.

      One more thing I would like to find a good solution for is aligning measure number comments. Usually they are written after the end of the line and therefore not very prominent to see.
      But of course right-aligning them with spaces would be a terrible idea.

      Reply
      1. Janek Warchoł

        Indeed, this alignment problem is why i’d rather have a separate full-line comment with current barnumber every 5 or so bars, rather than enter barnumber at the end of each line.

        Reply
        1. Urs Liska

          But in any case they should appear so often that any conceivable diff with it’s default 3-line context should ‘catch’ a line number, otherwise the commit will be partly meaningless.

          Reply
          1. Janek Warchoł

            Well, this is indeed a complicated issue.

            Fortunately we can always tell git to show more context with -Un option. But maybe the real solution would be to use diff programs integrated with Frescobaldi, so that you could click on a diff hunk, and Frescobaldi would open that file at that place, and compile the pdf with point-and-click and scroll the preview to that measure. Hmm.

            Reply
            1. Urs Liska

              Well, sigh …

              I think this will be (earliest) the third major attempt with Frescobaldi. Before we have to implement MusicXML export, graphical editing in the Music View and probably also the \annotation interface.

              But I admit: displaying the diff against the current HEAD (= the modification since the last ‘save’ equivalent) or right-clicking on a line-number and get a visualization of the history of that line through git blame, and everything else one could dream of … well, sigh …

              Reply
  3. Carl

    I think the “one measure per line” rule varies on context. For many instrumental scores, this may work, particularly those which are very dense. However, I work with a lot of hymns (almost exclusively, in fact), and for music with lyrics, my rule is to line break at the lyrical phrase. I do this with both lyrics (setting them as they would appear as poetry) and music.

    Reply
    1. Urs Liska

      You’re right. With hymns you will probably have a small number of ‘items’ per measure so it will work well to consider the musical phrase as an ‘entity’ to put on a source code line.

      I’m mostly working on songs of the 19th and early 20th century with lots of notes, so sometimes I’m even forced to split single measures over more than one line.
      Lyrics on the other hand I too write down as poems.

      Reply
  4. Markus

    Hi all!

    I, too, use LilyPond (with git for versioning) for “non-static” scores—that is own compositions that may change. Numbering every bar with a simple comment is most helpful, as far as they don’t change.

    A search and replace function comes to my mind:

    Search for

    % NN

    and replace with

    % NN+n

    This function would simply recalculate the bar number comments (not just put i. g. “+25” next to it).

    I guess, one could program a terminal function. Has anyone an idea for this?

    Thank you very much for providing all these valuable information on a great piece of software. I would be very interested in composer specific/non-static score information!

    Reply
    1. Urs Liska

      You mean a function that offsets all of these special comments from “now” on? This could be quite easily done, e.g. as a Frescobaldi snippet. But it’s only easy for inside your current file and variable. Everything else will become complex.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *