Versioning of Igor Code - suggestions please

Hello all,

I am (slowly) moving to GitHub to allow me to do version control as I write Igor procedures. I'd like to be able to be able to identify which version of the procedure was run in a particular Igor experiment. The only thing I can think of is to print something in the history area that identifies which version of the code was run. I'm wondering what other people do or if anyone has better suggestions? Maybe there is a way to incorporate commit versions of the code somehow? Any suggestions appreciated.

Thanks,
Steve
I am using a dedicated data folder (also for checking whether it has been run before) for my "environment" and store the "package" version in a coded string variable, e.g. "NAC 3.12 beta".
Other opinions?
HJ
HJDrescher wrote:
I am using a dedicated data folder (also for checking whether it has been run before) for my "environment" and store the "package" version in a coded string variable, e.g. "NAC 3.12 beta".
Other opinions?
HJ

HJ, do you mean that you keep the procedure with the experiment (local)? I have the procedures in User Procedures folder and so when I open old experiments, they have the latest version (which is great, but then I don't know which version did the analysis).
jjweimer wrote:

Does Git have the same?


Thanks for that. I'm not aware of other versioning systems. GitHub has a UID for each commit, so my guess is that can be used, but I don't know how to specify that after the commit. I'd like a method that just happened automatically like the Revision number you mention.
ATM my procedures are located in one of the Igor procedure folders: Global on one computer (resp. a shortcut to the actual file on a server).
The use of a datafolder has the big advantage that you can check whether your application has been run before in that particular experiment file ("DataFolderExists") without any run-time-error-handling and it keeps the root folder tidy.

Here is an example:
I have a main datafolder just for the "typical" data in my experiments.
root:NAC //  <-- used for "valid experiment checking"

This one contains another one for program settings
root:NAC:Setting // and a couple of other folders

and this one contains my version string
root:NAC:Setting:NACVersion="3.14 alpha" // <-- used for patching etc.

You could also generate a wave that hold this information for each function...

I also use the version string to define the title of a "control panel".
Printing it in the history is good for documentation, but if it's not the first entry it becomes difficult to find again.

Hope that's inspirational,
HJ
Git does not have keyword expansion like SVN/CVS does. This is a design decision in git. The often talked about alternative using Id from here does not do what you need.

In my git projects I usually implement one of following solutions:

  1. Hardcode the versions using #pragma version or a constant. This works if you release seldomly and thus the additional hassle is not a problem

  2. Add a version.ipf file which will be generated by your release script

  3. Use FunctionPath("") together with ExecuteScriptText to get the git version at runtime. This assumes that the user installs from a git repository. You then need to store the git version in a global string variable which is killed before experiment save. Very convenient but a lot work to implement.



The script for the second version can be something like:

#!/bin/sh version=$(git describe --always --tags) file="myproject_version.ipf" rm -f "$file" echo "#pragma rtGlobals=3\n" >> "$file" echo "// DO NOT EDIT: Your changes are lost" >> "$file" echo "// Last written: $(date)" >> "$file" echo "StrConstant version = \"$version\"\n" >> "$file"

You need a dummy version file in the repository and need to include that file by your main procedure.

PS: Other git config hints are in http://www.igorexchange.com/node/6013.

EDIT: Git's keyword expansion is useless for project versioning. Clarified statement.
I see two slightly different elements of your question that are being discussed.

The first is how to determine what "version" of your code is being executed at the time it is being executed. The second is how to store that version so that when you come back to your experiment at a later time, you know what version was used originally.

Thomas's suggestions address the first element of the question very nicely. I would add that since git commit ids are hashes, knowing the hash alone that represents the state of your code for a particular analysis may not be all that useful. Unlike in Subversion, where revision numbers are sequential, you wouldn't have any idea just looking at two git commit ids if one came before the other. Of course there are ways to figure that out. You might be best served by storing both a human readable version number and the git commit id. For example, you could store "3.24.1c46fe2", where "3.24" comes from you manually setting the version number in a procedure file somewhere and "1c46fe2" comes from git directly using one of the methods mentioned by Thomas. That way you don't need to manually increment the human readable version number every time you make a change in your code (only when you've made significant changes) but it's possible for you to figure out exactly what code was used if that ever becomes necessary.

As for the second element of your question, how to store the version with the experiment itself, you have a few options. One is to print something to the history window. Another is what Hans suggested and store the version information in a specific global variable. You can also store such information in user data. For windows (graphs, panels, etc.) use SetWindow to set the user data and GetUserData to read it back. Controls (buttons, check boxes, etc.) also support user data. You can also store information in a wave's note (use the Note operation to set it and the note function to read it back).

I suspect that the best option would be storing the information in a global variable, but depending on what exactly you're doing it could make more sense to store it in user data or the wave note.

For those of you using Subversion and thinking about jjweimer's suggestion of using SVN keywords in procedure files, let me add a warning. In subversion, each file has its own revision number, and that's set the last time a file or its subversion properties is modified. If you update your SVN working copy to the very latest revision (HEAD), the working copy itself will have the latest revision number, but each individual file in that working copy may have a different (earlier) revision number. The SVN keyword substitution will substitute the *file's* revision number and date, not that of the entire repository. If you use multiple procedure files as part of an analysis, but if you stored the revision information for only *one* of those files, you wouldn't necessarily be able to determine which version of the other files was used at the time. If you need to do something like this with Subversion checkout, you can use Igor's ExecuteScriptText operation to execute "svn info ." from the root directory of your working copy (or the part of the working copy that's relevant to your analysis) and then parse out the revision number from the output of that command.
Regarding the non-sequential commit hashes mentioned by aclight.
My method uses git describe --tags --always and by tagging specific commits of your repository you get a version string like

1.2-202-g95c96aa

which can be read as "The last tag was 1.2 then 202 commits later the current version is g95c96aa". Altough this is still no sequential, by using a proper tag labeling scheme you can get the prefix of the version string to be a parseable number.
Thank you for the responses to my questions. I'm new to versioning and to git and hence pretty clueless. I'll investigate these suggestions and see what works best for me. Thanks all!