Workflow

This section describes the typical SUNDIALS workflow for adding new features and patching released code based on the Gitflow workflow. For details on setting up Git and cloning the repository see the Git Setup section. A list of helpful commands for working with Git is available in the Git Cheat Sheet.

Gitflow

In the Gitflow workflow there are two persistent branches in the repository, master and develop. The master branch contains the official release history while develop is an integration branch for new features. Work is not done directly on master or develop, rather changes to either branch are merged in through pull requests from short-lived branches that engage a single feature or issue. These working branches generally fall into two groups:

  • Feature branches for developing new features for future releases (typically created off of develop).

  • Maintenance branches for patching the current production release (typically created off of master).

New feature or maintenance branches are created and worked on until they are ready to be merged into master or develop. To merge the code changes into the desired branch a pull request is created and the code changes are reviewed by other team members. Once the pull request is approved, the changes will be merged and the working branch can be deleted. See the Example Workflow sections for an example of a typical workflow.

Naming Branches

To keep track of what work is in progress on different branches it is helpful to use short, descriptive branch names. When creating a new feature branch, use the feature/ label followed by a name for the feature e.g., feature/HypreVector for adding for a hypre vector. For maintenance branches, the branch label is usually bugfix/ or maintenance/ followed by the corresponding JIRA ticket name e.g., bugfix/SUNDIALS-123 or a name that describes the issue being addressed e.g., maintenance/documentation-updates.

Example Workflow

In the following example workflow PARENT refers the branch from which the current working branch was created i.e., the develop branch for feature branches and the master for maintenance branches.

  1. To start working, checkout an existing branch or create a new one.

    1. To work on an existing branch:

      1. Checkout the desired branch:

        $ git checkout <branch-name>
        
      2. Make sure the branch is up to date:

        $ git pull
        
    2. To create a new branch to work on:

      1. Checkout the desired PARENT branch and make sure it’s up to date:

        $ git checkout PARENT
        $ git pull
        
      2. Create a new branch off of the PARENT branch:

        $ git checkout -b <branch-name> PARENT
        
      3. Push the new branch to the remote repo:

        $ git push -u origin <branch-name>
        

    NOTE: When checking out a branch, any local changed must be committed (or stashed) prior to switching branches.

  2. Modify files with your editor of choice:

    $ emacs <some-path/file-name>
    
  3. Stage the files you want to commit with:

    $ git add <some-path/file-name>
    
  4. Commit changes locally with either of the following commands depending on the detail needed in the commit message. See Commit Messages for guidelines when writing longer commit messages.

    1. For short commit messages:

      $ git commit -m "Short Description of the Commit"
      

    — OR —

    1. For longer commit messages:

      $ git commit
      

      This opens the default system editor or the editor set in .gitconfig, see Git Configuration for more information.

  5. Repeat the above modify, stage, and commit steps as needed to complete the work.

  6. During the development cycle it is a good practice to periodically push local commits to the remote repo. To push your locally commited changes use:

    $ git push
    

    If changes exist on the remote copy of the branch that are not in your local version, Git will not allow you to push. You must first pull in the remote changes as described below and then push your local changes.

  7. If you are collaborating with other developers on a feature you may need to update your local copy of a branch with changes from the remote version. To pull in remote changes use:

    $ git pull
    

    This will attempt to merge any remote commits into your local branch. If conflicts arise, Git will tell you. Follow the instructions in Resolving Conflicts to manually finish the merge. More experienced Git users may wish to use the --rebase option with git pull. See Rebasing for more information.

    NOTE: Locally tracked changes must be committed (or stashed) prior to pulling remote changes.

  8. As changes are merged into the PARENT branch, you may need to incorporate those changes into your working branch. To pull in changes from the remote PARENT branch use:

    $ git pull origin PARENT
    

    This will attempt to merge any changes on the remote PARENT branch into your local branch. If conflicts arise, Git will tell you. Follow the instructions in Resolving Conflicts to manually finish the merge. More experienced Git users may wish to use the --rebase option with git pull. See Rebasing for more information.

    NOTE: Locally tracked changes must be committed (or stashed) prior to pulling remote changes.

  9. Once the development work is complete make sure all changes have been pushed to the remote branch and open a pull request (PR) to start a code review for integrating the changes into the PARENT branch. See Pull Requests for more details on the opening a PR and the review process.

Commit Messages

The desired format for longer commit messages (more than a single line) is a short descriptive title followed by a blank line, and then a detailed commit message. For example, a commit making several changes to the ARKode initialization function might have the following message:

Retain history, remove LS/NLS init flag, skip init on reset

* move initializations inside FIRST_INIT
* retain error history on reset
* clear error/step history in SetInitStep
* skip stepper init checks on reset
* remove updates to ark LS and NLS init functions
* remove prototypes for old reinit utility function
* update docs

Resolving Conflicts

When updating the local copy of a branch with changes from the remote version or the PARENT branch merge conflicts may arise. In this case the conflicts can be resolved using either of the following approaches.

Manually resolve the conflicts in an editor:

  1. View the status of the branch for more info on the files with conflicts:

    $ git status
    
  2. Use your editor of choice to resolve the conflicts

  3. Add the resolved files:

    $ git add <path/file-name>
    
  4. Repeat the above steps until all conflicts are resolved

  5. If conducting a merge, commit the merge changes with

    $ git commit
    

    or if rebasing, continue the rebase with

    $ git rebase --continue
    
  6. If desired, push the updated local brach to the remote repo with

    $ git push
    

Alternatively, if you have setup a merge tool in your .gitconfig file (see Git Configuration for more details), then use resolve the conflicts with the merge tool:

  1. Start the mergetool

    $ git mergetool
    

    Git will open each conflicted file in the merge tool one at a time. Resolve the conflicts, save the merged file, and close the merge tool. Git will then open the next conflicted file. As files are resolved and saved they will be automatically added to the merge/rebase commit.

  2. When all conflicts are resolved, either commit the changes to the local branch if merging with

    $ git commit
    

    or if rebasing, continue the rebase with

    $ git rebase --continue
    
  3. If desired, push the updated local brach to the remote repo with

    $ git push
    

Rebasing

Rebasing is an alternative to merging that replays commits one at a time on top of the HEAD of another branch (e.g., the remote copy of a local branch or the branch’s parent). This rewrites the commit history by reapplying old changes in a new commit to keep the history linear and avoid a merge commit. Rewriting history is potentially dangerous and should be done with caution.

As mentioned above when pulling changes the --rebase option can be used to perform a rebase rather than a merge e.g.,

$ git pull --rebase

If conflicts arise during the rebase (Git will tell you), follow the steps in Resolving Conflicts to resolve them. If you choose to continue working locally and later run git pull --rebase again, you will likely have to re-resolve conflicts that occurred in the previous rebase. In this case git rerere can be used to have Git remember how conflicts were resolved previously.

Generally, rebasing changes on the PARENT branch e.g., when running git pull --rebase origin PARENT is not recommended as all of the commits (local and remote) on the working branch will be replayed on the PARENT branch. As such this will rewrite commits that have been pushed to the remote repo and will therefore change the commit history that other developers have pulled and are working on.