Fork me on GitHub
DEBAM and DETIM
Contributing

Git and Github

We use git to keep track of changes we make to the model. Git is a revision control system, similar in purpose to SVN or CVS, but different in execution. If you're new to git, Github has some good documentation on setting up git, and gitref is a good quick-reference page and has an excellent git tutorial as well, the git project's documentation is a good resource for more in-depth details on git's workings, and Jan Krüger has a great git cheat sheet if one needs a quick reference.

The model repository is hosted by Github, a webpage that offers project hosting, as well as a bevy of tools for collaborating using git. Signing up, as well as hosting open source projects, is free, and we strongly recommend that collaborators sign up and use Github to assist in collaboration.

Versioning

As of version 1.0.0 (Sep 2013), we've begun using Semantic Versioning to dictate model version numbers. Roughly speaking, version numbers consist of MAJOR.MINOR.PATCH, which are incremented when

  1. MAJOR: when backwards incompatible changes are made

  2. MINOR: when backwards-compatible functionality is added

  3. PATCH: when backwards-compatible bug fixes are made.

The upshot of which is that your parameter files for model version 1.0.3 will not work with version 3.6.4 but will work with 1.2.0 and 1.0.4. If you are contributing, we highly recommend you read the full SemVer specification.

The various versions of the model are marked in git with tags and can be reviewed on Github. Creating a new tag using git is straightforward, as is pushng the tag to a server:

$ git tag <tag-name>
$ git push <remote> <tag-name>

For example, supose we wanted to tag version 1.2.5, and push this tag to Github. At the shell we would type:

$ git tag v1.2.5
$ git push origin v1.2.5

which create the new tag, and sends it to the server.

Using Git to contribute to model development

Git's a flexible tool, which allows for a wide variety of work flows. Here's one which serves well for working with DEBaM and DETIM, i.e. if you want to contribute to the model by adding a feature, fixing a bug, editing documentation etc.

Workflow:

  1. Fork: Github allows you to create your own fork of the model code, and host it on Github as well. Think of your fork as your own version of the model, which you can modify, upload and share these modifications. Github also offers tools for combining changes from forks into the main project, as well as tools to discussing changes before they are merged. These tools make forking the project a great way to get started contributing, instructions for making your own fork on Github are located at https://help.github.com/articles/fork-a-repo.

This only needs to be done the first time you start working with the model code; your fork will need to be updated occasionally to keep up to date with changes to the model, but you shouldn't need to re-fork the model.

How to create a fork: - Go to the model github page - Click on 'Fork'. This makes your own fork and at the same time copies the entire github model repository (including all branches) to your fork on github.

  1. Download a copy of your fork to your local computer

open terminal

     $ git clone https://github.com/USERNAME/meltmodel.git

(Replace 'USERNAME' with your user name) Now you a local copy of your Github fork on your computer.

  1. Branch: Make a new branch off of the master branch of your local copy, and give it a descriptive name. Branches let you make changes and develop them separate from the main line of development. This way if your changes take a while or you need to work on a different part of the project you can commit the changes you've made so far, and switch back to your master branch for model application. Or if your changes don't work out, you can delete the changes you made by simply deleting the branch instead of having to track down every change made.

Say we want to add a new parameterization to compute longwave radiation, at the terminal (in folder meltmodel) make a new branch by typing:

    $ git branch longwave
    $ git checkout longwave

or, we can use the equivalent one-liner:

    $ git checkout -b longwave

this will create a new branch, entitled longwave and make that the active branch. Now, any changes which we commit to the repository will be made to the new branch only.

The title of the branch longwave is just an example, we could have named the new branch anything, but we should give the branches descriptive names.

  1. Make Changes to the Source Code: Now that we're in a new branch on our local computer, we can make changes at will, by editing, adding or removing files. Git will recognize files in the directory as being in one of four statuses:
    • Untracked: Git is not tracking this file, and it is not included in the repository.
    • Unmodified: Git is tracking this file, and it has not changed since the most recent commit.
    • Modified: This file is being tracked, and has changed since the last commit, but Git has not been told to include these changes.
    • Staged: Some changes made to this file have been staged, and these changes will be included the next time a commit is made.

