How to push bug fixes with Mercurial - mercurial

Ok, I have tried searching for something concrete, but haven't come up with anything.
If I am working away on new features in my default branch and a bug report comes in from previous work, what is the best way to handle the fix and pushing? I was trying Bookmarks, but then I saw that it also pushes ancestors. This is what I was doing...
Work on default branch for future changeset (rev 76)
Switch to bug fix in middle of coding
hg bookmark main (for current work)
hg bookmark -r 76 fix1 (for bug work)
hg update fix1
hack hack on now rev 77
hg commit -m 'bug fix'
hg update main
hg push -B fix1
And that's when I noticed that 76 also went up.
Since I don't want new unfinished work going up, just the bug fix, what would be the best way to approach this? Clones for bugs?
Thanks.

You were setting your fix1 bookmark on the same changeset as the main bookmark instead of first updating to the desired changeset where to fix the bug. And when pushing, you can define the revisions to be pushed with the -r parameter. This will only push the branch and ancestors of the specified revision (the branch with your fixes in this case).
Try something like:
Work on default branch for future changeset (rev 76)
Switch to bug fix in middle of coding. Bug is in Changeset 50
hg bookmark main
hg update -r 50
hg bookmark fix1
hack hack on now rev 77 to fix bug
hg commit -m 'bug fix part 1'
hack hack on now rev 78 to fix bug
hg commit -m 'bug fix part 2'
hg push -rfix1
hg update main
Bring your bugfix in the main line of code again
hg merge fix1
Delete the bookmark if you want
hg bookmark -d fix1
work on your new feature again

Related

TortoiseHG Workbench

Hi im a bit of a newbie on tortoise hg. I made some changes to the code (revision 100 and 101) and realised I dont need them. I therefore "updated" (right click update) to 99 then continued developing. Now I try to commit to the server using the push button and I get the error:
abort: push creates new remote head 66444791e8ed on branch 'Marc-dev'!
hint: merge or see 'hg help push' for details about pushing new heads
How do I solve this? Please make it as easy as possible for me as I dont have a tonne of experience.
thanks
If you don't need the two changesets 100 and 101 and want to get rid of them, you can delete (strip) them from the history. First ensure that the strip extension is activated (File > Settings > Extensions). Now right-click on changeset 100 and select Modify History > Strip from the context menu. The function removes the selected changeset and its children. You can also do this from the terminal with hg strip 100.
With the second head removed, you should now be able to push your changes.
Edit: I just noticed that you probably already pushed the changesets 100/101 to the remote server. In this case you can't simply delete them. Instead, you could backout the redundant changes and rebase your latest changes on top of the initial branch:
It's easier to do this from the command-line:
hg up 101
hg backout 101
hg backout 100
hg rebase -s 102 -d 105
The backout commands creates two additional changesets, probably 104 and 105. rebase moves your two new changesets 102/103 on top of 105. Now you should be able to push.

mercurial copying an existing branch

We have 3 branches, default bugfix and release.
After some bad merges bugfix is now in a very broken state. We've kind of ignored this branch for a while but now it's needed again. I'd like it to be exactly like default but merging doesn't work, because it now has the same ancestor as default.
I've tried to just copypaste default branch to bugfix branch, and commit that.
That seems to work in the sense that
hg up --rev commitB
hg diff --rev commitA
hg diff gives back nothing, and
hg up --rev commitA
hg diff --rev commitB
hg diff gives back nothing
but when I hg up from one commit to the other I still see "42 files updated" which makes me think there are differences...
How can I know for sure that there aren't any differences? and if there are how do I make the branches identical?
Branches are more fluid than you're imaging them. When you talk about what is in branch X what you're really saying is "what the working directory looks like if I check out the most recent (technically tipward) commit whose branch: label is set to X.
So, if I'm understanding what you want your easiest solution is to just create a new (and thus most recent) commit with the branch name bugfix. This should do that:
hg update default
hg branch --force bugfix
...make a tiny change (perhaps to the readme)...
hg commit -m 'reinvogorating bugfix'
Then when you hg update bugfix it will be exactly like deafult was at the time you did that.
What you're doing isn't working because files that have been removed and/or added in default weren't removed or added in your bugfix via copypaste, but reallly don't copy paste, just re-create bugfix off of default and be done with it.

