Splitting pull request

How to split a large pull request into several smaller ones.

Yesterday I have added several features to a fork of semantic-release-gitlab. I have opened a pull request (called "Merge Request" on GitLab) to the repo's author here. The pull request has 6 commits, since I was adding more code as I was debugging the problem. The author Hutson Betts asked me to split my pull request into 3 smaller focused ones.

1
2
3
4
@bahmutov would you mind breaking your merge request into three parts:
one for adding debug into the project, one for adding the debug mode,
and a third for the user-configurable preset?
I would like to go ahead and accept the debug addition.

This is a valid request. Let me show how to do this step by step.

I have my own local fork of the repo, and I have been adding my commits right to master branch. The one line Git log looks like this

1
2
3
4
5
6
7
8
9
$ git log --oneline --graph --all --decorate
* c646369 (HEAD -> master, origin/master, origin/HEAD) feat(config):
you can pass config in the package.json file
* 273053b chore(debug): use release-debug to observe gitlab release plugin
* 4e31d46 fix(doc): added note about SSH remote repo problem
* 0b3495c feat(debug): turn on debug config option using DEBUG=release variable
* 1643993 updated debugging comment in readme
* ebd0edd feat(debug): added debug module for extra messages when needed
* 50dc59a (tag: 2.2.3) docs(README): correct typo

The bottom commit 50dc59a tagged 2.2.3 is the last common commit before I started adding my own code in ebd0edd. The debug feature has been implemented in two commits

1
2
* 1643993 updated debugging comment in readme
* ebd0edd feat(debug): added debug module for extra messages when needed

Let us create a separate branch from the common commit 50dc59a and pick these two commits.

1
2
3
4
5
6
$ git checkout 50dc59a
HEAD is now at 50dc59a... docs(README): correct typo
$ git checkout -b debug-messages
Switched to a new branch 'debug-messages'
$ git cherry-pick ebd0edd
$ git cherry-pick 1643993

The cherry picked commits have brand new ids, they are no longer ebd0edd and 1643993, but d29e22c and ba4b5b4.

We now have branch debug-messages with just two commits related to debug messages. While we are here, we can tidy the code up a little. For example, I have changed the debug trigger to be the full semantic-release-gitlab module name instead of short but fuzzy release. This created new commit 17b67e1 chore(debug): using semantic-release-gitlab as debug log label.

It is a good practice to squash multiple commits into one before making a pull request. We have 3 commits we want to squash into one. Run the command git rebase -i HEAD~3 which opens your text editor. By default the three commits are shown as pick which means they will be kept separately. Edit the lines to have one pick and two squashes

1
2
3
4
5
pick d29e22c feat(debug): added debug module for extra messages when needed
s ba4b5b4 updated debugging comment in readme
s 17b67e1 chore(debug): using semantic-release-gitlab as debug log label

# Rebase 50dc59a..17b67e1 onto 50dc59a (3 command(s))

Save the file end exit. It will open a second editor session where you can edit the commit message for the newly created single commit. I just kept the message from the very first commit, saved and exited.

1
2
3
4
[detached HEAD 761215d] feat(debug): added debug module for extra messages when needed
Date: Wed Aug 17 17:22:07 2016 -0400
4 files changed, 23 insertions(+), 1 deletion(-)
Successfully rebased and updated refs/heads/debug-messages.

The branch debug-messages now has a single commit I can push to the remote server.

1
$ git push origin debug-messages

At GitLab.com create a new merge request and this time use the branch debug-messages

1
From bahmutov/semantic-release-gitlab:debug-messages into hutson/semantic-release-gitlab:master

You can see this request online.

I can repeat the process and create new cherry picked branches with the other two features.

Additional information

Bonus

To actually remove commits from the master branch see the instructions in this blog post. In a nut shell:

  • Reset local HEAD position to the last "good" commit git reset <id> --hard
  • Force push the master branch to the origin git push origin +master

Standard warnings apply :)