1. petsc
  2. PETSc
  3. petsc

Wiki

Clone wiki

petsc / developer-instructions-git

See also the quick reference.

Configuration and convenience

Safety

Run this once to avoid accidentally pushing more branches than intended:

$ git config --global push.default simple

(older versions of git require git config --global push.default tracking)

Prompt

To stay oriented when working with branches, we encourage configuring git-prompt. In the following, we will include the directory, branch name, and PETSC_ARCH in our prompt, e.g.

~/Src/petsc (master=) arch-complex
$ git checkout maint
 ~/Src/petsc (maint<) arch-complex

The < indicates that our copy of maint is behind the repository we are pulling from. To achieve this we have the following in our .profile (for bash)

source ~/bin/git-prompt.sh  (point this to the location of your git-prompt.sh)
export GIT_PS1_SHOWDIRTYSTATE=1
export GIT_PS1_SHOWUPSTREAM="auto"
export PS1='\w\[\e[1m\]\[\e[35m\]$(__git_ps1 " (%s)")\[\e[0m\] ${PETSC_ARCH}\n\$ '

Tab completion

To get tab-completion for git commands, first download and then source git-completion.bash.

Branching

Summary

We use a simplified version of the branching model described in gitworkflows(7), minus the pu (proposed updates) branch described there. All new features should start from master. Do not start from next! Each feature is developed in a separate feature branch, allowing the individual features to be merged and improved independently.

When a feature is ready for testing, it will be merged to next where it will be tested (in combination with other new features) in the nightly builds and by early users. Once it is considered stable, the topic branch will be merged to master. In this model, master should always be nearly as stable as a release.

Developing new features

Always start new features on a fresh branch ('topic branch') named after what you intend to develop. Always branch from master:

(master) $ git checkout -b yourname/purpose-of-branch
Switched to a new branch 'yourname/purpose-of-branch'
(yourname/purpose-of-branch) $

The naming convention for a topic branch is

 <yourname>/<affected-package>-[<affected-package>-...]-<short description>

For example, Matt's work on finite elements for hexahedra within dmplex is carried out in the topic branch knepley/dmplex-hexfem or knepley/dmplex-petscsection-hexfem. Don't use spaces or underscores, use lowercase letters only.

Now develop your feature, committing as you go. Write good commit messages. If you are familiar with git rebase, it can be used at this time to edit your local history, making its purpose as clear as possible for the reader. When your feature is ready for review and possible integration, run

(yourname/purpose-of-branch) $ git push --set-upstream origin yourname/purpose-of-branch

You can continue to work on this branch, and use git push to make your changes visible. Only push on your branches.

If you have long-running development of a feature, you will probably fall behind the master branch. If your branch has not been merged to another branch (e.g., next) yet, you can replay your changes on top of the latest master using

(yourname/purpose-of-branch) $ git rebase master

Checking out (Tracking) a Remote Branch

If you wish to work on a branch that is available on the remote (shown via git remote show origin), run

git checkout <branchname>

to create a local branch that will merge from the remote branch. If your local repository is not yet aware of the new branch at the remote repository, run git fetch and then repeat the checkout.

Merging

Every branch has a purpose. Merging into branch branch-A is a declaration that the purpose of branch-A is better served by including those commits that were in branch-B. This is achieved with the command

(branch-A) $ git merge branch-B

Topic branches do not normally contain merge commits, but it is acceptable to merge from master or from other topic branches if your topic depends on a feature or bug fix introduced there. When making such a merge, use the commit message to state the reason for the merge. Never merge next into your branch.

For further philosophy on merges, see

Integration branches

This section explains the workflow used by maintainers to create the integration branches. As with all branches, integration branches have a well-defined purpose:

  • next : latest changes for testing, may be unstable
  • master : stable platform for new development
  • maint : bug fixes against the latest release

Branch next

The purpose of next is to provide a testing ground for new features to stabilize. When a feature is ready for testing and public consumption, it is merged to next.

(next) $ git merge loginname/topic-purpose    # Maintainers ONLY!

After resolving possible conflicts and running tests, next can be pushed. The next branch is solely for testing. It is never merged into another branch and new development never starts on next.

If your work conflicts with something else being developed, you will find out it when your topic branch is merged into next. This does not imply that your topic branch needs to depend on the other branch. If the conflicts are merely incidental, you can just resolve them when committing your merge into next and relax with the knowledge that Git's rerere mechanism will remember the resolution so you won't need to resolve it manually when eventually merging your topic into master. If that other branch introduces a feature that you want to use (e.g., a new interface or a bug fix), merge that feature into your branch:

(my/topic) $ git merge their/feature-that-i-need

Branch master

The master branch provides a stable platform for new development and is the basis for releases. After loginname/topic-purpose has been tested in next and is deemed stable, it can be merged to master.

(master) $ git merge loginname/topic-purpose    # Maintainers ONLY!

After running local tests, master can be pushed. New releases will be tagged on master.

Branch maint

The maint branch provides bug-fix patches for the latest release. Bug fixes that are relevant to the release should be started here:

$ git checkout -b yourname/fix-component-name maint

As with new features, it will be tested in next and later merged to maint and master. Maintenance releases are tagged on maint.

Long running development

If you support a particular physics code, like PyLith, you will want to certify that a certain branch incorporates new features that it needs, as well as passes all PETSc tests and follows the latest development. This tracking branch can be called something like knepley/pylith. You develop new features in separate feature branches, and integrate into next. Then

(next) $ git pull  # get changes from upstream
(next) $ git merge knepley/new-feature-for-pylith

run tests with application, and

(next) $ git push origin next next:knepley/pylith

so that you push your local branch 'next' that you just tested with the application to both 'next' and 'knepley/pylith'.

