Git Workflow
The GEOS project is hosted on github here. For instructions on how to clone and build GEOS, please refer to the Quick Start Guide. Consider consulting https://try.github.io/ for practical references on how to use git.
Git Credentials
Those who want to contribute to GEOS should setup SSH keys for authentication, and connect to github through SSH as discussed in this article. Before going further, you should test your ssh connection. If it fails (perhaps because of your institution’s proxy), you may consider the personal access token option as an alternative.
Downloading the Code
Once you have created an ssh-key
and you have added it to your Github account you can download
the code through SSH. The following steps clone the repository into your_geosx_dir
:
git clone [email protected]:GEOS-DEV/GEOS.git your_geosx_dir
cd your_geosx_dir
git lfs install
git submodule init
git submodule update
If all goes well, you should have a complete copy of the GEOS source at this point. The most common errors people encounter here have to do with Github not recognizing their authentication settings.
Branching Model
The branching model used in GEOS is a modified Gitflow approach, with some modifications to the merging strategy, and the treatment of release branches, and hotfix branches.
In GEOS, there are two main branches, release
and develop
.
The develop
branch serves as the main branch for the development of new
features.
The release
branch serves as the “stable release” branch.
The remaining branch types are described in the following subsections.
Note
The early commits in GEOS (up to version 0.2) used a pure Gitflow approach for merging feature branches into develop. This was done without cleaning the commit history in each feature branch prior to the merge into develop, resulting in an overly verbose history. Furthermore, as would be expected, having many active feature branches resulted in a fairly wide (spaghetti) history. At some point in the development process, we chose to switch primarily to a squash-merge approach which results in a linear develop history. While this fixes the spaghetti history, we do potentially lose important commit history during the development process. Options for merging are discussed in the following sections.
Feature Branches
New developments (new features or modifications to features) are branched off
of develop
into a feature
branch.
The naming of feature branches should follow feature/[developer]/[branch-description]
if you expect that only a single developer will contribute to the branch,
or feature/[branch-description]
if you expect it will be a collaborative effort.
For example, if a developer named neo
were to add or modify a code feature
expecting that they would be the only contributor, they would create a branch
using the following commands to create the local branch and push it to the remote
repository:
git checkout -b feature/neo/freeYourMind
git push -u origin feature/neo/freeYourMind
However if the branch is a collaborative branch amongst many developers, the appropriate commands would be:
git checkout -b feature/freeYourMind
git push -u origin feature/freeYourMind
When feature
branches are ready to be merged into develop
, a Pull Request
should be created to perform the review and merging process.
An example lifecycle diagram for a feature branch:
create new feature branch:
git checkout -b feature/neo/freeYourMind
A-------B-------C (develop)
\
\
BA (feature/neo/freeYourMind)
Add commits to 'feature/neo/freeYourMind' and merge back into develop:
A-------B--------C-------D--------E (develop)
\ /
\ /
BA----BB----BC (feature/neo/freeYourMind)
See below for details about Submitting a Pull Request.
Bugfix Branches
Bugfix branches are used to fix bugs that are present in the develop
branch.
A similar naming convention to that of the feature
branches is used, replacing
“feature” with “bugfix” (i.e. bugfix/neo/squashAgentSmith
).
Typically, bugfix branches are completed by a single contributor, but just as with
the feature
branches, a collaborative effort may be required resulting a
dropping the developer name from the branch name.
When bugfix
branches are ready to be merged into develop
, a Pull Request
should be created to perform the review and merging process.
See below for details about Submitting a Pull Request.
Release Candidate Branches
When develop
has progressed to a point where we would like to create a new
release
, we will create a release candidate branch with the name consisting
of release_major.minor.x
number, where the x
represents the sequence of patch tags that
will be applied to the branch.
For instance if we were releasing version 1.2.0
, we would name the branch
release_1.2.x
.
Once the release candidate is ready, it is merged back into develop
.
Then the develop
branch is merged into the release
branch and tagged.
From that point the release
branch exists to provide a basis for maintaining
a stable release version of the code.
Note that the absence of hotfix
branches, the history for release
and
develop
would be identical.
An example lifecycle diagram for a release candidate branch:
v1.2.0 (tag)
G (release)
^
|
A----B-----C----D-----E-----F-----G------------ (develop)
\ \ /
\ \ /
BA----BB----BC----BD (release_1.2.x)
Hotfix Branches
A hotfix
branch fixes a bug in the release
branch.
It uses the same naming convention as a bugfix
branch.
The main difference with a bugfix
branch is that the primary target branch is the
release
branch instead of develop
.
As a soft policy, merging a hotfix
into a release
branch should result in
a patch increment for the release sequence of tags.
So if a hotfix
was merged into release
with a most recent tag of
1.2.1
, the merged commit would be tagged with 1.2.2
.
Finally, at some point prior to the next major/minor release, the release
branch should be merged back into develop
to incorporate any hotfix changes
into develop
.
An example lifecycle diagram for hotfix branchs:
v1.2.0 v1.2.1 v1.2.2 v1.3.0 (tag)
B------------H1-----------H2 I (release)
^\ /| \ / \ ^
| \ / \ \ / \ |
| BA-----BB \ H1A--H1B \ | (hotfix/xyz)
| \ \ |
A----B-----C-----D----E------F------G----H----I--- (develop)
Documentation Branches
A docs
branch is focused on writing and improving the documentation for GEOS.
The use of the docs
branch name root applies to both sphinx documentation
and doxygen documentation.
The docs
branch follows the same naming conventions as described in the Feature Branches
section.
The html produced by a documentation branch should be proofread using sphinx/doxygen
prior to merging into develop
.
Keeping Your Branch Current
Over the course of a long development effort in a single feature
branch, a
developer may need to either merge develop
into their feature
branch, or rebase
their feature
branch on develop
.
We do not have a mandate on how you keep your branch current, but we do have
guidelines on the branch history when merging your branch into develop
.
Typically, merging develop
into your branch is the easiest approach, but will
lead to a complex relationship with develop
with multiple interactions… which
can lead to a confusing history.
Conversely, rebasing your branch onto develop
is more difficult, but will lead
to a linear history within the branch.
For a complex history, we will perform a squash merge into develop
, thereby
the work from the branch will appear as a single commit in develop
.
For clean branch histories where the individual commits are meaningful and should
be preserved, we have the option to perform a merge commit in with the PR is merged
into develop
, with the addition of a merge commit, thus maintaining the commit history.
Branching off of a Branch
During the development processes, sometimes it is appropriate to create a branch
off of a branch.
For instance, if there is a large collaborative development effort on the branch
feature/theMatrix
, and a developer would like to add a self-contained and easily
reviewable contribution to that effort, he/she should create a branch as follows:
git checkout feature/theMatrix
git checkout -b feature/smith/dodgeBullets
git push -u origin feature/smith/dodgeBullets
If feature/smith/dodgeBullets
is intended to be merged into feature/theMatrix
,
and the commit history of feature/theMatrix
is not changed via git rebase
, then
the process of merging the changes back into feature/theMatrix
is fairly standard.
However, if feature/theMatrix
is merged into develop
via a squash merge
,
and then smith
would like to merge feature/smith/dodgeBullets
into develop
,
there is a substantial problem due to the diverged history of the branches.
Specifically, feature/smith/dodgeBullets
branched off a commit in feature/theMatrix
that does not exist in develop
(because it was squash-merged).
For simplicity, let us assume that the commit hash that feature/smith/dodgeBullets
originated from is CC
, and that there were commits CA, CB, CC, CD
in feature/theMatrix
.
When feature/theMatrix
was squash-merged, all of the changes appear in develop
as commit G
.
To further complicate the situation, perhaps a complex PR was merged after G
, resulting
in E
on develop.
The situation is illustrated by:
A----B----C----D----E----F----G----E (develop)
\ /
CA---CB---CC---CD (feature/theMatrix)
\
CCA--CCB--CCC (feature/smith/dodgeBullets)
In order to successfully merge feature/smith/dodgeBullets
into develop
, all
commits present in feature/smith/dodgeBullets
after CC
must be included, while discarding
CA, CB
, which exist in feature/smith/dodgeBullets
as part of its history, but not
in develop
.
One “solution” is to perform a git rebase --onto
of feature/smith/dodgeBullets
onto
develop
.
Specifically, we would like to rebase CCA, CCB, CCC
onto G, and proceed with our
development of feature/smith/dodgeBullets
.
This would look like:
git checkout develop
git pull
git checkout feature/smith/dodgeBullets
git rebase -onto G CC
As should be apparent, we have specified the starting point as G
, and the point
at which we replay the commits in feature/smith/dodgeBullets
as all commits
AFTER CC
.
The result is:
A----B----C----D----E----F----G----E (develop)
\
CCA'--CCB'--CCC' (feature/smith/dodgeBullets)
Now you may proceed with standard methods for keeping feature/smith/dodgeBullets
current with develop
.
Submitting a Pull Request
Once you have created your branch and pushed changes to Github, you can create a Pull Request on Github. The PR creates a central place to review and discuss the ongoing work on the branch. Creating a pull request early in the development process is preferred as it allows for developers to collaborate on the branch more readily.
Note
When initially creating a pull request (PR) on GitHub, always create it as a draft PR while work is ongoing and the PR is not ready for testing, review, and merge consideration.
When you create the initial draft PR, please ensure that you apply appropriate labels. Applying labels allows other developers to more quickly filter the live PRs and access those that are relevant to them. Always add the new label upon PR creation, as well as to the appropriate type, priority, and effort labels. In addition, please also add any appropriate flags.
Note
If your branch and PR will resolve any open issues, be sure to link them to the PR to ensure they are appropriately resolved once the PR is merged. In order to link the issue to the PR for automatic resolution, you must use one of the keywords followed by the issue number (e.g. resolves #1020) in either the main description of the PR, or a commit message. Entries in PR comments that are not the main description or a commit message will be ignored, and the issue will not be automatically closed. A complete list of keywords are:
close
closes
closed
fix
fixes
fixed
resolve
resolves
resolved
For more details, see the Github Documentation.
Once you are satisfied with your work on the branch, you may promote the PR out of draft status, which will allow our integrated testing suite to execute on the PR branch to ensure all tests are passing prior to merging.
Note
The title of a PR has to follow the conventional commit specification. The allowed prefixes are:
feat: A new feature
fix: A bug fix,
docs: Documentation only changes,
style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc),
refactor: A code change that neither fixes a bug nor adds a feature,
perf: A code change that improves performance,
test: Adding missing tests or correcting existing tests,
build: Changes that affect the build system or external dependencies (example scopes: cmake),
ci: Changes to our CI configuration files and scripts (example scopes: github),
chore: Other changes that don’t modify src or test files,
revert: Reverts a previous commit,
Once the tests are passing – or in some cases immediately – add the flag: ready for review label to the PR, and be sure to tag any relevant developers to review the PR. The PR must be approved by reviewers in order to be merged.
Note that whenever a pull request is merged into develop
, commits are either
squashed
, or preserved depending on the cleanliness of the history.
Keeping Submodules Current
Whenever you switch between branches locally, pull changes from origin
and/or
merge
from the relevant branches, it is important to update the submodules to
move the head
to the proper commit
.
git submodule update --recursive
You may also wish to modify your git pull behavior to update your submodules recursively for you in one command, though you forfeit some control granularity to do so. The method for accomplishing this varies between git versions, but as of git 2.15 you should be able to globally configure git to accomplish this via:
git config --global submodule.recurse true
In some cases, code changes will require to rebaseline the Integrated Tests
.
If that is the case, you will need to modify the integrated tests submodule
.
Instructions on how to modify a submodule are presented in the following section.
Working on the Submodules
Sometimes it may be necessary to modify one of the submodules. In order to do so, you need to create a pull request on the submodule repository. The following steps can be followed in order to do so.
Move to the folder of the submodule
that you intend to modify.
cd submodule-folder
Currently the submodule
is in detached head mode, so you first need to move
to the main branch (either develop
or master
) on the
submodule repository, pull the latest changes, and then create a new branch.
git checkout <main-branch>
git pull
git checkout -b <branch-name>
You can perform some work on this branch, add and commit the changes and then push
the newly created branch to the submodule repository
on which you can eventually
create a pull request using the same process discussed above in Submitting a Pull Request.
git push --set-upstream origin <branch-name>
Resolving Submodule Changes in Primary Branch PRs
When you conduct work on a submodule during work on a primary GEOS branch with an open PR, the merging procedure requires that the submodule referenced by the GEOS PR branch be consistent with the submodule in the main branch of the project. This is checked and enforced via our CI.
Thus, in order to merge a PR that includes modifications to submodules, the various PRs for each repository should be staged and finalized, to the point they are all ready to be merged, with higher-level PRs in the merge hierarchy having the correct submodule references for the current main branch for their repository.
Starting from the bottom of the submodule hierarchy, the PRs are resolved, after which the higher-level PRs with reference to a resolved PR must update their submodule references to point to the new main branch of the submodule with the just-resolved PR merged. After any required automated tests pass, the higher-level PRs can then be merged.
The name of the main branch of each submodule is presented in the table below.
Submodule |
Main branch |
---|---|
blt |
develop |
LvArray |
develop |
integratedTests |
develop |
hdf5_interface |
master |
PVTPackage |
master |