How to revert a PR when there's no revert option on Github? - github

A PR was accidentally merged into main before it had been properly sanitized which I think has resulted in their being no revert option. The lack of an option suggests that it is not possible/simple?
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/reverting-a-pull-request
I have write permissions to the repo in question.

A revert is just a commit like any other commit. So, you can certainly revert the merge commit and push that, possibly as a PR if you're not able to push directly to main.
However, note that this reverses the effect of the merge without undoing the topology. You won't be able to merge those same commits again later.
In theory you can force main to go backwards to a commit before this bad merge took place, erasing the unwanted commits since then, or force main to point directly to the commit at the end of the good branch — namely by using a hard reset. But in practice, where you're sharing this repo with others, that would be a pretty terrible idea.

Related

Do squashed pull requests show up in the contributions graph as a single commit?

I'm working on feature branches that can have over a hundred commits over the course of a week or two. I've expected to get daily marks on my contribution graph for these daily commits once my pull request is accepted, but when that pull request gets "Squashed and merged", it looks like it just shows up as a single commit on the contribution graph.
Is this the intended behavior, or are my commits missing for a different reason?
Yes, this is the intended behavior. You only got one commit merged. That's the point of squash and merge.
I do not recommend squash merges. It takes all the carefully considered commit history about how the branch was developed and mashes it into a convenient but homogeneous paste.
I'm working on feature branches that can have over a hundred commits over the course of a week or two.
I would say this is the real problem. Feature branches should not regularly have over a hundred commits. Your features are too
big, or you're making a lot of commits to fix previous commits, or you have a lot of incidental merge commits from updating your branch, or all of the above.
Update your branch using rebase instead of merge. git rebase main rewrites your branch as if it were written on top of the latest version of main all along. This removes merge commits which say nothing but "I updated my branch" and makes it easier to see what work has been done on the branch. You can change git pull to do a rebase instead of a merge with git pull --rebase and by default by setting pull.rebase. See git-config and Git Branching - Rebasing.
Break up large features into a series of smaller features. This is a skill beyond the scope of this answer, but often a big change can be broken down into a series of smaller refactorings.
Eliminate incidental fixup commits. If you need to fix something in the previous commit, instead of making a new commit "amend" your changes to the previous one with git commit --amend.
For a general cleanup, do an interactive rebase and squash your incidental commits individually. Use fixup.
$ git rebase -i master
pick abcd1234 feature: do that thing
fixup 1234dcba whoops, had a typo in that thing
fixup b33fdead docs: document that thing
fixup afdcefff test: test that thing
fixup deadb33f fix that thing
pick efga1389 feature: did another thing
You had six commits, but you only really did two things. Now you will have just two commits for doing two things.
Using these techniques you can bring your PRs down to a handful of well thought out commits, each conveying important information to the reviewer and future developers wondering why the code was written that way.
See Rewriting History for more.
Yes, they show up as a single commit. That's because GitHub only counts commits that end up on the default branch, and when you squash a PR, you end up with one commit on the default branch.
I personally don't worry about my contribution graph, so this doesn't matter to me. However, I also don't use squash and merge, since I write nice, bisectable commits with good commit messages, and squash and merge destroys that. If it's important to you not to reduce the work that a contributor has made down to a single commit, then you would need a merge strategy whose goal isn't explicitly to destroy history.

Switch branches and take only specific changes with you