Application users then follow 'knepley/pylith', which is just marking the state of 'next' the last time you tested it. Since it's always marking a point on 'next', it will fast-forward, so the user just clones PETSc, then

$ git checkout knepley/pylith

and from then on, they will get your the tested state with

(knepley/pylith) $ git pull

Racy integration

Two people occasionally attempt to merge at about the same time, in which someone will lose the race. It usually goes like this: you checkout 'next', pull to make sure you have everything from upstream (you didn't forget this, right?), merge 'my/topic-branch', test, and attempt to push, getting an error like:

To git@bitbucket.org:petsc/petsc
 ! [rejected]        next -> next (fetch first)
error: failed to push some refs to 'git@bitbucket.org:petsc/petsc'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Do NOT perform a non-fast-forward pull on an integration branch. (Doing so creates messy history that does not summarize nicely with git log --first-parent.) Instead, you have two choices. The cleanest is to gracefully lose the race and merge again. Recommended:

$ git reset --hard origin/next
$ git merge my/topic-branch
... build and test ...
$ git push

This produces clean history with no evidence that you encountered a race and had to try again. Junio explains in detail why this is preferable. If your merge had significant conflicts or if the testing you just did was especially onerous, you can switch hats and merge the result:

$ git reset --hard origin/next
$ git merge ORIG_HEAD
  # edit commit message to state which branch was actually merged
  # due to losing a race to the integration branch.
... build and test ...
$ git push

This keeps both merge commits (which is a record that there was a race, usually perceived as clutter) but git log --first-parent still produces an accurate and concise summary.

Integrating Pull Requests (for PETSc developers/integrators only)

When users make a pull request they may be from the users own repository, rather then the BitBucket.com/petsc/petsc repository. In order to test the pull request and merge them you must first get access to their branch from your machine. Run

 $ git fetch git@bitbucket.org:owner/repositoryname branchname:pr###/owner/branchinfo/<maint or master>

To get this information click on the origin of the pull request; a popup will appear with Owner, (repository)Name, and Branch(name). The new branch name above is appended with maint of the pull request is to update maint and master if the pull request is to update master.

Then push to origin so others may access

 $ git push -u origin pr###/owner/branchinfo/<maint or master>

 $ git checkout pr###/owner/branchinfo/<maint or master>

Make and test, etc.

$ git checkout next
$ git pull
$ git merge pr###/owner/branchinfo/<maint or master>
$ git push

Notes: Instead of git@ you can use https:// if the user has not given read access to the repository the fetch will fail and you will need to respond on the pull request page requesting the user provide read access.

The bash function below (put it in your .profile) creates a new branch based on a pull request and makes a copy of it in the petsc repository

 gitpullrequest () {
    read -p "Enter pull requestion number >" prnum
    read -p "Enter user bitbucket account: Owner >" userid
    read -p "Enter repository name (default is petsc): Name >" repo
    if [ "${repo}foo" = "foo" ]; then
    repo="petsc"
    fi
    read -p "Enter branch name: Branch >" branch
    read -p "Enter better branch name (default is branch name)>" branchname
    if [ "${branchname}foo" = "foo" ]; then
    branchname=${branch}
    fi
    read -p "Destination of pull request: maint or master >" des
    if [ "${des}foo" = "foo" ]; then
    des="master"
    fi

   echo git fetch git@bitbucket.org:${userid}/${repo} 
     ${branch}:pr${prnum}/${userid}/${branchname}/${des}
   git  fetch git@bitbucket.org:${userid}/${repo}   
   ${branch}:pr${prnum}/${userid}/${branchname}/${des}
   echo git push -u origin pr${prnum}/${userid}/${branchname}/${des}
   git  push -u origin pr${prnum}/${userid}/${branchname}/${des}
  return 0
}

If you wish the submitter to make changes to the branch you've created you should have them merge the pr###/owner/branchinfo/<maint or master> into their pull request branch, make additional updates to their pull request branch and then push their pull request branch. This will automatically trigger an update to the pull request web page. You then will need to merge the updated pull request branch into pr###/owner/branchinfo/<maint or master> and start the new test cycle by merging pr###/owner/branchinfo/<maint or master>. This pulling between the two branches in different repos continues until no additional changes to pr###/owner/branchinfo/<maint or master> are needed, it is clean in next and can be merged into maint or master, as appropriate.

Integrators group

This group has permissions to push to integration branches maint, master, next.

We recommend integrators to use the following git hook in .git/hooks/prepare-commit-msg - to avoid bad merges from next to master - or from next/master to maint

#!/bin/bash
if [ "$2" == "merge" ]; then
    br="$(git describe --contains --all HEAD)"
    case "$br" in
    maint)
        grep "PETSC_VERSION_RELEASE *1" $(git rev-parse --show-toplevel)/include/petscversion.h >/dev/null
        if [ "$?" != "0" ]; then
        echo "Attempting to merge master/next (or a branch off master/next) to maint! Aborting merge!"
        exit 1
        fi
        ;;
    master)
        grep "PETSC_VERSION_RELEASE *0" $(git rev-parse --show-toplevel)/include/petscversion.h >/dev/null
        if [ "$?" != "0" ]; then
        echo "Attempting to merge next (or a branch off next) to master! Aborting merge!"
        exit 1
        fi
        ;;
    next)
        grep "PETSC_VERSION_RELEASE *-2" $(git rev-parse --show-toplevel)/include/petscversion.h >/dev/null
        if [ "$?" != "0" ]; then
        echo "PETSC_VERSION_RELEASE not set in next?"
        exit 1
        fi
        ;;
    esac
fi

And disable fast forward merges by adding the following to .git/config

[merge]
    ff = no

Updated