At the command line, you can view the status of your files via the command

    $ git status 

Editing a tracked, but unmodified, file will change its status to modified, but these changes will not be tracked by Git until we commit them to the repository.

  1. Commit Your Changes: Once you're happy with your changes, it's time to assemble and commit your changes which means that it will allow you to browse the history of changes in the code because by committing the changes they become part of the version control. Because Git doesn't force us to save all of the changes we've made at the same time, we can separate our edits into several commits. If we think of a single commit as a snapshot of the project at a particular point in time, it's a good idea to ensure that every commit we make represents a single change to the project, be it a bugfix, a new feature or one rearrangement. One benefit of making frequent, atomic commits, is that when bugs are found, and you need to back-track to find its source, it is much easier to back track through a series of small changes to root out the offending changes than it is to pick apart a large commit, where several desperate things have been changed. It's not a bad idea to make commits at semi-regular intervals while you're working on the code; once you've finished a small task, make a commit. This way your commit history presents a history of how the code has changed. You may want to compile the model before committing your changes (go to the meltmodel folder and type 'make models')

So how do we make a commit? Assuming we've made some changes, we need to assemble a commit, by staging changes. Git requires you to explicitly add every change that you want included. Suppose we've only changed the source file radiat.c and the corresponding header file radiat.h. * Stage These files are currently untracked by Git. We add them by staging them using the git add command.

        $ git add radiat.c radiat.h
  1. Make More Changes and Make More Commits: We can now happily edit away, making more changes at will. Repeat steps 4 and 5 as needed, making new commits as you go.

  2. Push Branch to Github: At some point you'll want to push the entire branch that contains your the changes on local computer to your own github repository. This will allow you to access the content from any other computer and also makes your changes visible to others. If you have pulled the source from your own fork on Github (see step 2 above) this is as easy as

    $ git push origin longwave
    

    where "longwave" is our example of the name of the branch and needs to be replaced by the name of the branch you are using. This tells git to push the changes you've made on the branch "longwave" to the remote server named "origin" which is, by default, the server you cloned the model from.

Until you are sure that you want to include the changes you've made in the master branch of your fork, it's wise to keep your edits isolated in the branch you've made. Continue this by repeating steps 2 - 5. When your code is ready to be included in the model's "official" code (master version), proceed to 8.

  1. Submit a Pull Request: A good way to let people know that you've been working on the model, and that your changes may be ready to be merged into the master version on github, is to submit a Pull Request through Github. Once you've submitted a Pull request, people can review the changes, discuss modifications, and submit follow-up commits if need be. Github's help page on Pull Requests is a good place to learn more about Pull Requests.

How to make a pull request: Go to your fork on github and change into the branch that you want to merge with the 'official' master version. click on 'submit pull request'.

This will notify the model administrators and create a page where people can discuss the proposed model changes. Note that it is up to the administrator to merge your changes into the 'official' master version. You don't have permission to do so and need to contact R. Hock.

Other useful operations

  1. Deleting a Branch: Git's branches are easy to make, and easy to delete. If we decide that the changes we've made on the branch aren't to your likeing, and want to get rid of them entirely, we can delete the entire branch. Here we're going to delete the longwave branch.

    1. Deleting a Branch Locally: We should first make sure that we're on a different branch from the one we're deleting. Also you have to commit all your changes or stash them before you can switch branches:

      $ git checkout master
      

      we can then delete the branch in our working copy

      $ git branch -D longwave
      
    2. Deleting a Branch on your fork on Github: The above only deletes the local version of the branch on your computer. If this branch has been pushed to your fork on Github, we can delete it there too. This should be done with caution.

      $ git push origin :longwave
      
  2. Merging Branches on your own fork: We've gone over making branches to isolate changes, and deleting branches when those changes don't work out, so it remains to combine branches when changes do work out. It is recommended to merge branches locally and then push the merged branch to github. When there are no conflicts, merging with git is simple. Suppose we've finished making changes on our longwave branch, are pleased with the results, and want to include the code in the master branch of the code. Assuming we're on the longwave branch we first checkout the master branch

    $ git checkout master
    

    And then merge the longwave branch into it:

    $ git merge longwave
    

    Assuming no conflicts were found, your master branch will now have new commits in it which incorporate the changes made on the longwave branch. It's a good idea to look over the new code to make sure that the merge resulted in the code you expected, and that nothing surprising broke.

