Skip to content

Instantly share code, notes, and snippets.

@loilo
Last active November 14, 2024 13:38
Show Gist options
  • Save loilo/930f141d9acf89e9e734ffa042acd750 to your computer and use it in GitHub Desktop.
Save loilo/930f141d9acf89e9e734ffa042acd750 to your computer and use it in GitHub Desktop.
Split a large pull request into two

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:

  1. (Being on the ln-directory-dest branch,) create the new branch ln-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]
    
  2. Set the HEAD of branch ln-directory-dest back by one commit (to F).

    git reset --hard HEAD~1

    Result:

    X -- [master]
     `- A - B - C - D - E - F -- [ln-directory-dest]
                            `- G -- [ln-handle-dead-links]
    
  3. Rebase all commits that happened between branch ln-directory-dest and branch ln-handle-dead-links (which is only commit G) 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!

@ashanz93
Copy link

ashanz93 commented Apr 3, 2020

Worked perfectly @loilo. This is what I desired to do

@areee
Copy link

areee commented Jul 10, 2020

Thanks for this hint, @ComFreek! It worked perfectly!

@itai-huddly
Copy link

Thanks for this guide, it's quite useful!

@jvortmann
Copy link

Alternatively switch (with -c to create a branch) can be used and it allows a starting-point as a param:

X - A -- B -- C -- D -- E [master]

git switch -c ace-branch X will result in (and move to the branch):

X - A -- B -- C -- D -- E [master]
 \
  `- [ace-branch] *

and then git cherry-pick A C E will cherry pick those commits in that order and apply to the branch:

X - A -- B -- C -- D -- E [master]
 \
  `- A -- C -- E [ace-branch] *

To create the other branch it is the same two commands and you can even change the order if needed:
git switch -c bd-branch X && git cherry-pick B D or
git switch -c db-branch X && git cherry-pick D B

@TheGreatRambler
Copy link

git cherry-pick worked nicely for me, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment