This is about how to split a GitHub pull request, following a real in-the-wild example.
So it happened that I once wanted to fix a bug (#832) on the shelljs
repository.
I forked the repository, cloned it and created a new branch called ln-directory-dest
. I fixed the bug, created a pull request, and implemented initial review feedback.
At this point, I had added the commits A, B, C, D, E and F (renamed here for simplicity). It made the repository look like this:
X -- [master]
`- A -- B -- C -- D -- E -- F -- [ln-directory-dest]
However, it happened that the project maintainer encouraged me to take on some similar issues (namely, #829). I jumped on and fixed that one — and pushed the commit (G
) to the ln-directory-dest
branch.
X -- [master]
`- A - B - C - D - E - F - G -- [ln-directory-dest]
I hoped this was okay, but the maintainer (understandibly) preferred having two separate pull requests for the fixes.
So, what was desired was this:
X -- [master]
`- A - B - C - D - E - F -- [ln-directory-dest]
`- G -- [ln-handle-dead-links]
So that left me wondering how to take G
from the ln-directory-dest
branch and put it onto ln-handle-dead-links
.
After reading some articles (most about a similar git constellation, but not the same), I sucessfully trial-and-error'ed my way to success.
The steps are the following:
-
(Being on the
ln-directory-dest
branch,) create the new branchln-handle-dead-links
(but not checking it out):git branch ln-handle-dead-links
Result:
X -- [master] `- A - B - C - D - E - F - G -- [ln-directory-dest], [ln-handle-dead-links]
-
Set the
HEAD
of branchln-directory-dest
back by one commit (toF
).git reset --hard HEAD~1
Result:
X -- [master] `- A - B - C - D - E - F -- [ln-directory-dest] `- G -- [ln-handle-dead-links]
-
Rebase all commits that happened between branch
ln-directory-dest
and branchln-handle-dead-links
(which is only commitG
) onto master.git rebase --onto master ln-directory-dest ln-handle-dead-links
Result:
X -- [master] `- A - B - C - D - E - F -- [ln-directory-dest] `- G -- [ln-handle-dead-links]
And we're done!
In my scenario where commits weren't in a clear order, using
git rebase -i
turned out to be easier.Scenario: I've got the following commits on master such that I want
A -- C -- E
on one branch andB -- D
on another.git checkout -b ace-branch
git rebase -i HEAD~5
because we want to modify the last 5 commitsAn editor will pop up asking you configure how you want the last commits to survive:
Replace
pick
bydrop
in the lines for commits B and D. (If VIM is used, press insert, then do replacement.)Close the editor. (If VIM is used, press escape, then
:wq
and enter.)Now the current branch, which is
ace-branch
, will only contain commits A, C and E.Repeat the same steps in order to create a
bd-branch
. Start bygit checkout master
,git checkout -b bd-branch
.Note that we need to check out
master
first since otherwisebd-branch
would start with the history oface-branch
, which we just modified to no longer contain commits B and D.After you have done all steps, it should look as follows:
Finally, you can also just
drop
all commits on master bygit checkout master && git reset --hard HEAD~5
. Then it looks like as if you made followed very clean approach from the very beginning 😄