Easy way to tell what branch your working directory is in with Mercurial?

If I create a new branch using hg:
$ hg branch newbranch
And then look at branches:
$ hg branches
default 194:d9df55198e53
newbranch 193:a36a491b8507 (inactive)
newbranch is marked as (inactive), despite my working directly being currently mapped to it.
If I do a commit, default will then be flagged (inactive).
However, if I switch to default, merge, and commit, then switch back to newbranch, newbranch will say (inactive) again.
This is a bit of a pain, because I may do that on a friday night, and not come back to it until Monday, and not know what branch my working directory is actually pointed at.
So, is there a better way to tell, or should I always make it my workflow to specify the branch I want to work in before I start.
Though hg summary will tell you what branch you're on, so will hg branch without a branch name argument. Let's say I've never created a branch called mybranch before, but I want to start it:
> hg branch
default
> hg branch mybranch
marked working directory as branch mybranch
And now I've worked for a bit and want to commit, but forgot if I set the branch name for this next commit or not:
> hg branch
mybranch
Oh, I did.
Ok, I just discovered hg sum:
$ hg sum
parent: 195:d0a2617b4b51 tip
[Commit Message]
branch: newbranch
commit: (clean)
update: (current)
So I guess this is how you do it?

Abandoning changes without deleting from history

