Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

How to avoid pushing past commits when making a pull request?

+6
−1

I had a PR that was accepted. Now I make another one, but it also push my past commits. I have created a new branch but it doesn't solve the problem. Why does this happen and how to prevent this?

History

0 comment threads

1 answer

+9
−0

The Problem

The main problem is that it's important where on the commit graph your branch diverges.

I'm going to make some assumptions about the circumstances that are not explicit in your question:

  1. When accepting PRs, the upstream project either
    • Rebases them,
      --A--B--C--X'-Y'-Z'  main
               \
                `X--Y--Z  first-pr
      
    • Merges them
      --A--B--C-----------M  main
               \         /
                `X--Y--Z`    first-pr
      
    • Or uses a squashed merge
      --A--B--C--XYZ'  main
               \
                `X--Y--Z  first-pr
      
  2. You made your second branch from the tip of your first one.[1]
    --A--B--C--X'-Y'-Z'  main
             \
              `X--Y--Z  first-pr
                      \
                       `Q--R--S  second-pr
    

Taken together, these would give your branch different recent history from the upstream project, even if the content is the same (minus your new PR).

What you should have done

Before any PR against the current state of a project, you want to sync your clone to that state. The code below assumes that your remote is origin, the project's remote is upstream, and the primary branch is main.

git fetch upstream
--A--B--C--X'-Y'-Z'  main

Next, you want to make a branch for your improvements

git switch --create second-pr upstream/main
--A--B--C--X'-Y'-Z'  main, second-pr

Then do your hacking, make commits, and push to your remote.

git push origin
--A--B--C--X'-Y'-Z'  main
                  \
                   `Q--R--S  second-pr

The branch you push will only have the commits you made on it that are different from the state of upstream/main when you created the branch.

What you can do now

Don't Panic!™ You can recover pretty easily in two different ways. Since the first PR was accepted, your differences from the upstream are probably minimal. Ideally, they're just the changes you have locally.

Make a fresh branch and cherry pick

If you only have one commit,[2] you can kind of simulate the "Should have done" section but steal the work you've already done.

Sync upstream/main.

git fetch upstream
--A--B--C--X'-Y'-Z'  main
         \
          `X--Y--Z  first-pr
                  \
                   `Q  second-pr

Now make a new branch, just as you would have done.

git switch --create second-pr-take-2 upstream/main
--A--B--C--X'-Y'-Z'  main, second-pr-take-2 (HEAD)
         \
          `X--Y--Z  first-pr
                  \
                   `Q  second-pr

And now grab the last commit[2:1] from your other branch...

git cherry-pick second-pr
--A--B--C--X'-Y'-Z'  main
        |         \
        |          `Q'  second-pr-take-2 (HEAD)
         \
          `X--Y--Z  first-pr
                  \
                   `Q  second-pr

And you're ready to push for a new PR, and close the old one!

Rebase your existing branch

This is probably more common. It has the advantage that it doesn't require a new PR, but it has the downside that it rewrites history. That history won't matter to anyone in most cases, since it's unlikely that people are relying on work from your not-yet-accepted PRs.

First make sure that you have the latest version of upstream/main as normal, but here you don't switch to it.

git fetch upstream

Next, an optional step that I use to get out of jail free if the rebase doesn't look right. You can do without this tagging if you feel like going into the reflog if something goes wrong. Hopefully it's not even needed.

git tag tmp/second-pr
--A--B--C--X'-Y'-Z'  main
         \
          `X--Y--Z  first-pr
                  \
                   `Q--R--S  second-pr, tmp/second-pr

Now for the rebase. The command is actually easy, but sometimes the effects are not.

git rebase upstream/main

This moves your branch to the end of your copy of upstream/main, eliminating any already-applied commits along the way. If there are no conflicts, this is seamless. If there are conflicts, consult the second part of my answer about them.

--A--B--C--X'-Y'-Z'  main
        |         \
        |          `Q'-R'-S' second-pr
         \
          `X--Y--Z  first-pr
                  \
                   `Q--R--S  tmp/second-pr

If it looks good, you can push, but it will have to be a forced-push because the history of your branch is now different from its previous history as known to GitHub. The polite first step is to do this with --force-with-lease instead of a raw --force. The first version makes sure that it was you who made the last change to your remote branch.

git push --force-with-lease

If that doesn't work, consult with the project owners. They may have rebased or otherwise changed your PR already. There's an option in GitHub for PRs to allow changes from the upstream owners.


  1. The diagrams here and below show a rebase of your first PR into upstream, but the steps are the same for any PR acceptance pattern. ↩︎

  2. In fact, you can also cherry pick ranges of commits with .. syntax if your history is linear. But I will leave that as an exercise for the reader. ↩︎ ↩︎

History

2 comment threads

Why fetching and not pulling? (3 comments)
Typo? (2 comments)

Sign up to answer this question »