If you are merging two branches and both have had commits made on them since the branch, it's possible that git will have some trouble resolving the changes made, and you will need to fix the offending lines by hand. Git's good about telling you this though and about parking up your files to help you find points of contention.

Repository Administration

  1. Merge Pull Requests: In case you receive a pull request for any of your branches of your fork on Github you can decide to merge them into your code repository (master or any other branch you may have). Two ways to do so:

    1. Using the Pull Request Merge Button: Github provides an automated way to pull in changes via the Pull Request. If Git detects conflicts in the merge, you will be presented with instructions on manually proceeding with the merge.
    2. Manually merging via the commandline: Following the example we have been working with, to merge the changes we've made on the longwave branch into the master branch we would do the following from the command line:

      $ git checkout master 
      $ git merge longwave
      

    Push to Github: Finally, to push the changes we've made up to Github, we would do the following from the command line.

        $ git push origin master
    
  2. Remote Repositories: Becasue Git is a distributed system, it gives us the abolity to interact with multiple "central" repositories. That is, my local clone of the repository can simultaneously retrieve and send commits to/from my fork on github, the official fork on github, someone else's fork, or remote repositories located elsewhere. On our local machines, we use the git remote subcommand to manage how our local copy of the code interacts with remote copies on servers or elsewhere.

  1. Adding the Official Repo to your Local Repo: Assuming that you have cloned you local copy of the code from your own fork on Github, we'd like to be able to pull code from the official reposotory, say when bug fixes occur. In the commandline, change directories into your local copy of your repository. At the commandline enter:

      $ git remote add regine https://github.com/regine/meltmodel.git
    

    You can double check that the remote has been added correctly using

      $ git remote -v
    

    which will list the remote repositories availibe to your local repo.

    Remotes are useful for working with other collaberators as well, the general syntax for adding remotes is:

      $ git remote add <remote_name> <remote_clone_url>
    
  2. Pulling Changes From a Remote: When we want to bring our local branch up-to-date with a remote branch (say bring master up to date with the official master branch) we use the git pull command.

    • First, checkout the branch we will pull onto

      $ git checkout master
      
    • Then pull changes from the remote regine

      $ git pull regine
      
  3. Pushing Changes To a Remote: The other obvious operation we'd like from remotes is the ability to push changes up to them. We do this via the git push command. The only difference between pushing to your fork, on remote origin and pushing to any other remote is that we specify the remote's name

        $ git push <remote_name>
    

    This assumes that you have write access to the remote repository you are pushing to.

An Example: Suppose we've cloned the official repository, made some changes, and decided to fork the project on Github and push our chages to it. We can start by renaming the official remote

    $ git remote rename origin regine

Then add our remote, giving it the name origin

    $ git remote add origin https://github.com/<user_name>/meltmodel.git

Now we can push the changes we've made on our branch to our fork:

    $ git push origin --set-upstream <branch_name>

by specifying --set-upstream, we're telling git that your local branch specified by corresponds to the same branch located on our remote, origin.

Caveat Git versions prior to v1.8.x may have issues using HTTP(S) addresses. To deal with the you will either need to update your version of git, or use ssh remotes. Github has decumentation to setting up ssh remotes here.

Further information about the remote tool can be found at Git Ref.

A Concise version of the above

Making Model Changes:

  1. Create a new branch:

    $ git branch <branch_name>
    
  2. Check out a branch:

    $ git checkout <branch_name>
    
  3. Make Changes/ Add files

    $ git add <new/changed_filename>
    
  4. Check on what's added/changed/staged

    $ git status
    
  5. Commit changes

    $ git commit
    
  6. Push to Github

    $ git push origin
    
  7. Delete a local branch

    $ git branch -d <branch_name>
    
  8. Merge one branch (source) into another (target)

    $ git checkout <target_branch_name>
    $ git merge <source_branch_name>