There is a commit that just didn't work, so I want to abandon it without deleting it from history.
I have updated from an earlier revision and committed, thus creating a new head.
I don't have branches, I don't want branches, I just want to simply go on with the new head exactly as it is, nothing fancy, no merge, no worries, just go on forgetting the previous one.
I can't seem to find how to do that, and I'm starting to believe it can't be done. All I find is stuff about branches, or stuff about merging.
Update your repository to the head with the revision that you want to forget about, then use hg commit --close-branch to mark that (anonymous) branch as closed. Then update to the head of the branch that you do want, and continue working.
You can still see the closed branch if you use the -c option to hg heads, but it won't show up by default and hg merge will know not try to merge with the closed head.
You will need to use hg push --force the first time you push this closed head to another repository since you are actually create additional heads in the remote repository when you push. So tell Mercurial that this is okay with --force. People who pull the closed head wont be bothered by any warnings.
I know you don't want to work with branches at this stage, but that's exactly what you've done. When you went back to an earlier version and committed something that worked you created a branch - an unnamed branch, but a branch all the same.
There's no problem with just carrying on just as you are and not worrying about having multiple heads, but if you want to tidy things up so you don't accidentally pick the wrong head one time then you can kill off the old branch.
There's a good section in the Mercurial documentation that takes you through a number of options around Pruning Dead Branches.
I think the best option for you is to mark the old branch as "closed". If your old head is revision "123" then:
hg update -r 123
hg commit --close-branch -m 'Closing old branch'
hg update -C default
First of all, type:
hg heads
Imagine, you have three heads listed:
changeset: 223:d1c3deae6297
user: Your name <your#email.com>
date: Mon Jun 09 02:24:23 2014 +0200
summary: commit description #3
changeset: 123:91c5402959z3
user: Your name <your#email.com>
date: Sat Dec 23 16:05:38 2013 +0200
summary: commit description #2
changeset: 59:81b9804156a8
user: Your name <your#email.com>
date: Sat Sep 14 13:14:40 2013 +0200
summary: commit description #1
Let's say, you want to keep the last head active (223) and close the rest.
You would then do as follows:
Close head #59
hg up -r 59
hg ci --close-branch -m "clean up heads; approach abandoned"
Close head #123
hg up -r 123
hg ci --close-branch -m "clean up heads; approach abandoned"
Commit the changes
hg push
Don't forget to switch to the right head at the end
hg up -r 223
And you're done.
You want to use hg backout. This removes the changes made by the changeset from any child changeset.
Check this out for a good explanation.
Mercurial Backout
An alternative to closing or stripping the unwanted branch would be to merge it in a way that totally discards its effects, but leaves it in history. This approach will allow those unwanted changes to propagate in a push - so only use this if that is the intended effect.
Let's say the changeset history looks like this:
1-2-3-4-5-6
\
7-8-*
and it is 5 and 6 which are no longer wanted.
You can do this:
hg up 8
hg merge -r 6 -t :local
hg commit ...
which will create this:
1-2-3-4-5-6
\ \
7-8-9-*
The update to 8 ensures you are working at the desired head in history, which you want to keep.
The -t :local instructs hg to use the merge "tool" called local which tells it to ignore changes from the other branch, i.e., the one NOT represented by the current working folder state. More info.
Thus the unwanted changes in 5 and 6 are preserved in history but do not affect anything more recent.
Both Niall's and Nick's answers are straight on. Because I find myself creating lots of dangling heads, I ended up writing an alias to close heads more easily. By adding this to your .hgrc:
[alias]
behead = !REV=$($HG id -i); $HG update $# -q && $HG ci --close-branch -m "Closing dead head" && $HG update $REV -q
(if you already have an [alias] section, you can append to it instead)
You can now close a head in one single-command (and without having to update to a different changeset manually) like this:
$ hg behead 123
Note: the alias takes advantage of the fact that Mercurial aliases can be shell commands. This means that this will probably only work on UNIX, not on Windows.
This is a use case for the Evolve extension. It's currently not bundled with Mercurial, so it is technically a third party extension. But it's being used quite heavily by a bunch of people, including Mercurial developers, is being very actively developed, and isn't going anywhere.
With the Evolve extension, you simply do
hg prune -r revname
and get on with your life. The cset will still be there, but obsoleted. It won't be visible unless you pass the --hidden option to Mercurial commands, and by default won't be pushed to remote repositories. Though I think you can force it if you really want to.
If the cset you are pruning has ancestors you want to keep, then you'll have to run hg evolve to rebase those changesets. hg evolve will do so automatically. Otherwise, you don't have to do anything.
You may clone your corrupted repo to a new one without cloning that unwanted head. Then remove old repository, move newly created clone to the original place and continue working with it. This will take some time, but you'll get a perfectly clean repository without a sign of that unwanted revision.
hg clone --rev myGoodResition myDirtyRepo myCleanRepo
I have run into this issue many times when I want to behead a head that was created in error. I always want to see it disappear off the face of the Earth.
On your local copy, get the latest and then:
Find the beginning of a head you want to strip (where a new neck starts to branch off), get the revision number
Strip it.
Source: TipsAndTricks.
Source: PruningDeadBranches#Using_strip.
hg --config extensions.hgext.mq= strip -n <rev>
Make a trivial file update (add a whitespace to a file), commit and push.
Your repo should now have the head stripped. The last step is important as stripping doesn't create any changes you can push to your central repository. Without the last step you only have stripped the head locally.

Is there any way to delete local commits in Mercurial?

