The preferred way to contribute to the Freesurfer code base is to fork the main repository on GitHub. Here we outline the workflow used by the developers:

Initial Setup

  1. Sign up for a github account if you don't already have one. When creating an account, you can use any email you want, but developers at the Martinos Center should eventually link their <username>@mgh.harvard.edu email to their GitHub account. This can be done after the account is created.

  2. Fork the freesurfer project repository by clicking on the 'Fork' button near the top right-hand of the page. This creates a copy of the freesurfer code base under your account on the GitHub server.

  3. On your local machine, make a clone of your freesurfer repository (the one you forked):
    git clone git@github.com:<git_username>/freesurfer.git
  4. Add the main freesurfer repository as a remote to the local clone you already have on your local disk, and set it as the upstream remote:

    git remote add upstream git@github.com:freesurfer/freesurfer.git
  5. clone fork
  6. create branch
  7. push branch
  8. submit pull request

Data files

  ## External users.
  git remote add datasrc https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/repo/freesurfer.git

  ## Internal users.
  git remote add datasrc file:///space/freesurfer/repo/annex.git

  git fetch datasrc
  git annex get distribution/average/fsaverage.tar.gz

This page is provided for FreeSurfer developers to assist in the CVS -> git transition.

This page is not meant to be a comprehensive guide for using git. Git is a feature loaded version control system which at times can be a bit of a hurdle to learn. However, when used in its simplest form, it can be very similar to most all other version control systems, including CVS. Below are many of the basic CVS commands used by FreeSurfer developers the git equivalent of that command.

The following sites are great resources for those who want to dig deeper and and learn more about git and its features.

Initial Git Setup

Very first thing to do. Add the following line to your .cshrc or .bashrc file.

## bash
export PATH=/usr/pubsw/packages/git-annex/current/bin:$PATH

## csh
setenv PATH "/usr/pubsw/packages/git-annex/current/bin":"$PATH"

When we start out using git we want to set a few of our configuration settings. We only need to do this one time:

$> git config --global user.name "Zeke Kaufman"
$> git config --global user.email zkaufman@nmr.mgh.harvard.edu
$> git config --global core.editor <your preferred editor (e.g. emacs, vim, etc)>
$> git config --global color.ui true

For additional git specifics setting:

Customizing-Git

Checkout out the main branch

When working with CVS, we would checkout out the FreeSurfer repository using the cvs checkout dev command. In git we 'clone' repositories. This gives us a local version of the repository which we can work with:

## CVS 
$> cvs checkout dev

## git
$> git clone file:///space/freesurfer/repo/freesurfer

## The git read-only repo:
$> git clone https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/repo/freesurfer.git

Or check out a specific branch:

## CVS
$> cvs checkout -r stable6 dev

## git
$> git clone -b stable6 file:///space/freesurfer/repo/freesurfer

Additional information and examples:

Cloning-an-Existing-Repository

Cloning-an-Existing-Repository

Daily Workflow

Updating your code

In CVS, when we want the most up-to-date version of the code, we issue a cvs update command. This will update our files to the latest version, restore any missing files, and warn us of any conflicts. The nearest equivalent in git is the git pull command. This will update our local repository and update all the necessary files to the most recent version. It is good practice to always issue a git pull command before starting to work on any files.

## CVS
$> cvs update

## git
$> git pull

One major difference between cvs update and git pull command is that (depending on version/platform specifics) git pull may not restore missing files (i.e. file deleted locally). In git, if we want to restore locally deleted files, we need to take the additional step of issuing a git checkout command. For example:

## CVS
$> cvs update
  cvs update: warning: README was lost
  U README

## git
$> git pull
$> git status

    deleted:    README.txt

Use the checkout command to restore a deleted file:

$> git checkout README.txt

Additional information and examples:

Git Pull

Modified files

Generating diffs between your working copy of the code, and the repository version, is also very similar with git and cvs. For example, say we want to know what files differ:

## CVS
$> cvs update
  M README

## git
$> git status

  modified:    README.txt

To view the difference, use the diff command just as you would in CVS:

## CVS
$> cvs diff README
  Index: README
  ===================================================================
  RCS file: /space/repo/1/dev/dev/README,v
  retrieving revision 1.13
  diff -r1.13 README
  20a21
  > An example line of added text.

## git
$> git diff README
  diff --git a/README b/README
  index 95ec88a..d4686af 100644
  --- a/README
  +++ b/README
  @@ -18,3 +18,4 @@
  +An example line of added text.

View log information

Again, CVS and git are very similar in this regard:

## CVS
$> cvs log README
  ----------------------------
  revision 1.13
  date: 2016/04/08 20:27:48;  author: nicks;  state: Exp;  lines: +1 -1
  this change requires retesting EVERYTHING
  ----------------------------

## git
$> git log README
commit 7fd91e12ec4e619c18cd11b0a156327322ffbfaf
Author: Z K <zkaufman@nmr.mgh.harvard.edu>
Date:   Tue Apr 12 05:51:13 2016 -0400

    this change requires retesting EVERYTHING

If we wanted to inspect the difference:

