I've come across a difficulty at work (as presented in the simplified sketch below). During the creation of a branch the default for some reason got stuck as a parent to a branch, but still keeping a default branch separately (that is the default branch we're using going forward). This has left us with two default branches.
Someone mistook how to commit changes before branching, so we ended up merging changes made in branch1 into a branch2.
I've been looking into Mercurial: the definitive guide to see if this is a resolvable issue, but couldn't find out what commands regarding backing out or closing that would help. The easiest way would be if it's somehow possible to rename the left-over default branch.
What is the best and/or easiest way to resolve this?
I'm preparing the merging of development branches into the correct default branch and want to have this headache fixed before I start any major merging that could make it even more difficult to fix this in the future.
Remember that the branch names are just labels put on the commits — there's nothing really broken about your graph. The branch names doesn't affect what happens when you merge, only the file content is important when merging.
That being said, you can close the extra head on default, the one below branch1:
$ hg update "min(heads(branch(default)))"
$ hg commit --close-branch -m "closing this head"
That will leave a dangling close changeset in your graph, which is fine. The close changeset will hide the head from hg heads and commands such as hg merge will then no longer suggest to merge with this head.
Old question, but I though this might be useful to someone.
..this occurs when a single branch diverges, usually when someone does an hg push -f instead of pulling and updating. In your case, the forced head happens to be also on another branch, but this can happen on a single branch as well. My solution would be to let it sit until the branches are merged -- at least, if there's a plan to merge them at some point. This solution is more clean than closing the erroneous head, in my opinion.
However, doing hg update default will take you to the newest commit with the 'default' name. Although I think this idea is the right one in your case, this is because the "default" that you actually want is the newest commit with the "default" branch name, so there should be no problem.
However, if the erroneous head were newer, hg update default would take people to the erroneous head, which could be quite confusing.
In either case, this would resolve the issue:
hg update <revision number of correct 'default' head>
hg merge <branch the erroneous 'default' head is on>
So in this case, hg update default will update to the erroneous head:
1-2(default)
\
3(default)-4(branch1)
You would need to do:
hg update 2
hg merge branch1
# results in this graph:
# 1-2---5(default)
# \ /
# 3-4(branch1)
whereas below, hg update default will update to the one you actually want anyways:
1-2------------5(default)
\
3(default)-4(branch1)
..and you could just ignore the erroneous default, because it won't affect anyone. ..then, once someone does an hg update default; hg merge branch1, the erroneous head will silently disappear, because at that point it's an ancestor of the erroneous 'default'. ..which would result in something like this:
1-2-5----------11(default)
\ /
3-4-[...]-10(branch1)
..you could also do a useless commit on your desired default, and then it will be the newest, and it would be the one people get when they do hg update default, but I don't really like having junk commits in the history.
Related
I am on the default branch, but some old commits are said by mercurial to be other default heads.
I would like to push a commit, but I can't because otherwise I would have to push other default heads which would be wrong.
How can I make the situation clean? I assume I have to get reed of these additional default heads and so that I again push my work. Is there a safe way to do it?
First piece of advice is to backup you repo so that if something goes wrong, you have a return path.
You will need to determine if the other heads are important or if they can be thrown away. You can list the heads with:
hg heads
if the other heads are throwaways, you can use the hg strip command. Some caution is
needed here. If you created a anonymous branch (the head in question) and later merged
it back to your default (or other branch), deleting it will cause any changed after the merge to also be removed.
You should spend some time reviewing: hg log -G (or one of the many graphical interfaces) and determine if this is going to be an issue.
If it is an orphan branch (head) you can use:
hg strip changeset-id
I've got a problem with a repository where I tried to clean up a 5 head default branch, merging them one by one, but several things went wrong inside and outside of mercurial and it all just went hideously wrong.
I got everything into one head, in the default branch, and updated into it, but the system was very badly broken...
I've updated to a previous revision that works fine, and I'd like to forget everything that exists ahead of it. I can't just use hg revert --all --rev xxx as that'd mean when I commit next, it'll create a new head, and I'll be in the same situation again, where I can never merge theses two heads as the 2nd head will update and delete files trashing the system.
What can I do?
Many thanks.
Review your changes by:
hg glog
or:
hg serv --port 8888
then strip unwanted changesets by:
hg strip REV
I sometimes but not always end up with two heads on my default branch. The sequence of events is something like:
hg pull
hg update -C default
hg branch mybranch
hg merge default //merge in default
hg commit -m"merged mybranch into default"
hg heads -default //shows 2 heads
hg push --branch default //won't let ne. create 2 heads
The 'rival' head appears to be a changeset committed to default earlier in the day.
What I don't understand is why this happens sometimes and not other times.
The explanation I am usually offered is that the other guy pushed a change after I did a pull (my first action in the list above). But I think this happens in other cases e.g. when he pushed his changeset before I started.
I would have thought that when I pull default with his commit I get default with one head. My merge/commit should just create a new head after that. Why does it create a second head?
First of all, this is a totally normal situation. It's not a problem, or an error, or something to be avoided -- it's how a DVCS works.
In brief: you get two heads whenever two people start working from the same commit and do different things. It doesn't matter if they do it in their own (named) branch (as you're doing above) or on default. Once you merge your work back to default and someone else has done work on default you've got two heads and someone has to merge. It's just how things are.
Before you push do a hg pull and then a hg merge and you'll integrate your work with yours, by creating a new merge commit, with two parents -- your work and their work -- and then you push and you'll not see that warning.
Incidentally, you might want to check out the bookmarks feature. It's better suited for per-feature branches like you appear to be doing above than the named branches you're using, but it in no way saves you from having to deal with multiple heads.
check state of repository immediately after pull (pull can bring new head in default for you) with hg heads
hg branch without commit do nothing (you haven't mybranch)
Even if you'll create mybranch and merge it with default's tip (according to your syntax), it will not eliminate 2-nd head in default
As I understand it, you can't really fix a comment in Hg. So what I would like to do instead is re-push the exact same changes (or at least "touch" the same files and commit & push again).
The reason this is necessary is because we have a bug tracking and build system that relies on specific comment patterns, and we need to make sure the right files get included in the build, but if I forget to update the bug # in my comment from my last commit, and I accidentally commit and push it under the wrong # because i'm overzealous, how can I re-push those same files again without manually going into each one and adding a space or line break just to create a diff?
To clarify, I can't "rollback" or something; it's already been pushed with the wrong message.
As far as I know, current Mercurial features provide no support for this. After the changeset has been pushed, there's little you can do to un-push it, besides stripping it from the server repo and any other developer's repo.
I guess you you should ask those who set up this workflow in your shop; they should've come up with some exception handlers for it.
We usually just ignore issues like this, and close the bug by hand, making sure the bug links to the correct changeset. If the changeset is really messed up (usually this means bad changes, not a malformed commit message), we resort to stripping.
Since your change has already been pushed you can't use a simple fix, like "hg commit --amend", but you can do something similar. Basically, the following commands re-do the commit with Mercurial's help:
CSET=...the changeset to re-do...
hg up -r "p1($CSET)" # Update the working directory to the parent revision
hg log -r "$CSET" -p > changes.patch
hg import --no-commit changes.patch
hg commit # And use the appropriate commit message.
Then, merge and push.
The only way that I could think of doing this is to commit two more changes, one would be an hg backout of the incorrect revision and the other would be an hg backout of that revision with the corrected comment.
I don't like that idea though and wouldn't recommend it if there was any way to fix the problem in your bug tracking system.
I forked someone elses repository on Bitbucket and made some changes (and pushed them to my forked repo). In the meantime, the original author made substantial changes (pretty much a rewrite).
I want to update my repo to be exactly the same as his (but with my changes still present on that tag) in a way that he can easily pull my new changes without the previous changes I made affecting anything.
I pulled his changes into my local version, which left me with 2 heads. I want to just take his head as the tip/default. I tried to resolve this (based on some SO answers) by doing:
hg update -r [myrev]
hg commit --close-branch
hg update -r [hisrev]
This seemed to put me in a state I wanted. My working directory looks like his. However, when I tryed to hg push I'm told this will create multiple remote heads, and I'm not sure if this is what I want (the message makes it sound scary!)
So, have I done this correctly? Should I force the push? Will this do what I want (eg. keep a copy of my changes so I can get to them, but in a way that generally won't interfere?). If so, was this the best way to achieve this?
Heads on a closed branch are still heads, so if you want to push those changes you'll need --force.
The other option, is to merge that head into what you want to be your default branch, but select none of its changes. This can be done non-interactively using:
hg update [hisrev]
hg --config ui.merge=internal:local merge [myrev]
hg commit
You'll be down to one head, and it will have only his content, but yours is still available in the history.