All contributions to this project will be released to the public domain. By submitting a pull request or filing a bug, issue, or feature request, you are agreeing to comply with this waiver of copyright interest. Details can be found in our TERMS and LICENSE.
There are two primary ways to help:
- Using the issue tracker, and
- Changing the code-base.
Use the issue tracker to suggest feature requests, report bugs, and ask questions. This is also a great way to connect with the developers of the project as well as others who are interested in this solution.
Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in the issue that you will take on that effort, then follow the Changing the code-base guidance below.
Note that this document only discusses aspects of Git usage that should be needed for day-to-day development and contributions. For a more detailed overview of ngen's use of Git, see the GIT_USAGE doc.
To work with the repo and contribute changes, the basic process is as follows:
- Create your own fork in Github
- Clone the repo locally (conventionally from your fork) and setup your repo on your local development machine
- Make sure to keep your fork and your local clone(s) up to date with the official OWP ngen repo, ensuring histories remain consistent by performing rebasing
- Create feature/fix branches from
master
when you want to contribute - Write changes you want to contribute, commit to your local feature/fix branch, and push these commits to a branch in your personal Github fork
- Submit pull requests to the official OWP repo's
master
branch from a feature/fix branch your fork when the latter branch has a collection of changes ready to be incorporated
In order to be able to contribute code changes, you will first need to create a Github fork of the official OWP repo.
Next, set up your authentication mechanism with Github for your command line (or IDE). You can either create an SSH key pair and add the public key to your Github account, or you can set up a Personal Access Token if you plan to clone the repo locally via HTTPS.
After that, clone a local development repo from your fork, using a command similar to one of the following:
# SSH-based clone command. Change URL to match your fork as appropriate
git clone [email protected]:your_user/ngen.git
# HTTPS-based clone command. Change URL to match your fork as appropriate
git clone https://github.com/your_user/ngen.git
You can now change directories into the local repo, which will have the default branch - master
for this repository - checked out.
# Move into the repo directory "ngen"
cd ngen
# You can verify the branch by examining the output of ...
git status
Important
Git will add a Git remote named origin
to the clone's Git configuration that points to the cloned-from repo. Because of this, the recommended convention is to clone your local repo(s) from your personal fork, thus making origin
point to your fork. This is assumed to be the case in other parts of the documentation.
Next, add the OWP ngen repo as a second Git remote for the local clone. Doing the addition will look something like:
# Add the remote, here using the HTTPS URL (the SSH URL would be fine also)
git remote add upstream https://github.com/NOAA-OWP/ngen.git
# Verify
git remote -v
Important
The standard convention used in this doc and elsewhere is to name the Git remote for the official Github OWP repository upstream
. In regular text, that Git remote will always be denoted like this.
Git also has the more general concept of an "upstream branch" associated with "tracking branches", as discussed on the Git Remote Branches documentation. We will use "upstream branch" when discussing these.
Now set up the user and email in the local repo's configuration.
git config user.name "John Doe"
git config user.email "[email protected]"
Alternatively, one could also set these in the machine's global Git config (or rely upon the global settings if already configured).
git config --global user.name "John Doe"
git config --global user.email "[email protected]"
While optional, Git hooks are a useful feature for helping maintain code quality in your local development repo. See the repo's Git Usage document for more discussion on these.
When you want to contribute a fix or new feature, start by creating and checking out a local branch (e.g., new_branch
) to contain your work. This should be based on master
(you may need to sync remote changes first):
# Create the new branch "new_branch" based on "master"
git branch new_branch master
# Check out "new_branch" locally to work in it
git checkout new_branch
Go ahead and push this new branch to your fork so it exists there as well. Use -u
so that the local branch adds a tracking reference to the branch in your fork:
# Assuming the convention of your fork's remote being `origin`
git push -u origin new_branch
Important
While -u
isn't strictly required, including it causes origin/new_branch
to be set as the "upstream branch" for the local new_branch
(with the latter being referred to as a "tracking branch"). Tracking branch relationships are described in the Tracking Branches section of Git's Remote Branches doc.
While it is totally optional, parts our documentation - especially example commands - may assume this tracking branch relationship has been set.
From there begin writing and committing your changes to the branch. While up to you, it is suggested that development work be committed frequently when changes are complete and meaningful. If work requires modifying more than one file in the source, it is recommended to commit the changes independently to help avoid too large of conflicts if/when they occur.
Especially if making more frequent, smaller commits as suggested above, it is a good practice to regularly push these smaller commits to your fork. If the -u
option was used when initially pushing the branch, it is simple to check if there are local, unpushed commits.
# The fetch is probably unnecesssary unless you work from multiple local repos
git fetch
# Assuming your branch of interest is still checked out:
git status
# And if there are some newer, local changes that haven't been push yet:
git push
Once a code contribution is finished, make sure all changes have been pushed to the branch in your fork. Then you can navigate to the OWP repo via Github's web interface and submit a PR to pull this branch into the OWP master
branch. Verify that master
is selected as the recipient branch. You will also need to make sure you are comparing across forks, choosing your appropriate fork and branch to pull from. Complete details on the process can be found in Github's documentation.
The following guidelines are recommended for pull requests. Following these increases the likelihood of a PR being reviewed quickly and minimizes the amount of changes likely to be needed before approval:
- Make sure the PR has an informative and human-readable title
- Limit the scope of changes within a PR to a single goal (no scope creep)
- Ensure the resulting code can be automatically rebased into
master
without conflicts - Make sure project coding standards, if/when defined, are followed
- Ensure resulting code passes all existing automated tests
- Ensure any changes or additions to functionality are tested
- Document new functions with a description, list of inputs, and expected output
- Flag any placeholder code is flagged and note future TODO items in comments
- Update repo-level documentation appropriately
- Select one or more appropriate reviewers when creating the PR
Once the PR is submitted, it will be reviewed by one or more other repo contributors. Often conversations will be had within the Github PR if reviewers have questions or request revisions be made to the proposed changes. If revisions are requested, you will need to make those in your locally copy of the feature/fix branch, and then re-push that branch (and the updates) to your personal fork. Then, use the PR page in Github to re-request review.
- A Rebase Strategy
- Getting Remote Changes
- Rebasing Development Branches
- Fixing Diverging Development Branches
Development for this repo uses a rebase strategy for integrating code changes, rather than a merge strategy. More information on rebasing is available here, but the main takeaway is that it is important all changes are integrated into branches using this approach. Deviation from this will likely cause a bit of mess with branch commit histories, which could force rejection of otherwise-good PRs.
When it is time to check for or apply updates from the official OWP repo to a personal fork and/or a local repo, check out the master
branch locally and do fetch-and-rebase, which can be done with pull
and the --rebase
option:
# Checkout local master branch
git checkout master
# Fetch and rebase changes
git pull --rebase upstream master
Then, make sure these get pushed to your personal fork. Assuming the above-described setup where the local repo was cloned from the fork, and assuming the local master
branch is currently checked out, the command for that is just:
# Note the assumptions mentioned above that are required for this syntax
git push
Alternatively, you can use the more explicit form:
git push <fork_remote> <local_branch>:<remote_branch>
The previous example command is effectively equivalent to running:
# Cloning a repo from a fork created a remote for the fork named "origin"; see above assumptions
git push origin master:master
You also can omit <local_branch>:
(including the colon) and supply just the remote branch name if the appropriate local branch is still checked out.
Note that the above steps to get remote changes from the official OWP repo can be applied to the production
branch also (just swap production
in place of master
). production
should not be used as the basis for feature/fix branches, but there are other reasons why one might want the latest production
locally or in a personal fork.
When the steps in Getting Remote Changes do bring in new commits that update master
, it is usually a good idea (and often necessary) to rebase any local feature/fix branches were previously created. E.g.,
# If using a development branch named 'faster_dataset_writes'
git checkout faster_dataset_writes
git rebase master
See documentation on the "git rebase" command for more details.
It is possible to have more control over rebasing by doing an interactive rebase. E.g.:
git rebase -i master
This will open up a text editor allowing for reordering, squashing, dropping, etc., development branch commits prior to rebasing them onto the new base commit from master
. See the Interactive Mode section on the rebase command for more details.
If a local feature/fix branch is already pushed to a remote fork, and then later rebasing the local branch is necessary, doing so will cause the histories to diverge. For simple cases, the fix is to just force-push the rebased local branch.
# To force-push to fix a divergent branch
git push -f origin feature_branch
However, extra care is needed if multiple developers may be using the branch in the fork (e.g., a developer is collaborating with someone else on a large set of changes for some new feature). The particular considerations and best ways to go about things in such cases are outside the scope of this document. Consult Git's documentation and Google, or contact another contributor for advice.