## CVS
$> cvs diff -r 1.12
  ===================================================================
  RCS file: /space/repo/1/dev/dev/README,v
  retrieving revision 1.12
  diff -r1.12 README
  1c1
  < FreeSurfer © 2011 The General Hospital Corporation (Boston, MA) "MGH"
  ---
  > FreeSurfer © 2011-2016 The General Hospital Corporation (Boston, MA) "MGH"

## git
$> git diff dd623df16051522125419 README
  diff --git a/README b/README
  index a4daeb1..95ec88a 100644
  --- a/README
  +++ b/README
  @@ -1,4 +1,4 @@
  -FreeSurfer © 2011 The General Hospital Corporation (Boston, MA) "MGH"
  +FreeSurfer © 2011-2016 The General Hospital Corporation (Boston, MA) "MGH"

Commit a change

Git and CVS can be virtually identical when it comes to committing changes. The primary difference is that git requires the additional step of pushing to the central repository. This means issuing the git push command after committing all your changes:

## CVS 
$> cvs commit -m "Fixed a bug." <file_name>

## git
$> git commit -m "Fixed a bug." <file_name>
$> git push   ## DON'T FORGET TO DO THIS!!

Always issue a git push command after committing all your changes

Additional information and examples:

Saving changes

Recording changes to the repository

Adding/Removing a file

Adding and removing files in CVS and git is also a very similar operation. Use the git rm and git add command in the same way you would use the cvs rm and cvs add command. Just remember to commit the change, followed by a git push. For example,

Adding a file:

## CVS
$> cvs add <file_name>
$> cvs commit -m "initial add of new file." <file_name>

## git
$> git add <file_name>
$> git commit -m "initial add of new file." <file_name>
$> git push

Removing a file:

## CVS
$> cvs rm <file_name>
$> cvs commit -m "initial add of new file." <file_name>

## git
$> git rm <file_name>
$> git commit -m "Removing obsolete file." <file_name>
$> git push

Additional information and examples:

git-add

Tracking-New-Files

Help! Just reset my repo!

Sometimes our workspace just gets over cluttered with changes we don't actually want. And we just want to get rid of everything and give us exactly what exists in the repository:

## CVS 
$> cvs update -C -d

## git
$> git reset --hard origin/master

Data files

Data files represent a special case for source code repositories and generally speaking data files should not be stored in a source code repo. Rather they should be stored in a separate storage area reserved for times when retrieval is required. Like updating test data, or performing local installations. Think of "source code" as files which are made up of text and can be easily inspected by the human eye and diff'ed by the diff program, and data files as files stored as binary and not required for compilation.

In the past our CVS repo contain ALL the data files. This caused major bottlenecks, time delays and space requirements for users when they only wanted to view source code. Going forward, the free surfer repo will use the git-annex software for storing data file.

A default clone of the repo will only give the user source code. Data files need to be specially requested. Data files stored in git annex will look like this:

$> ls -l testdata.tar.gz
  testdata.tar.gz@ -> ../.git/annex/objects/73/j9/SHA256E-s108571796--31df343ebab2d0f7f002f1d55c66100e23dc7eeacd4a8ede7723201ad09fd9b7.tar.gz/SHA256E-s108571796--31df343ebab2d0f7f002f1d55c66100e23dc7eeacd4a8ede7723201ad09fd9b7.tar.gz

Getting data files

$> git annex get testdata.tar.gz
  get testdata.tar.gz (from origin...)
  SHA256E-s108571796--31df343ebab2d0f7f002f1d55c66100e23dc7eeacd4a8ede7723201ad09fd9b7.tar.gz
     108,571,796 100%  110.59MB/s    0:00:00 (xfr#1, to-chk=0/1)
  ok
  (recording state in git...)

Add a data file

## CVS
$> cvs add <file_name>
$> cvs commit -m "Initial add." <file_name>

## git
$> git annex add <file_name>
$> git commit -m "Initial add." <file_name>
$> git push
$> git annex copy --to origin <file_name>

Remove data file

## CVS
$> cvs rm <file_name>
$> cvs commit -m "Removing from repo." <file_name>

## git
$> git rm <file_name>
$> git commit -m "Removing from repo." <file_name>
$> git push

Modifying a data file

The git annex get <file_name> will retrieve a data file from the server so that you can access it contents. However, this file remains read-only. If you want to actually modify the data you will need to unlock it for modification purposes:

$> git annex unlock <file_name>
## Make modifications to <file_name>
$> git annex add <file_name>
$> git commit -m "Updating test data." <file_name>
$> git push
$> git annex copy --to origin <file_name>

Organizing data files using metadata

Data files in the freesurfer repository use metadata tags to help keep the data organized and requirements to a minimum. Currently their are two tags that can be assigned to a datafile, makecheck and makainstall. If a data file is required for the make check command, it should get the makecheck tag. If it is required for the make install command, it should get the makeinstall tag. For example, to assign a metadata tag:

  $> git annex metadata mri_ca_register/testdata.tar.gz -s fstags+=makecheck

To get all data files that have a tag:

  $> git annex get --metadata fstags=makecheck .

To see a list of all files that have a tag:

  $> git annex find --metadata fstags=makecheck