Quick start to CTSM development with git - ESCOMP/CTSM GitHub Wiki

Getting started with developing CTSM in git

The following instructions describe the basic development workflow in generic terms. If you prefer to see a tutorial-style specific example, see the May 30, 2018 tutorial, "Using git and GitHub with CTSM".

Learning git

If you are new to git, we recommend the following resources (roughly in order from shorter to longer and more comprehensive):

  • For a glossary of common terms used in git and GitHub documentation, see the GitHub glossary.
  • For a brief overview of git and GitHub, including example workflows and links to more in-depth resources, we recommend GitHub's Git Handbook.
  • For a hands-on introduction, we recommend Software Carpentry's git tutorial.
  • For a slightly more extensive set of tutorials, see Atlassian's git tutorials.
  • For a comprehensive reference, we highly recommend the free pdf book Pro Git. The first three chapters, along with sections 6.1 and 6.2 on GitHub, are particularly useful if you're getting started with git.1

Git also offers extensive built-in help, although it can be hard to understand until you are familiar with basic git concepts:

git help
git help COMMAND

Setting up git

First, make sure you have set up your GitHub and git environments, as described in Recommended git setup. If you have used GitHub and git for other projects, it's likely that you've already done everything necessary in this respect.

Creating a fork

The main CTSM repository (https://github.com/ESCOMP/CTSM) is read-only for most people. Thus, to do development that you want to share with others (or share with yourself easily across machines), you will need to create a fork of this repository on GitHub. To do so, click the "Fork" button at the top right of https://github.com/ESCOMP/CTSM, and create a fork in your personal GitHub user account. You only need to do this once: you'll have one GitHub fork to hold all of your branches.2

Opening an issue prior to starting development

We strongly encourage collaborators to open an issue in the early stages of a project in order to get feedback from other CTSM scientists and software engineers and to avoid duplicated work. You can open an issue here: https://github.com/ESCOMP/CTSM/issues/new/choose.

Feel free to describe your plans in as much or as little detail as you'd like initially. Some things that can be helpful to describe are:

  • Relevance of the proposed science changes
  • Planned structure of the implementation, if known (a new module or class, new subroutine in an existing module, changes to an existing subroutine, etc.)
  • Files you are planning to change, if known
  • Collaborators (if any)

Basic development workflow

Git lets you manage multiple branches within a single local clone. In some circumstances this can be helpful. However, checking out a different branch in an existing clone can interfere with any ongoing cases that you created from that clone, and can make it hard to reproduce what you've done later. So, as a general rule, we recommend having a separate clone for each branch.3

To create a new clone with a new branch, starting from the master branch, do the following. First, make a new clone of the main repository4:

git clone --origin escomp https://github.com/ESCOMP/CTSM.git ctsm_MYBRANCH
cd ctsm_MYBRANCH

(where you should use some descriptive name in place of MYBRANCH).

Then create a new branch for your work:

git checkout -b MYBRANCH master

Finally, get the externals you'll need to run a case:

./manage_externals/checkout_externals

The above git checkout command assumes that you want to create your branch starting from the latest version of the master branch. The master branch contains the latest development code, and is often the best starting point for new developments. Starting from master (as opposed to a release branch) is also important if you plan to get your work integrated into the main CTSM repository in the future. However, in some cases you may want to branch off of a different point. For example, you may want to branch from a particular tag (for example, if you have run a control simulation from that tag and now you want to run a modified version). In that case, you can replace master with the tag you want to start from. If you are unsure where to branch from, please ask us.

Do not commit changes directly to the master branch (or any similar branches that you got from ESCOMP/CTSM, such as release branches). While we have set up safeguards to ensure that you cannot accidentally push your changes back to the ESCOMP repository, you will create headaches for yourself if your version of master diverges from the true master branch.

You can then use the standard git workflow to commit your changes:

[Make some changes]
git status
git add ...
git commit

If/when you want to share your changes, you can do so with5:

git remote add GITUSER [email protected]:GITUSER/CTSM.git
git push -u GITUSER MYBRANCH

replacing GITUSER with your GitHub username.

Merging in recent changes from master

For long-term developments, it is often the case that you want to keep your branch up-to-date with the latest changes on master. This can be because you want to incorporate bug fixes or new features. In addition, if you are planning to eventually merge your branch back into the main repository (via a pull request), then it's a good idea to periodically pull in updates from master to reduce the potential for conflicts in the end. For the latter case, a good time to do this merge from master is just before you start making new changes to your branch after you have stepped away from it for some time.

Before following the instructions in this section, run git status to make sure you don't have any uncommitted changes. If you do have uncommitted changes, either commit them or undo them before proceeding.6

Also, you generally should NOT update to the latest version of master if you have ongoing cases that are being run out of this directory. Existing cases can be in an inconsistent or invalid state after some code updates, so any cases created with your old code version should no longer be used with the updated version. If you need to maintain the usability of old cases, then you should create a separate git clone for this update and any further development.

The first step is to get the latest changes from ESCOMP/CTSM:

git fetch escomp

Before merging these changes into your branch, it's helpful to know what tag your branch is up-to-date with and what the latest tag is on master. This can be done with7:

git describe
git describe escomp/master

The first command will tell you the tag your branch is up-to-date with. The output of this command will look like ctsm1.0.dev060-2-g5428b8e2, where the first part, before the dash (ctsm1.0.dev060) tells you the tag your branch is up-to-date with, the second part (2) tells you how many commits ahead of that tag you are (i.e., commits on your branch that aren't in that tag), and the third part (g5428b8e2) gives the ID of the current commit on your branch (ignore the first g, which just tells you this is a git repository).

The second command will tell you the latest tag on master. The output of this command will typically be shorter, like ctsm1.0.dev068, which tells you that the latest tag on master is ctsm1.0.dev068. So in this case, when you merge the latest version of master into your branch, you will get all of the changes that have been made between ctsm1.0.dev060 and ctsm1.0.dev0688.

You can then merge the latest version of master into your branch with:

git merge escomp/master

If the merge went smoothly, your editor should pop up, letting you type a commit message (or just use the default commit message, which describes the merge you just did). When you save and close your editor, the merge is complete; you can confirm this by rerunning git describe, which should now show you as being up-to-date with the latest tag from escomp/master. You should then rerun checkout_externals in case Externals.cfg, Externals_CLM.cfg or Externals_cime.cfg changed in the merge.

However, it's also possible that there were conflicts that git couldn't resolve. Git will give you a message about this, and will leave the merge in an uncommitted state. The Pro Git book gives some information on resolving conflicts, as does a Tutorial we put together. Bear in mind, though, that conflict resolution can be challenging and error-prone; this is a common source of bugs in the model. If you're not sure of what you're doing, ask for help. After resolving conflicts, it's a good idea to check the diffs in the conflicted file, both from the previous version of your branch and from master (see the tutorial link above for more details).

If you're not ready to deal with the conflicts right now, you can back out to the state you were in before starting the merge with:

git merge --abort

Rerunning checkout_externals

You need to rerun checkout_externals whenever Externals.cfg, Externals_CLM.cfg or Externals_cime.cfg have changed (unless you have already manually updated the relevant external(s) to have the correct branch/tag checked out). Common times when this is needed are:

  • After checking out a new CTSM branch/tag
  • After merging some other CTSM branch/tag into your currently checked-out branch

Submitting a Pull Request

If you'd like to get your developments onto the master branch, you will need to submit a GitHub Pull Request. To do this:

  1. Push the latest version of your branch to your fork, as described in Basic development workflow
  2. Navigate to your fork on github (https://github.com/GITUSER/CTSM)
  3. In the "Branch" pull-down menu on the right, select the correct branch
  4. Next to the "Branch" pull-down menu, click the button labeled, "New pull request"
  5. In the "Open a pull request" page, confirm the forks and branches being used for the pull request. On the left you should see "base fork: ESCOMP/CTSM" and "base: master". On the right you should see "head fork: GITUSER/CTSM" and "compare: MYBRANCH" (where GITUSER will be your git username, and MYBRANCH will be the branch you'd like brought to master).
  6. Enter a short but descriptive title for this pull request
  7. In the comment box, give a more detailed description of this pull request
  8. Click the green "Create pull request" button
  9. Optionally, once the pull request is created, you can comment on individual lines. To do this, click on "Files changed" (just below the title of the pull request). As you hover over changed code, you'll see a blue button with a "+" appear; if you click this, you can enter a comment for that specific change.

This article gives some useful tips on how to be a good author of Pull Requests.

Incorporating changes in your Pull Request

After you submit a pull request, your changes will likely be reviewed by one or more people. If they ask for changes, please go ahead and make whatever changes you are able to yourself. You can then commit your changes (either as a single commit or multiple commits) and push them back to your fork. As soon as you push the changes back to your fork, GitHub will notice this; it will automatically update the Pull Request and notify reviewers and anyone else who is watching the Pull Request.

At that point, reviewers will typically look at your latest changes and then either approve the Pull Request or ask for further changes.


  1. You can skip the last section of chapter 3, on rebasing, until you have more experience with git. It's easy to cause problems for yourself or others with rebasing. Furthermore, we recommend avoiding rebasing if you have done any scientific runs with a branch: rebasing rewrites history, which can make it impossible to reproduce exactly what you've done before.

  2. The ESCOMP CTSM repository is public. This means that your fork will also be publicly readable (but only writeable by you, unless you add collaborators). If you want to keep your developments private for some time, you can avoid pushing them to your fork. In fact, since git is a distributed version control system, you can get its full benefits without pushing your changes at all: you can just commit them to the local repository that exists on your machine and wait to push them until you're ready to share them. If you want to share them with a small group of people, you can create a private repository on GitHub or elsewhere - but you cannot use GitHub's "fork" functionality to do this.

  3. Once you have become comfortable with git, a good alternative to having separate clones is to use git worktree. This gives you a separate working directory that shares branches, remotes, etc. with your original clone.

  4. Doing the initial clone of the main ESCOMP repository (rather than of your personal fork) ensures that the master branch is set up to track ESCOMP's CTSM master branch. This connection to ESCOMP's master branch is typically what you want: trying to work with the master branch on your fork can create confusion and errors.

    The instructions here will give you two remotes whose names have unambiguous meanings: one named escomp that points to the main repository, and one named with your GitHub username. Many git tutorials refer to remotes named origin and upstream. With the above recommendations, escomp corresponds to upstream, and the remote named with your username corresponds to origin. Of course, feel free to use origin and upstream if you prefer, but I prefer my remotes to be named explicitly with their GitHub username or organization name.

  5. You only need to do the git remote add command once per clone. The URL used here assumes that you have set up ssh keys, as described in Recommended git setup. If you have not done so, you can use the URL https://github.com/GITUSER/CTSM.git.

    The -u (or --set-upstream) argument to git push sets the upstream of MYBRANCH to GITUSER/MYBRANCH. This way, you can run git push and git pull from this branch in the future without having to specify any other arguments.

  6. For help with undoing uncommitted changes, see the Pro Git book.

  7. The commands in this section assume that your branch is currently checked out. That will typically be the case if you are following the instructions in this guide.

  8. Occasionally, master will contain commits beyond the last tag. For CTSM, these untagged changes are typically just documentation or other minor changes. Even if git describe shows that escomp/master has commits beyond the last tag, you can still follow all of the instructions here.

⚠️ **GitHub.com Fallback** ⚠️