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

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.

Related

How to revert a PR when there's no revert option on 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.

Git - Remove commit from history but lesve the code

I am using git on VS2019
I was wondering if there is a way to remove old commits but always keep the latest code. The reason is that when I work on a big change, I do a lot of commits after checking every small step but at the end it is annoying when I click on view history and need to search an old commit to compare the changes. I would like to remove specific commits but leave the changes. In that way I will see on history only the main milestones of the developing process. There is a way to do that??
It sounds like in these scenarios, you're developing a new feature, in which case you should be using a branch+pull request approach to development. During the pull request, you can do a squash merge. It's not all in the command line, but that might be for the best anyway.
If you're already working within a feature branch, then I like VonC's approach.
It seems that you want the git rebase feature.
If you know how many commits you want to squash together, you can use
git rebase -i HEAD~N
You can also do it in interactive mode:
git rebase --interactive HEAD~N
Be aware that if you merging commits you have already pushed, you may have trouble with your next push.
For more details, see: https://www.internalpointers.com/post/squash-commits-into-one-git
You can follow a workflow similar to "Git better with fixups " from Atul Sharma
For the commits which are incremental improvement for the same step, use git commit --fixup small step, which allows you to "do a lot of commits after checking every small step".
(You can see it in Git Extension in Visual Studio)
But at the end, you can cleanup all those small steps with git rebase --interactive --autosquash <First step commit> (assuming you have not pushed those commits yet)
That way, you end up with a cleaner history.

hg rollback Alternative to Undo Changes?

hg rollback was the easy way to simply undo your last local Mercurial repository transaction.
Sadly hg rollback has been deprecated as of Hg2.7 August 2013
Most of the question/answers are seeking solution to undo "Write nature" commands easily doable with strip or other "Delete nature" commands.
But what happens with delete related commands?
I rebased and Collapsed a set of commits (all from the same branch) into one.
Now how do i undo this action???
I suggest to look into both: mercurial phases and the evolve extension of mercurial. Using the either secret or draft phase as your default phase you then can easily undo anything you did not yet push (which usually makes them public, thus immutable) as old changesets are kept as obsolete changesets which you can revive if needed.
The old, pre-squashed commits may be there -- just hidden (depending exactly how your collapse command works).
Step one is the find the hashes that you care about. I use the smartlog extension, so this is 'hg sl --hidden --all', but some form of 'hg --hidden log' should work for you too. If you are lucky enough to still have a screenshot with the expected hashes that's better.
Step two is to recover those commits. I did it by attaching a bookmark to each of the commits I wanted back.

Can I still merge and push to the repository even if the state was forcefully changed to public?

So, I'm new to Mercurial, and on my first try I screwed up.
Before pushing my data, I tried to merge with one branch (which I think was an old branch)
Instead of pushing it properly to change from "draft" to "public" I manually changed it from Tortoise by using the change phase from "draft" to "public"
I thought it meant that it would be placed in the repository, but when I went to the actual repository (on Bit Bucket) I couldn't find it.
So what happened, is I think I never made a push.
This is causing me an issue to make new changes, because when I tried committing other files, merging it with other branches and pushing it to the repository, i get the error:
searching for changes
remote has heads on branch 'branch one' that are not known locally: 62bf86f93d4f
abort: push creates new remote head 7edef5d2e2e5 on branch 'branch one'!
hint: pull and merge or see "hg help push" for details about pushing new heads
[command returned code 255 Thu May 27 14:43:44 2015]
So I think the solution would be to merge with the original draft (which is now public)
Thus my question: Is it possible to still merge and push a revision that was already deemed "public", even if I can't find it in the repository on bitbucket?
The phase of your commit (public vs. draft vs. secret) has no relevance for whether the commit can be merged. The difference between draft and public only affects whether the history involving the commit can be altered (e.g. via hg commit --amend or hg rebase). Public revisions are considered immutable, draft revisions can still be altered.
You can still merge and push. In theory, if you are positive that you didn't push the commit, you can also safely change the phase back to draft. However, that would be pointless [1], because pushing the merge will immediately make it public again [2].
[1] It can be useful if you use hg pull --rebase, but if you don't know what that does, you probably shouldn't use it.
[2] Unless you push to a non-publishing repository, but that's unlikely unless your group is using the evolve extension. If you don't know what a non-publishing repository or the evolve extension is, you don't need to know.

Please suggest a better workflow in Mercurial

I'm new to Mercurial and what I'm starting to realize is that my basic workflow may not be the most efficient way of working because I perform commits so frequently and for feature improvements that are so small that when I need to find some earlier step to revert to, it is extremely difficult.
Here's what I do after I have a project set up in Mercurial and have already completed my first commit.
Make some changes to a file and get it to a state where a small improvement is working
hg commit -m "improvement A works"
Make some changes to the same file and get it to a state where the next minor improvement is working.
hg commit -m "improvement B works"
Check whether all of the minor improvements add up to a single minor feature working correctly.
hg commit -m "feature A works"
If I find a mistake that was made in "improvement A", I open up history (with the Netbeans Mercurial visual plugin) and copy and paste some of the code back into my current version and start again from there.
This doesn't seem like a good system - I would appreciate any suggestions.
I agree with Jon that branches are the solution, but I would create branches for features rather than for the individual improvements that make up a feature. The workflow pattern would then be this:
Create branch for feature A.
Complete work for improvement A and commit.
Complete work for improvement B and commit.
When the feature seems to be working, merge the feature A branch back into trunk.
If you find a mistake in an improvement A of feature A, instead of starting over, you switch to the feature A branch and do the following:
Fix improvement A and commit.
Merge the feature A branch back into trunk.
You could isolate the changes for the improvements into branches maintaining a stable trunk.
Take a look at Branch wiki page.
Workflow pattern would be:
Create branch for improvement A
Complete work for improvement A and checkin
Test changes and merge back into trunk if successful
Create branch for improvement B
Complete work for improvement B and checkin
Test changes and merge back into trunk if successful
If you find a mistake you can abandon the branch (or correct the bug in the branch prior to merging back into trunk).
I disagree with the branches approach. If no parallel development is needed, why add the complexity of branches? There's nothing wrong with small 'checkpoint' commits. Tags can be used to point to important commits, which might be more clear.