I’ve been through some recent agony screwing up pull requests. I figured before I shoot myself in the foot again, I would ask for some advice/help.
I have a particularly stale branch and pull request I’d like to at least make technically feasible to move forward. (I’m not as interested in whether or not it’s eventually accepted, though I think it’s worthwhile. At the moment, I’m more concerned with improving my Git/GitHub-fu.)
The branch is here:
GitHub tells me it’s 3 commits ahead and 5189 commits behind python:main. That is — I think — going to present problems.
The corresponding PR is here:
My inclination is to simply abandon both the branch and the PR and start over. I think if I abandon my changes, I can probably catch up my branch to python:main and go from there. Is that the right thing to do with such a stale branch and PR? TBH, at this point I probably need to rewrite the change to Python/ceval.c anyway, so discarding my three small commits would be no huge deal. That file has been a real moving target for a few years. I have simply not had the time or — to be honest — the desire to keep tracking it through all its various changes.
while there are hoops you could attempt to jump through in the right order to preserve the existing PR… in a case like this just creating a new branch and PR is fine, you aren’t losing anything.
my guess as to the hoops (the names upstream and origin are arbitrary and defined in your local clients git config based on other things you may have done, substitute your names for them as appropriate):
git pull upstream main
git push origin main
git checkout issue44060
git merge main
… this will get you into merge/rebase hell, resolve all of those, git add and git commit the files …
git diff main # verify that your changes vs main are what you want
git push origin issue44060
If the PR is in hell at that point, just abandon it. close the PR and create a new one (which I believe can be done using the existing branch; github seems to maintain a concept of which base branch commit a PR was started from and some forms of merging or rebasing seem to mess this up but I’ve never tried to understand how, instead just tossing the mangled PR and starting a fresh one).
There were two ways you could have updated your branch first.
In your local clone, git switch issue44060, git merge upstream/main, fix the merge conflict and commit, push to your fork.
In your fork, on GitHub - smontanaro/cpython at issue44060, press the Sync fork, fix the merge conflict (I am not sure how to do this on the fork), commit, and pull the branch into your clone.
Either way, the revised ceval.c would be pulled into the PR.
Instead, you apparently hit the sync button on the PR, after the test results. You need to fix the merge conflict, which you can do online. I commented on what I believe the fix should be.
Once the PR is fixed, you should either pull the PR code into your local clone branch (I don’t know how to do this) or delete your local clone branch and create a new branch with the same name (and push to your fork). Or maybe editing the PR will edit the branch on your clone. I don’t know.
PS: I have done update merges on branches/PRs older than 2 years.
Even after years of Git usage, I’m still scared of losing my work. So sometimes, I create a temporary branch for a rebase. Let’s say that I’m working on an important bugfix local branch:
# update main
git switch main
git merge --ff
# rebase the outdated branch on updated main
# in a new temporary bugfix_REBASE branch
git switch bugfix
git switch -c bugfix_REBASE bugfix
git rebase main
# handle the rebase mess
# once, the rebase is clean, tests pass, you're safe to:
# rename bugfix_REBASE branch to bugfix
git branch -D bugfix
git branch -m bugfix # rename bugfix_REBASE to bugfix
In the middle of the rebase, if something goes wrong, just do:
# abort the mission!
git switch main
git branch -D bugfix_REBASE
You’re safe: the bugfix branch was not touched.
If you didn’t create a bugfix_REBASE and you messed up your repo, git reflog gives you sha1 of commits before the mess. I use git log <sha1> to see what it is. If it’s the branch I’m looking for with the old code, I just recreate the branch:
git switch -c old_bugfix <sha1>
Also, if the local branch was uploaded to my github.com/vstinner/cpython fork and I didn’t make any local change in the meanwhile, I just remove the local branch and recreate it: git branch -D bugfix and git switch bugfix.
I prefer to keep a linear Git history on top of the main branch, so I prefer rebase over merge.
Git is like a filesystem. Creating local branches is cheap, you can rename a branch to OLD_branch to keep it aside until you’re 100% sure that you don’t need it anymore. It’s also cheap to create a copy of a branch to rework it, and only override the old copy when you’re 100% sure that your new branch works as expected.
When a PR has many commits, sometimes git rebase creates conflicts at each commit, sometimes even “the same” conflicts multiple times (around same lines of code). In that case, either I squash commits locally (git rebase -i <reference commit of the PR> and squash commits) and then do the rebase, or I “export” the whole PR (branch) as a .patch file (git diff main.. > patch) and then I recreate manually the PR on top of the up to date main branch and then override my PR (its branch). I tend to prefer the “patch file” way since I can more easy recreate the PR step by step (file per file) in my text editor. Well, pick your favorite and most effective method