So I keep making a silly mistake in Mercurial. Often times, I'll start work without doing an "hg pull" and an "hg update." When I try to push my changes, I get an error.
Is there any way to delete my local commits so I can avoid creating multiple heads, branches, etc? I just want to delete my local commits, merge my changes with the tip, and then re-commit. Sounds simple, right? I can't seem to find any way to easily delete local commits so I can cleanly merge with the tip.
Again, I'm only trying to delete local commits made with "hg ci". I don't want to modify files, revert, etc.
Enable the "strip" extension and type the following:
hg strip #changeset# --keep
Where #changeset# is the hash for the changeset you want to remove. This will remove the said changeset including changesets that descend from it and will leave your working directory untouched. If you wish to also revert your committed code changes remove the --keep option.
For more information, check the Strip Extension.
If you get "unkown command 'strip'" you may need to enable it. To do so find the .hgrc or Mercurial.ini file and add the following to it:
[extensions]
strip =
Note that (as Juozas mentioned in his comment) having multiple heads is normal workflow in Mercurial. You should not use the strip command to battle that. Instead, you should merge your head with the incoming head, resolve any conflicts, test, and then push.
The strip command is useful when you really want to get rid of changesets that pollute the branch. In fact, if you're in this question's situation and you want to completely remove all "draft" change sets permanently, check out the top answer, which basically suggests doing:
hg strip 'roots(outgoing())'
If you are using Hg Tortoise just activate the extension "strip" in:
File/Settings/Extensions/
Select strip
Then select the bottom revision from where you want to start striping, by doing right click on it, and selecting:
Modify history
Strip
Just like this:
In this example it will erase from the 19th revision to the last one commited(22).
Modern answer (only relevant after Mercurial 2.1):
Use Phases and mark the revision(s) that you don't want to share as secret (private). That way when you push they won't get sent.
In TortoiseHG you can right click on a commit to change its phase.
Also: You can also use the extension "rebase" to move your local commits to the head of the shared repository after you pull.
As everyone else is pointing out you should probably just pull and then merge the heads, but if you really want to get rid of your commits without any of the EditingHistory tools then you can just hg clone -r your repo to get all but those changes.
This doesn't delete them from the original repository, but it creates a new clone that doesn't have them. Then you can delete the repo you modified (if you'd like).
I came across this problem too. I made 2 commit and wanted to rollback and delete both commits.
$ hg rollback
But hg rollback just rolls back to the last commit, not the 2 commits. At that time I did not realize this and I changed the code.
When I found hg rollback had just rolled back one commit, I found I could use hg strip #changeset#. So, I used hg log -l 10 to find the latest 10 commits and get the right changeset I wanted to strip.
$ hg log -l 10
changeset: 2499:81a7a8f7a5cd
branch: component_engine
tag: tip
user: myname<myname#email.com>
date: Fri Aug 14 12:22:02 2015 +0800
summary: get runs from sandbox
changeset: 2498:9e3e1de76127
branch: component_engine
user: other_user_name<name#email.com>
date: Mon Aug 03 09:50:18 2015 +0800
summary: Set current destination to a copy incoming exchange
......
$ hg strip 2499
abort: local changes found
What does abort: local changes found mean? It means that hg found changes to the code that haven't been committed yet. So, to solve this, you should hg diff to save the code you have changed and hg revert and hg strip #changeset#. Just like this:
$ hg diff > /PATH/TO/SAVE/YOUR/DIFF/FILE/my.diff
$ hg revert file_you_have_changed
$ hg strip #changeset#
After you have done the above, you can patch the diff file and your code can be added back to your project.
$ patch -p1 < /PATH/TO/SAVE/YOUR/DIFF/FILE/my.diff
You can get around this even more easily with the Rebase extension, just use hg pull --rebase and your commits are automatically re-comitted to the pulled revision, avoiding the branching issue.
hg strip is what you are looking for. It's analogous of git reset if you familiar with git.
Use console:
You need to know the revision number. hg log -l 10. This command shows the last 10 commits. Find commit you are looking for. You need 4 digit number from changeset line changeset: 5888:ba6205914681
Then hg strip -r 5888 --keep. This removes the record of the commit but keeps all files modified and then you could recommit them.
(if you want to delete files to just remove --keep hg strip -r 5888
If you are familiar with git you'll be happy to use histedit that works like git rebase -i.
[Hg Tortoise 4.6.1]
If it's recent action, you can use "Rollback/Undo" action (Ctrl+U).
In addition to Samaursa's excelent answer, you can use the evolve extension's prune as a safe and recoverable version of strip that will allow you to go back in case you do anything wrong.
I have these alias on my .hgrc:
# Prunes all draft changesets on the current repository
reset-tree = prune -r "outgoing() and not obsolete()"
# *STRIPS* all draft changesets on current repository. This deletes history.
force-reset-tree = strip 'roots(outgoing())'
Note that prune also has --keep, just like strip, to keep the working directory intact allowing you to recommit the files.