Justification

Currently pull requests are managed on mailing lists etc and while this is fine it doesn't fit with the disconnected/distributed development model which Git promotes. We are looking to provide a mechanism to manage pull requests, allowing the core discussion to continue in whatever medium the project prefers but storing the salient points into Git, allowing for offline activity.

Precis

The idea of git pull-request is to provide an in-git mechanism to record the conversation between a patch author and a core developer while looking at a patch provided for merging. The conversation might include submitting particular commits for merging, or providing feedback on those commits. It also might involve arbitrary information passing in either direction.

Other implementations

Github and Gitorious both have pull-requests built into them. Both use a bit of the Git ref namespace. Github seems to use refs/pull/<nnn>/{head,merge} where Gitorious uses refs/merge-requests/<nnn>. Both these implementations are only using the refs to indicate the actual commit-line to be merged. Neither of them seem to store any metadata about the pull-request in Git. Thus, to manipulate pull requests (beyond test-merging them) you need access to the Github or Gitorious server.

Gitolite carries a contrib adc called hub which implements pull requests. You must be connected to the server in order to use the hub tool and while the hub means you don't have to fetch the implementations of pull-requests local, it still doesn't store the data in the Git repository itself.

Implementation details

Each pull-request consists of two important parts. The first is a line of commits which are being considered for merging. The second is a line of discussion about the merge. Each of those can be represented as a ref. The commit itself could be in refs/heads/ and the meta-information under refs/pull-requests/heads/.

Using the refs/pull-requests/heads/ prefix for access control

Since projects tend to use git servers (such as Gitano) to perform access control, we want git pull-request to be able to satisfy those kinds of access controls. As such, we will support the ref-to-be-merged being stored under refs/pull-requests/heads/ alongside the meta ref.

Naming refs for pull requests.

In order to increase the efficiency of pull requests while still allowing all of the history to be stored if desired, pull requests will be also use an additional refs namespace, namely refs/pull-requests/archived/ which will only contain pull requests considered to be archived. By default git pull-request will not interact with these refs (except to archive finished pull requests on demand).

Pull requests already present in remotes.

In order to work effectively with git remotes (and thus work with others) the git pull-request system places remote requests under refs/pull-requests/remotes/<remotename>/heads/ and refs/pull-requests/remotes/<remotename>/archived/. The git pull-request script can automatically add appropriate fetch rules to remotes and/or control the fetching/pushing itself via git pull-request sync or similar.

Use-case / story

Alice has been working on a feature and is ready to submit a pull request

The work Alice has been doing is currently in her repository in her working branch. She's ready to submit it for pulling into the project's master branch which is where that project accepts submissions for the next release.

She runs git pull-request create alice/magical-unicorns and then feeds a precis into the editor which appears. This results in two refs being created: refs/pull-requests/heads/alice/magical-unicorns and refs/pull-requests/heads/alice/magical-unicorn__anchor the former of which contains the metadata about the request and the latter is an anchor for the commit being requested for pull.

She already has the project's remote setup as origin and has permissions to send pull requests directly using her username as a prefix (hence she used alice/ in naming her pull request). She simply runs git pull-request sync and thanks to the fact that her branch was already tracking origin/master the tool knows where to send the pull request which is does using git push and some appropriate refspecs.

Bob, owner of the project Alice sent the pull-request to, receives the request

Bob, being ready and willing to accept pull requests, has been notified about Alice's pull request. Perhaps this is via a mailing list thread or perhaps by some magic to do with the server he's using to host his project. Either way he runs git pull-request sync and gets notified of the new pull request.

To learn about the pull request, Bob runs git pull-request precis alice/magical-unicorns which prints to his terminal the content of the precis of the pull request.

Having decided that Alice's idea is good, he wants to review the code. First he thinks he should look at the commits in isolation so he runs git pull-request log alice/magical-unicorns and is presented with the log for Alice's work (Note, not the log of the pull-request itself, for that he'd have to run git pull-request request-log alice/magical-unicorns instead.)

Bob then runs git pull-request merge alice/magical/unicorns and is told that his currently checked out branch is not suitable for landing the request. Feeling sheepish he switches from a feature-branch he's working on to the master and re-runs the merge command. This time the merge is okay and he's left with his working tree having had the merge done and he can run git diff --cached to look at the diff and obviously he can build and test Alice's contribution. When he's finished he can either git commit the work if he likes it, or git reset --hard HEAD to remove the changes if he doesn't.

If Bob has committed the merge, providing it was merged to the branch which it was originally intended to be landed, git pull-request sync will notice and complete the pull request, automatically archiving it and pushing the info to the remote server. If he merged it into somewhere else, he has the option of saying git pull-request merged alice/magical-unicorns which causes the branch onto which the pull request was actually merged to be recorded ready for the next time he synchronises. He may also git pull-request archive alice/magical-unicorns if he does not wish to wait until the branch lands on the original target before it is archived.

If, on the other hand, Bob decided not to merge Alice's work, he may choose to comment on it instead. He might run git pull-request needs-work alice/magical-unicorns and enter his comments into the editor which appears. If he wants to attach extra stuff he might run git pull-request attach alice/magical-unicorns some/files... which will allow him to add content to the pull-request which Alice can retrieve later. Once he's satisfied he's said/attached all that he needs to, Bob runs git pull-request sync to ensure that the updated pull requests are sent to the server for Alice to see later.

Alice, author of the pull-request, gets notified that Bob updated it

Alice first runs git pull-request sync which updates her with Bob's notes. She runs git pull-request status alice/magical-unicorns and sees that Bob marked it as needs-work. She runs git pull-request request-log alice/magical-unicorns and notes that Bob has attached some files and made various comments. about stuff she did.

Bob had suggested another test case which he invented which matched Alice's specification but did not pass. She runs git pull-request get alice/magical-unicorns bob/test-case and integrates the test case into her branch, making the fixes necessary to ensure that it works.

She commits that work and then runs git pull-request resubmit alice/magical-unicorns followed by git pull-request sync to re-send the request to Bob.

Bob receives the updated pull-request notification

Bob runs git pull-request sync and then since he knows what he needs to look for, he runs git pull-request log alice/magical-unicorns -p and reads the extra commits Alice made since the last time he reviewed the branch.

Bob, deciding that the code and test cases all look good, then merges the code with git pull-request merge alice/magical-unicorns, runs one final set of tests and then runs git commit. Finally he runs git pull-request sync. The sync process notes that Alice's branch has been landed, updates it to indicate how/where and moves it to the archive, before pushing the ref updates to Bob's server.

Alice gets a notification that her pull-request was updated.

Alice runs git pull-request sync and gets informed that alice/magical-unicorns was archived as merged. She, rather deservedly, has a celebratory drink.