The following page is a slightly modified version of the ModeShape workflow.

The Fedora project uses Git, GitHub, and pull-requests for our development. Basically, this process is as follows:

  1.  Setup your GitHub account, fork our GitHub repository, and create a local git repository - This is done just once!
  2. Work an issue

Why do we like this approach?

This workflow has worked really well for us, for a couple of reasons:

  1. GitHub accounts are free, and you use your account for all projects you work on.
  2. GitHub pull-requests are essentially changes to Fedora code that committers/contributors are requesting be merged. GitHub makes it very easy for everyone to see/discuss/review proposed changes. If need be, you can alter your pull-request. If all is well, we will merge your changes into the codebase.
  3. People can work independently without a lot of coordination.
  4. You can collaborate with other developers using your public fork.
  5. Git makes a distinction between the author (you) and committer (a few Fedora committers). So you are recorded as the author of the changes.

How about good ol' patches? We still accept them, so if you prefer using the patch approach you can are welcome to create and submit patches.

Prerequisites

  1. Git
  2. Maven3
  3. Java8
  4. Sign CLA

Setup

There are a couple of steps to set things up the first time:

Step 1: Create a free GitHub account if you don't already have one. Be sure to set up your account with a SSH key pair and your email address(es) so Git can identify which commits are yours.
Step 2: Go to the Fedora repository on GitHub and click on the "Fork" button
Step 3: Clone the Fedora repository. At a command line, go to a directory where you want the new local repository, and issue the following:

$ git clone https://github.com/fcrepo4/fcrepo4.git

When this finishes you will have a local clone of the Fedora code base, complete with a remote named 'origin' that points back to the main Fedora Github repository.

Step 4: Tell your local clone about your fork of the repository on GitHub:

$ cd fcrepo4
$ git remote add <you> https://github.com/<you>/fcrepo4.git

Now we've set up a local Git repository, we can talk about the steps you'll do much more often.

Pulling Upstream Changes

Start by ensuring that you are on the 'master' branch and that you have no local changes:

$ git checkout master
$ git status

The last command should report something like:

# On branch master
nothing to commit (working directory clean)

Now, we need to pull any changes made to the main repository due to new features or bug fixes.

$ git pull

Now that your local Git repository has the latest, go ahead and push all the new commits to your fork:

$ git push <you> master

This is an optional step. The "master" branch on your fork is not really used at all, but you can keep it up-to-date with the upstream repository if you want.

Make Changes

All changes should be made on topic branches, typically named according to the JIRA issue. (Recommended naming convention "fcrepo-xxxx".) There is nothing special about a "topic" branch -- it is just a normal Git branch that you create and use for a specific topic (i.e., JIRA issue).

NOTE: Pull-requests that use the 'master' branch will not be accepted, even in your fork repository. There are too many things that can go wrong. Firstly, doing so will make it difficult to work on more than one (independent) set of changes at a time; working on 'master' will make your second set of changes dependent upon the first set of changes. Secondly, GitHub pull-requests are tied to branches, so GitHub will want to include all your commits into the same pull-request. Thirdly (and perhaps most importantly), if your commits are not approved, your 'master' branch history will have commits that don't actually appear in the official 'master' branch, and this could be problematic in the future. The 'master' branch in your fork should really be just the local branch that represents the official repository's 'master' branch - use it to pull changes from origin and merge/rebase onto your topic branches.

To create a topic branch, start on a branch you want to base from (which is often 'master'). The following command creates a new branch named "fcrepo-1234" (based off of 'master') and then checks out that branch:

$ git checkout -b fcrepo-1234 master

Work directly in the new "fcrepo-1234" branch. This is where you make your changes and run your new/modified unit tests. When you are happy, stage your changes with:

$ git add .

Do a complete integration build to make sure your new tests pass and that your changes did not cause a regression:

$ mvn clean install

If you need to make more changes, be sure to stage them and re-build.

Committing

Once everything builds, you can then commit your changes to this branch. There are various ways to commit, but this form will commit those changes you've staged and launches the editor where you can type out your commit message:

$ git commit

Be sure to use an appropriate comment. The first line should offer a brief description of the change (less than 50 characters), followed by an empty line, followed by a more detailed description on one or more lines (each line not to exceed 72 characters), followed by an empty line, followed by "Resolves: <ticket URL>"

Address invisible resources during transactions

- Disable Last-Modified and Etag headers during transactions

Resolves: https://jira.duraspace.org/browse/FCREPO-1234

If you think it makes sense to commit multiple times on your topic branch, then feel free to do so. Having multiple commits on a topic branch is perfectly fine for large changes. However, if your topic branch only contains a small number of changes (e.g., fixing a bug in one class and then adding or changing a test case), then it is preferred that they all be made in a single commit. 

