Skip to content
Kate Hedstrom edited this page Apr 8, 2016 · 35 revisions

Developers Guide

This guide mainly applies to developers who have write access to the https://github.com/NOAA-GFDL repositories. These developers should follow specific conventions or policies regarding branching and merging. Even if you don't have write access to the NOAA-GFDL/* repositories the material on this page may be useful for understanding and organising your development process.

Once you have downloaded all repositories with:

$ git clone --recursive git@github.com:NOAA-GFDL/MOM6-examples.git MOM6-examples

you will probably want to edit code in the sub-modules. Since sub-modules have specific versions checked out, you will need to checkout a branch instead. Type:

(cd src/MOM6; git checkout dev/master)
(cd src/SIS2; git checkout dev/master)

Under most circumstances, a git status in MOM6-examples will reveal that nothing appears to have changed. That is because the HEAD of dev/master on all repositories are in sync and consistent with those recorded in MOM6-examples. If you ever issue a git submodule update then the submodule(s) will be reset to the appropriate detached state.

Workflow

There are many combinations of operations a developer might have to enact which in combination can be made more succinct than follows. Here, we have atomized some operations into self-contained steps from which a developer can build more sophisticated operations.

git status and fetch

git status is your friend. It tells you everything you should know. Because of the use of sub-modules git status might show statuses that are not covered in most git tutorials and documentation.

After a recent clone of MOM6-examples a git status within the MOM6-examples directory will reveal

~/MOM6-examples$ git status
# On branch dev/master
nothing to commit (working directory clean)

which means everything is OK.

git fetch will check with the origin, in this case GitHub, and find out what has changed on the server since you last synced. git fetch does not change your currently checked-out files. It will do no harm.

If you see no messages after git fetch then you were already up to date. Often you will something like this:

~/MOM6-examples$ git fetch
Enter passphrase for key '/home/aja/.ssh/NOAA_rsa':
remote: Counting objects: 206, done.
remote: Compressing objects: 100% (121/121), done.
remote: Total 206 (delta 101), reused 116 (delta 83)
Receiving objects: 100% (206/206), 188.26 KiB | 0 bytes/s, done.
Resolving deltas: 100% (101/101), done.
From github.com:NOAA-GFDL/MOM6
   9e328e9..50fe6e4  dev/master -> origin/dev/master

which means there are new commits on the server. A subsequent git status will show:

On branch dev/master
Your branch is behind 'origin/dev/master' by 20 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working directory clean

Wow - someone has been busy!

Your branch is behind and can be fast forwarded - git pull

After a git fetch, when git status shows:

# On branch dev/master
# Your branch is behind 'origin/dev/master' by 1 commit, and can be fast-forward

then you can "pull" in changes from GitHub without fear of [code] conflicts with your current working directory. Issue git pull, for example:

~/MOM6-examples$ git pull
Updating e7b8b46..fa7e377
Fast-forward
 README.md |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Creating a branch