I’m still fairly new to the Git way of thinking, and I use it almost exclusively through the VSCode GUI and the Github desktop application, so bear with me if my thinking or terminology is backwards or sideways.
I frequently find myself in the situation that I do some work, then realise some of the work I’ve just done should have been done in a different branch than I’m in and need to move those changes to another branch. But this only applies to some of the changes in the current branch – the rest of the changes in the branch do belong where they are and should stay put. Usually it’ll be just a small handful of files I want to move, while perhaps 40 or 50 files should stay where they are.
There are lots of questions and tutorials on how to change branches and move all your uncommitted changes to another branch; I can also find questions on how to cherry-pick from an existing commit (like this one – but Google as I might, I cannot find any descriptions of how to move only specific, selected, uncommitted changes to a different branch. That is,
the changes are not committed in the current branch (and I don’t want to commit them there, because they don’t belong in that branch)
the changes to move are only a subset of the total number of changes in the current branch
after the move, the changes should disappear from the current branch and be added to existing changes in the other branch so that I can commit them in that branch
I can cherry-pick the files manually (file by file) or I can stage or unstage the particular changes I want to move or not move; either way is fine with me (or if there’s another way, that’d be fine too).
Theoretically, I would imagine I should be able to stash the changes in current branch excluding the files I want to move, and then switch to the other branch. I’ve found a description of how to stash specific files, but not a way to do the opposite, stashing everything except specific files.
Is there some relatively simple way to accomplish this?
Of course, as always happens, a solution occurred to me right after posting here… Very possibly not the best or easiest way of doing it, but it works.
It can be done in a few, relatively simple steps combining staging and stashing:
Stage the changes you want to bring over to the other branch
Stash your unstaged changes with git stash -ku (k for keep-index, which limits it to unstaged changes, u for including untracked files)
Switch to the branch you want and commit the changes there
Switch back to the branch you were in and apply/pop your stash with git stash apply git stash pop
For reasons I don’t really understand, the staged changes also reappeared when I applied my stash, but since they were now committed in the other branch, I could just unstage and discard them in the current branch.

How do I keep a fork of a branch in sync with the actual branch while also keeping the edits I made to the fork?

There is a library with a branch named dev which I created a fork of here. I then made a commit to my fork so that it would better suit my needs, and I intend to make further commits in the future. However, as the library is still in development I would also like my fork to stay up to date with the changed made in the original dev branch so that it has all of the latest bugfixes and such. Is it possible to sync the two branches while keeping my personal changes?
Edit:
I've looked at the possible duplicate and it seems like an appropriate answer but I just want to clear up one thing before I accept it - I need to sync to just the dev branch and not the whole repo, so would I do git rebase upstream/dev? What does git rebase upstream/master even do?
You'll want to periodically rebase your fork. Alternatively, you could merge the changes in if you'd like to preserve the history.

Amend merged pull request

I made a pull request which was merged to a project. It so happens that the code needs a minor modification. How can I possibly change this with no access to the master project whatsoever? Am I out of luck and I have to do a new PR?
Thanks.
Yes, you should submit another pull request.
When using any of Git's "rewriting" commands like commit --amend or rebase it is important that you avoid changing shared commits.
In its Rebasing chapter, the Git Book says:
The Perils of Rebasing
Ahh, but the bliss of rebasing isn’t without its drawbacks, which can be summed up in a single line:
Do not rebase commits that exist outside your repository.
If you follow that guideline, you’ll be fine. If you don’t, people will hate you, and you’ll be scorned by friends and family.
When you rebase stuff, you’re abandoning existing commits and creating new ones that are similar but different. If you push commits somewhere and others pull them down and base work on them, and then you rewrite those commits with git rebase and push them up again, your collaborators will have to re-merge their work and things will get messy when you try to pull their work back into yours.

How should I manage "reverting" a branch done with bookmarks in mercurial?

I have an open source project on bitbucket. Recently, I've been working on an experimental branch which I (for whatever reason) didn't make an actual branch for. Instead what I did was use bookmarks.
So I made two bookmarks at the same revision
test --the new code I worked on that should now be abandoned(due to an experiment failure)
main -- the stable old code that works
I worked in test. I also pushed from test to my server, which ended up switching the tip tag to the new unstable code, when I really would've rather it stayed at main. I "switched" back to the main bookmark by doing a hg update main and then committing an insignificant change. So, I pushed this with hg push -f and now my source control is "correct" on the server.
I know that there should be a cleaner way to "switch" branches. What should I do in the future for this kind of operation?
tip is not a widely useful concept in a repository which has branches of any kind. Whether you are using bookmarks, named branches, or anonymous branches, tip always means the most recent commit on any branch, which is rarely something you care about. The real solution to your problem is to stop worrying about the tip!
I don't really understand your question, since you are switching (without quotes) branches, even if they are not named branches, they are still branches when you use bookmarks.
The mistake you had was an honest mistake and I see no way of having Mercurial protect you from doing that again with bookmarks (marking the same rev with different bookmarks and committing with the wrong one). What I can tell you though is how to do private local branching with Mercurial, and this way you can avoid having the consequences you just had:
You use named branches and phases
Mercurial Phases are really sweet, let me explain them real quick. You can mark revisions to three special states called phases, and these are: secret, draft and public.
secret: Don't get pushed. Can be modified through history editing.
draft: Get pushed. Can be modified through history editing. This is the default state of any revision.
public: Get pushed. Will issue a warning when using history editting extensions on them (strip, rebase, histedit,...).
As mentioned, all local revisions are draft by default, when you push them, they become public. You can use the hg phase command to mark revisions to a particular phase, but if you are going from #3 to #2, or from #2 to #1 (according to the previous numbering), you need the -f argument to force the change, this is:
secret --> draft --> public
To go to the left you need to use --force or -f.
Here is what you do:
hg branch experiment
hg commit -m "Opening experimental branch" //say this creates revision 123
hg phase -sf tip //s is for secret, f is for force
//... hack hack hack
hg commit -m "Uh oh screwed up here"
hg push //no secret revisions are pushed
Now, you can just abandon that branch and leave it like so, it wont ever get pushed. Forget about it and even just close it so that it wont bother you when you list your branches. It won't get pushed it won't get listed, so just don't worry about it.
However, if you have OCD, just strip (hg strip) the branch at the commit where the branch was opened, and it is gone:
hg strip 123
If you have an already existing branch, you can phase several revisions at once like this:
hg phase <start revision>::<end revision> -sf
To make your secret branch draft or public, just phase the latest revision to those phases:
hg phase -d tip //assuming you are in the experiment branch
Then push, and the branch will become public.
Mercurial has been increasingly becoming better at history modification without changing it's general philosophy of discouraging just that. Phases are meant to protect you from accidental history modification as well as from sharing what you don't mean to.
How *I* use bookmarks
Personally, I use bookmarks for debugging and for when I want to try 2 different ways of doing one thing. To me, bookmarks are useful when you want to do anonymous branches (update to a previous revision, commit and fork the history) but want to keep things intelligible.