Note: After a pull-request has been submitted (see below), subsequent commits (based on response to code review comments) should be pushed to the same development branch so that they will automatically be added to the pull-request. Do not squash or amend subsequent commits into your original pull-request commits because it makes finding the deltas much more difficult for the code reviewer.

Rebasing

If you have been working on this branch for a while, other changes may have been merged (from other pull-requests) into the origin repository. Often times this is okay. However, sometimes your local change will be affected by recent merges. It is best to make sure that you update your local clone before you create your pull-request.

To do this, switch to the "master" branch, have Git obtain all recent commits, and then update your branch:

$ git checkout master          # switches to the 'master' branch
$ git pull origin master       # fetches all 'origin' changes and merges
                               # 'origin/master' onto your 'master' branch
$ git checkout fcrepo-1234     # switches to your topic branch
$ git rebase master            # reapplies your changes on top of the latest
                               # in master (i.e., the latest from master will
                               # be the new base for your changes)

At this point, your "fcrepo-1234" branch has been updated (rebased), and you can proceed.

NOTE: Do not ever merge these topic branches onto other official branches, even on your fork repository. If you do that, your "master" branch (or any other official branch) will no longer reflect the official repository.

Push Changes

After you have committed changes locally (and pulled from upstream), you can commit your changes to your fork repository and generate a pull-request. Pushing the changes is easy:

$ git push <you> fcrepo-1234

This will push the commits on 'fcrepo-1234' up to your fork on GitHub.

Create Pull-Request

After pushing your changes into your GitHub fork, you have published your changes but have not really told the Fedora community about them. To do this, generate a pull-request on GitHub. If your commits are on a branch other than 'master', be sure to update the commit range (changing 'master' to the correct branch name). Then record this on the JIRA ticket, and use the URL to the pull-request and include a good comment that describes your changes.  Finish the JIRA ticket;  the ticket will then be ready to deliver, and the integration managers will be alerted that you have a pull request outstanding.

NOTE: If you use good commit descriptions and fill out a good pull-request description, then you can just paste the same description as the JIRA comment (without the summary line).

After the ticket is put "In Review", one of Fedora's integration managers will be notified of your new pull-request. The role of an integration manager is to review the incoming pull-requests and decide whether they should be accepted and on which branch(es) they should be merged. As such, only a few people have this responsibility.

An integration manager will review your request within a few days, and often much faster. They will comment on your pull-request via the discussion or line notes, or in the JIRA ticket. If they like what they see, they will merge your proposed changes into the correct branch(es), then "Close" your JIRA ticket. However, they may like to see additional changes, in which case they will describe in the pull-request discussion area (or in line notes, or JIRA ticket) what they would like you to change, and "Reject" the ticket, to indicate to the ticket owner that the ball is back in their court. If you disagree, just use the discussion area. Otherwise, go back to your local topic branch for this issue, make the requested changes, commit them locally, and push them to same branch in your fork repository (using the same commands as before). As long as you are on the same branch (not simply named the same, but actually the same branch), GitHub will automatically update the pull-request with your additional commit(s) and notify the integration managers again. Finish the JIRA ticket again. Once the changes are accepted, the integration managers will merge your commits into the upstream repository.

NOTE: After your initial commit, please do not perform "git push --force" on your branch. Doing so requires a complete re-review of the entire pull-request since it is not clear what all changes have been forced. After the code review is complete and ready to be merged into the master branch, you may indicate if you want certain commits to be squashed or not. Typically, if all of the commits are simply iterations on a single unit of work, your commits will be squashed by the integration manager before being merged into master.

Cleanup

There is actually nothing else you need to do. However, you may want to periodically clean up the topic branches that are no longer needed. (Note that if you want to make additional changes on a topic branch and have them go into the original pull-request, do not delete the topic branch in your local repository or your fork repository on GitHub.)

This command will delete a local topic branch:

$ git branch -D fcrepo-1234

This command deletes the remote branch in your fork repository on GitHub:

$ git push <you> :fcrepo-1234

At first blush, the syntax of this second command is a little strange. It is actually a form of the "git push <remote> <localBranch>:<remoteBranch>" command. If you do not specify the local branch, this basically means push nothing onto the remote branch, and Git removes the remote branch.

Configure for Performing Code Reviews

Since pull-requests are used when offering patches for code review, if you are performing a code review, this is one way that you can configuration Git to simplify the process.

  1. At the top-level of the pertinent project directory, change your ".git/config" file as follows (notice addition of line:5)

    ...
    [remote "origin"]
            url = https://github.com/fcrepo4/fcrepo4.git
            fetch = +refs/heads/*:refs/remotes/origin/*
            fetch = +refs/pull/*/head:refs/remotes/origin/pull/*
    ...


  2. Refresh your local cache

    git checkout master
    git pull


  3. Checkout the pull-request branch for review

    git checkout --track origin pull/xxx


  4. Enjoy the review