The ModeShape project uses Git, GitHub, and pull-requests for our development. Basically, this process is as follows:
- Setup your GitHub account, fork our GitHub repository, and create a local git repository - This is done just once!
- Work an issue
Why do we like this approach?
This workflow has worked really well for us, for a couple of reasons:
- GitHub accounts are free, and you use your account for all projects you work on.
- GitHub pull-requests are essentially changes to our code that you are requesting we merge. GitHub makes it very easy for everyone to see/discuss/review your proposed changes. If need be, you can alter your pull-request. If all is well, we'll merge your changes into the codebase.
- People can work independently without a lot of coordination.
- You can collaborate with other developers using your public fork
- Git makes a distinction betweeen the author (you) and committer (a few of us). So you are recorded as the author of the changes, and
How about good ol' patches? We still accept them, so if you prefer using the patch approach you can follow our instructions for creating and submitting patches.
Note: If you are one of the few developers that has been told you have commit privilege to the official Git repository, you will follow the workflow on this page for normal development operations. But when reviewing and merging pull-requests you'll do this by following the workflow described in ModeShape Integration Managers.
Also, be sure to fill out a JBoss.org Contributor License Agreement for the ModeShape project, or else we won't be able to use your changes.
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 3: Clone your fork, using the private URL. At a command line, go to a directory where you want the new local repository, and issue the following:
$ git clone email@example.com:<you>/modeshape.git
This can take as long as a minute or two. But when it does finish you'll have a local clone of your fork, complete with a remote named 'origin' that points back to your fork on GitHub (not the original).
Step 4: Tell your local clone about the official upstream repository on GitHub:
$ cd modeshape $ git remote add upstream git://github.com/ModeShape/modeshape.git $ git fetch upstream
This uses the public URL for the upstream repository, which is read-only. This helps ensure that your changes only go into your fork repository.
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're on the 'master' branch and that you've got 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 official upstream repository due to new features or bug fixes. You can pull them into your fork two ways:
$ git pull upstream master
$ git fetch upstream $ git merge upstream/master
The first is more direct, but it only gets the changes for one branch ("master" in this case) and because the merge is not explicit it can be confusing for new Git users that the 'pull' actually results in a merge conflict (e.g., the files you've changed locally were also modified in the upstream). The latter uses an explicit merge and also fetches all branches (including any new branches that were created since you cloned your repository and/or added 'upstream' as a remote). You can list all branches with:
$ git branch -a
If you don't see a branch in 'remotes/upstream' that you know is in the official repository, run the "git fetch upstream" and "git merge upstream/<missingBranch>" form.
Any local changes you have will be merged, and any local commits already in the upstream will be handled as a fast-forward merge (leaving your branch at the same commit as the "upstream/master").
Now that your local Git repository has the latest, go ahead and push all the new commits to your fork:
$ git push origin 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.
All changes should be made on topic branches, typically named according to the JIRA issue. (We recommend naming them "mode-xxxx".) There's nothing special about a "topic" branch -- it's just a normal Git branch that you create and use for a specific topic (i.e., JIRA issue).
NOTE: We will not accept pull-requests that use the 'master' branch, 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 upstream 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 "mode-1234" (based off of 'master') and then checks out that branch:
$ git checkout -b mode-1234 master
Your working directly reflects the new "mode-1234" branch, and this is where you make your changes and run your new/modified unit tests. When you're happy, stage your changes with:
$ git add .
and do a complete integration build to make sure your new tests pass and that your changes didn't cause a regression:
$ mvn clean install
or, if you want to build the kits and run the integration tests, add the "integration" profile:
$ mvn clean install -Pintegration
NOTE: We didn't include the "-s settings.xml" argument on this or any other Maven commands shown on this page. We've assumed that you've modified your Maven settings. If you didn't, you will probably need to add this argument to all your Maven commands. If you get an error stating that some artifacts cannot be found, this is the reason.
If you need to make more changes, be sure to stage them and re-build.
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 list issue numbers and a summary sentence; additional paragraphs describe the commit in more detail. (See ModeShape Development Guidelines.)
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 we do prefer that they all be made in a single commit. You can create multiple commits and then squash them before pushing to your fork, but it is often easier to create the first commit as usual but then to amend that commit with subsequent changes:
$ git commit --amend
This will modify the previous commit to include the staged changes. Obviously, you should only amend your own commits on your topic branch - never amend a commit that on an official branch.
If you've been working on this branch for a while, we may have merged other changes (from other pull-requests) into the upstream repository. Often times this is okay, as we can deal with overlaps like this. However, sometimes your local change will be affected by recent merges. It's 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 upstream master # fetches all 'upstream' changes and merges # 'upstream/master' onto your 'master' branch $ git checkout mode-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 "mode-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. That's our job. If you do that, your "master" branch (or any other official branch) will no longer reflect the official repository.
After you've 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 origin mode-1234
This will push the commits on 'mode-1234' up to the 'origin' repository (which is your fork on GitHub).
After you've pushed your changes into your GitHub fork, the next step is to request the ModeShape community have a look at your proposed changes and potentially merge them. To do that, generate a pull-request on GitHub for your changes, using a very good description for the pull-request. (If you use good commit descripitons and fill out a good pull-request description, then you can just paste the same description as the JIRA comment.)
Since most of the changes on ModeShape are to be merged into the latest codebase (e.g., the "master" branch), creating a pull-request is actually quite straightforward. However, if you're proposing changes to an older branch, you should have created your topic branch off of that older branch. When you then create a pull-request with your topic branch, GitHub should know that the pull-request should be for that older ModeShape branch. But it doesn't hurt to make sure that when you create the pull-request that the branches listed at the top of the screen are correct.
When you've finished creating pull-request, please update the JIRA issue using the "Workflow -> Link Pull Request" action and the URL to the pull-request. Again, include a good comment that describes your changes.
Meanwhile, one of ModeShape'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 and 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'll comment on your pull-request via the discussion or line nodes. If they like what they see, they'll merge your proposed changes into the correct branch(es). However, they may like to see additional changes, in which case they'll describe in the pull-request discussion area (or in line notes) what they'd like you to change. 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're 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. Once they're acceptable, the integration managers will merge your commits into the upstream repository.
The aforementioned process adds your new commits to the pull-request. But sometimes, the integration managers will request just a few smaller changes, and making a separate commit for those small changes is less desirable. Instead, in this case we suggest that you make the changes and then amend your previous commit. This helps keep related changes in fewer commits, and makes it easier to apply the changes to other branches. Yes, amended commits actually do change history, so be sure to do this only with commits that appear only on a topic branch. We think it is perfectly acceptable (and sometimes preferable) to amend/change the commits on a pull request before it is merged onto an official branch (before this, a PR is really "proposed code"). The procedure is pretty straightforward. On your local branch (e.g., "mode-1234") that you used to push to your fork (e.g., "origin") and create the PR, make any additional changes to the code and then:
$ git commit --amend . $ git push -f origin mode-1234
GitHub will automatically update the pull-request, where it can be reviewed once again.
There's 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, don't 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 mode-1234
while this command deletes the remote branch in your fork repository on GitHub:
$ git push origin :mode-1234
At first blush, the syntax of this second command is a little strange. It's actually a form of the "git push <remote> <localBranch>:<remoteBranch>" command. If you don't specify the local branch, this basically means push nothing onto the remote branch, and Git removes the remote branch.