When you are making a set of related code or configuration changes it is best practice to do so on a specific branch. Our branch naming policy recommends branch names of the form user/abc/description for personal updates or `dev/description' for updates you are working on collectively.

To create your new branch:

git checkout dev/master
git branch user/abc/my_little_idea
git checkout user/abc/my_little_idea

where abc are your user initials (we typically use initials for legacy reason but you could use your GitHub account name if you prefer) and my_little_idea is a descriptive branch name. Notice that the first step was to checkout dev/master. This ensures the branch originates from dev/master which is a generally good idea although there are occasions where you might branch from another branch.

Without the second checkout, the current working directory would still show dev/master. The git branch creates the branch but does not move you on to it.

At a later stage, if you want to share your branch, you will need to push your branch upstream to GutHub with

git push origin user/abc/my_little_idea

Thereafter, when you are on your branch, a simple git push will push to the correct remote branch.

When and where to branch

We use branches for code that either needs to be evaluated via a pull request or should be kept aside. With the three-repository setup there is a question of where a branch (and associated pull request) should be made.

  • If your explicit changes are only in src/MOM6/ then make the branch within src/MOM6/ and the pull request for MOM6.
    • if there are implied changes (e.g. changes answers or parameter documentation in MOM6-examples) then a branch in MOM6-examples is also needed unless are not submitted those answer changes - we will see those changes when we evaluate the MOM6 pull request.
  • If your explicit changes are only in src/SIS2/ then make the branch within src/SIS2/ and the pull request for SIS2.
  • If your explicit changes are only in MOM6-examples/ (e.g. in tools/ or ocean_only/) then make the branch within MOM6-examples/ and the pull request for MOM6-examples.
  • If you have explicit change in both MOM6-examples/ and src/MOM6 (or other sub-module) then we need the same branch made in both. Only one pull request for MOM6 is necessary (a corresponding pull request for MOM6-examples would be OK but redundant).

Commit procedure for MOM6 and MOM6 examples

The section "A core-developer working on GitHub" in the MOM6 repository policies document outlines the procedure for testing and commit in the context of one repository. This page illustrates how to make coordinate commits between two repositories, namely MOM6-examples and the sub-module MOM6. The same applies to the sub-module SIS2.

The usual workflow for code development is

  1. Develop and test code

This typically involves editing source code, compiling with all compilers, running tests with all executables and checking answers.

Rules for commiting to dev/master are in section Policies for dev/master but the highlights are:

  1. each commit compiles without errors using all sanctioned compilers.

  2. regression tests pass with all the sanctioned compilers.

  3. commits are logged following the commit logging guidelines.

  4. Commit code changes to MOM6

Commit to the MOM6 first (or the relevant sub-module) so that the new commit hash of MOM6 can be recorded with any associated changes in MOM6-examples.

cd src/MOM6
git add file1 [file2] ...
git commit
git push

Should there be any updates on GitHub before the git push then the testing procedure in 1. should be revisited. The git push is not immediately necessary but it will be required before a git push of MOM6-examples so you might as well do "push MOM6" now. Besides, the longer you leave it, the more likely you'll have to update and merge.

  1. Add new version of MOM6 and new answers in MOM6-examples

If you cd up to MOM6-examples, a git status will now show that MOM6 has "(new commits)", e.g.:

> git status
# On branch dev/master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   ice_ocean_SIS/OM4_025/timestats.gnu
#	modified:   ice_ocean_SIS/OM4_025/timestats.intel
#	modified:   ice_ocean_SIS/OM4_025/timestats.pgi
#	modified:   src/MOM6 (new commits)

In this example, the new code we just pushed to MOM6 corrected a bug and changed the answers in OM4_025. The new answers and new version of MOM6 should be committed together:

git add -u ice_ocean_SIS/OM4_025/timestats.*
git add src/MOM6
git commit
git push

In the instance where the answers did not change then a git status will show you that only src/MOM6 (has new commits), i.e.:

> git status
# On branch dev/master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   src/MOM6 (new commits)

Simply adding and committing src/MOM6 will mean MOM6-examples is using the latest version of MOM6:

git add src/MOM6
git commit
git push

Your branch is ahead - git push

After following the commit procedure for MOM6 and MOM6-examples a git fetch followed by a git status might show

~/MOM6-examples/src/MOM6$ git status
# On branch dev/master
# Your branch is ahead of 'origin/dev/master' by 1 commit.

If this is the case, then do a git push:

% git push
Counting objects: 5, done.
Delta compression using up to 64 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 432 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@gitlab.gfdl.noaa.gov:alistair.adcroft/mom6-workspace.git
   ae8b847..6a38fe6  master -> master

Now everyone else can see the commits you have just pushed, either on GitHub or by using git status and fetch.

Your branch has diverged - git pull --rebase

After a git fetch, when git status shows

~/MOM6-examples$ git status
# On branch dev/master
# Your branch and 'origin/dev/master' have diverged,
# and have 3 and 2 different commit each, respectively.

then you have 3 commits to push but there are already 2 to "pull" which will stop you from being able to "push".

There are two ways forward. The first method results in merge-loops in the history. The second method often produces a linear-history (albeit with some commits in non-chronological order!).

git pull (always create a merge)

If you issue git pull this will merge your 3 commits with the servers 2 commits and create a new commit. If there are no conflicts you will be prompted with a commit message

Merge branch 'dev/master' of github.com:NOAA-GFDL/MOM6-examples into dev/master

which you should leave unchanged and save. You can optionally add annotations for the merge (be sure to leave the second line blank).

If there are conflicts during the merge, you should resolve the conflicts and create commits following the commit procedure for MOM6 and MOM6-examples.

git pull --rebase (try to avoid a merge)

This method rewinds your own commits, advances through the commits from GitHub and then replays your commits after those from GitHub. Issue git pull --rebase, for example:

~/MOM6-examples$ git pull --rebase
First, rewinding head to replay your work on top of it...
Applying: Added new eddy parameterization
Applying: Fix problem with gnu compiler

If a conflict occurs you will see

~/MOM6-examples$ git pull --rebase
First, rewinding head to replay your work on top of it...
Applying: Creating conflict
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Failed to merge in the changes.
Patch failed at 0001 Creating conflict

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".

You will need to either resolve the conflicts or "abort" and try a merge as shown above.

Sub module has modified content

If a git status shows that MOM6 (or another sub-module) has "modified content" or "untracked content" then it means you have local edits in that directory, e.g.

% git status
# On branch dev/master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#   (commit or discard the untracked or modified content in submodules)
#
#	modified:   src/MOM6 (modified content, untracked content)
#
no changes added to commit (use "git add" and/or "git commit -a")

In this instance, you should cd src/MOM6 and follow the the commit procedure for MOM6 and MOM6-examples.

Sub module has new commits

There are two cases where a git status in MOM6-examples will show you that src/MOM6 has "new commits" like this:

> git status
# On branch dev/master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   src/MOM6 (new commits)

Either you have added commits to MOM6 or there are new commits that MOM6-examples expects MOM6 to point too. Technically, the message means that the MOM6 commit registered in MOM6-examples is not the same as is currently checkout in the src/MOM6/ directory.

1) If you added commits to MOM6, then simply "add, commit and push" src/MOM6 as if it were a regular file. This will mean that new clones of MOM6-examples will use the newer version of MOM6:

git add src/MOM6
git commit
git push

It is important to push MOM6 first, otherwise a new clone of MOM6-examples will point to a non-existent commit of MOM6.

2) If the message appeared as a result of a git pull in MOM6-examples/ then MOM6 needs to be updated. If you are in a developer mode you could just do

cd src/MOM6/
git pull

or as an end-user, in the MOM6-examples/ directory do:

git submodule update src/MOM6

which will fetch and checkout the correct version of MOM6.

Useful git commands

Here are a few git commands.

  • gitk fname

To pop various windows with history, comparisons, etc.

  • git log

For logs of the changes made to the branch

  • git diff MOM6

to see what files differ.

  • git submodule update src/SIS2

An example of updating to a new submodule that has evolved outside of our main development path. Updating all submodules is necessary to ensure that local changes are compatible across all the submodules.

  • From MOM6-examples/

git add src/MOM6
git commit src/MOM6

in order to update the submodule MOM6 that is held inside MOM6-examples.

Policies