I created various branches which I closed as they were leading to nowhere. One of these branches is called v2. It was closed at some time in the past.
When developing further, I created another branch also called v2. Tortoise Hg warned me that this branch already exists and whether I would like to "restart it" or "commit to current branch". I asked to restart it.
More dev happens on v2 (several commits) and I decide to push to a remote repository which already has my project (including the previously closed v2). I then get the message
abort: push creates new remote head fce4441f5150 on branch 'v2'!
hint: merge or see "hg help push" for details about pushing new heads
I do not really want to merge (I assume that the message means "merge the old v2 with the new v2") as these branches do not have much in common. I closed v2 as opposed to leaving it hanging because I was not expecting to use it anymore. (the self whipping about reusing names comes later in the question, no worries about that)
This leaves me with new heads. hg outgoing shows me what I expected to happen ...
# this is the first commit for the new v2
changeset: 221:ba47b76010ef
branch: v2
user: w <w#home>
date: Fri Jul 18 14:42:08 2014 +0200
summary: New version: all frames are subclasses, frames are organiz
# some more commits for the new v2
# last commit for the new v2
changeset: 225:fce4441f5150
branch: v2
tag: tip
user: w <w#home>
date: Wed Jul 23 13:17:19 2014 +0200
summary: added manualstart.sh
... but v2 (the old one, closed) is already present in the repository:
Where should I go from now?
Should I force the creation of a new head on the remote repository? I do not like the --force parameter as it costed me a lot of cursing in the past. I want to make sure that it is OK this time.
or something else?
Overall I learned that it is not a good thing to reuse branches previously closed, is that correct? Or is it OK provided I take some precautions?
You are right, that it isn't a good thing to reuse branch names.
I see two ways to accomplish what you need - none of them is really "nice".
1) There is the -f option you already mentioned.
If you are afraid of pushing multiple heads, try pushing in steps:
hg push -r <close commit of old branch>
hg push -r <parent of 221>
hg push -f -r 221 --new-branch
hg push
2) The other option would be to do a No-Op-Merge from the old to the new branch.
hg update -C 221
hg merge v2
hg revert -a -r 221
hg commit -m "old is marked as commited"
But be aware that this might cause problems with future merges, because all changes that are in the old v2 are marked as merged, even if they came from sidebranches or similar.
For future reference, another option is to strip the old branch out of the repo completely. Thus allowing you to push the new branch without any issues.
hg strip <start of old branch>
This is a great option if the old branch wasn't merged into anything. Only negative is that you have run the command on all of the clones.
Related
I've created a named branch in mercurial, committed some changes, and now I want to push that back to the central repo. I've done a fetch, verified I have no changes to merge, but when I try to do the push, I'm getting the message push creates new remote head but I don't understand why. I'm the only dev on this branch and it is still local to my repository.
>hg fetch (pull/update/merge)
>hg status (shows nothing)
>hg push --new-branch mybranch
searching for changes
new remote heads on branch 'default'
new remote head c3064f3cf1b7
abort: push creates new remote head c3064f3cf1b7!
(did you forget to merge? use push -f to force)
Any ideas?
Edit: sorry for any confusion, this is a named branch created by hg branch mybranch
Update: using hg heads yields multiple heads all on different branches. I have one for my branch, and one under default:
changeset: 515:97b9a7802751
branch: mybranch
user: me <me#mymail.com>
date: Mon Feb 27 13:21:54 2012 -0800
files: CryptoRandom.cs
description:
fixing error message for size of max
changeset: 504:c3064f3cf1b7
user: me <me#mymail.com>
date: Thu Feb 09 11:41:32 2012 -0800
files: CipherKey.cs
description:
removing ambiguous characters - CAC-47
using hg log -r c3064f3cf1b7 yields the following (this is the head on default):
changeset: 504:c3064f3cf1b7
user: me <me#mymail.com>
date: Thu Feb 09 11:41:32 2012 -0800
files: CipherKey.cs
description:
removing ambiguous characters - CAC-47
The confusing is that the --new-branch flag has no effect when pushing feature branches (also known as anynomous branches). An anonymous branch looks like this:
... [a] --- [b] --- [c] <- the servers head on default
\
[x] --- [y] <- my feature branch on default
All changesets are on default so you now have two heads on default. When you push, you will create two heads on the server — but Mercurial aborts before that with the warning you see. It aborts since having multiple heads on a server is confusing: when you hg clone your working copy will be updated to one of them, almost at random.
The --new-branch flag is only for named branches. Mercurial will normally abort if you push a new named branch to a remote repository. Adding the --new-branch flag is how you tell it to go ahead.
Unfortunately, we don't have a dedicated --create-new-feature-branch flag. We only have the --force flag which tells Mercurial to go ahead and create the two heads in the remote repository. The downside of --force is that it overrules all safety checks: you can push three or more new heads with that flag and you can even push into an unrelated repository.
So you should use hg outgoing to double check what you're going to push.
I wrote above that multiple heads on the server is confusing since a new clone will be updated to a random head. To avoid the confusion you can give the feature branches names by bookmarking them. You will still be updated to a random head, but hg bookmarks will show you the available feature branches and you can then update to the right one. So if you're using such a workflow, then go ahead with hg push -f.
Just magically resolved this, yet still not clear why. It does seem to be a problem with default even though I'm not working on that branch. I could call >hg branch and get the expected branch name.
I had a change in my local default branch that was not pushed, and did not want. I backed out of that change and then committed. I then did a fetch on the default branch and merged that to my feature branch. Then back on default I merged with the changeset on default that I backed out of I believe. At some point during that process I got yet another head, which probably caused the multiple merges.
It all seems to boil down to existing heads on default, but I still do not know why (or why we would want to) that affects a separate named branch.
This all seem overly complicated for what I expect to happen (and what everyone can simply draw out in ascii diagrams)
Edit
It looks like the problem stemmed during the initial branch perhaps. It looks like I branched twice and [j] is an anonymous branch on default.
to sort of visualize what seems to be going on [j] is my changeset I backed out of and [k] is my first commit on mybranch:
[a] -- [b] -- [c] -- [d] -- [e] (default)
\ \ /
[j]-----------\--- (not sure where this branch came from)
\ \
[k] -- [l] -- [m] (mybranch. Still separate from default)
We are using Kiln as our mercurial server and I there are three developers working on the same repo and i get this issue often and I am not quite sure what is happening.
Every once in a while I will do an hg pull.
Then when I run hg up I get the following message
abort: crosses branches (use 'hg merge' to merge or use 'hg update -C'
to discard changes )
ok so I run hg merge and I get
abort: outstanding uncommitted changes (use 'hg status' to list
changes)
ok so I run hg status and I get something like this
! Safemail 3.0\CSM3.0\AddinSetup\Release\AddinSetup.tmp
! Safemail 3.0\CSM3.0\Outlook2007Addin\Outlook2007Addin_TemporaryKey.pfx
no idea what to do with that.
If I run hg commit again it says no changes.
Finally if i run hg heads I get
changeset: 51:daea74a29d5c
tag: tip
parent: 49:b88e6e522672
user: Rahul Chandran
date: Mon Jan 23 13:30:54 2012 -0800
summary: added login code
changeset: 50:cb6f6e1eec5e
parent: 46:d83431c322ad
user: dthompson#Jabberwock.lan
date: Mon Jan 16 22:10:11 2012 -0600
summary: Adjusted Email-PDF formatting
Clearly I do not come from a DSCS background and I am probably missing some basic understanding of what is going on . Any help appreciated.
What I do know is that the code that my co worker checked in via a push has like no files in common with my changes. I would not expect like a merge conflict or some such in a non distributed source control system . essentially I am having some trouble understanding what is happening here exactly
Check out the help for hg status. It will tell you that ! means:
! = missing (deleted by non-hg command, but still tracked)
So you deleted some files that are tracked in your repository. If you didn't mean to track them in the first place (they look like good .hgignore candidates) you can hg forget FILENAMES; hg commit them. If, instead, you do mean to track them you can hg revert FILENAMES them (to get them back into your working dir from your repository.
Once hg status agrees you have no uncommitted changes you'll be able to hg merge.
Consider taking a little time to read the first few chapters of the (free) Mercurial book. These basic concepts are easy when presented well and in order, but horribly frustrating when you try to pick them up piecemeal from google searches and Stack Overflow questions. It's worth the 30 minutes to save you hours.
I'm new to Mercurial, and I made the mistake of making different changes on different systems before the main repository was up to date. (I understand this is what Mercurial is built for, but my thick brain is struggling to resolve the issue.)
Now on my primary development server, everything is up to date and committed. However...
$ hg push
abort: push creates new remote branches: 4f2672f039d7!
(use 'hg push --new-branch' to create new remote branches)
I don't really want a new branch. I just want all the changes to be merged.
$ hg heads
changeset: 459:ff5f94e44aba
branch: 4f2672f039d7
tag: tip
parent: 458:e63d02baf4cf
parent: 455:267abda62069
user: mike#...
date: Tue Sep 13 14:25:16 2011 -0400
summary: Images from prof
changeset: 455:267abda62069
parent: 453:a74757e26357
user: mike#localhost.localdomain
date: Tue Sep 13 09:08:12 2011 -0400
summary: images for FLC
Point me in the right direction?
EDIT: (adding detail)
When I try to merge, I get the following result:
$ hg merge
abort: branch '4f2672f039d7' has one head - please merge with an explicit rev
(run 'hg heads' to see all heads)
I have tried hg merge ff5f94e44aba, and all of the revs listed above, and each one returns the same result:
$ hg merge 267abda62069
abort: merging with a working directory ancestor has no effect
It looks like you've accidentally created a branch with a silly name. What you most likely want to do is reapply your changes with a branch name that makes better sense. There's no totally automatic way of doing this, but you can extract each changeset as a patch, revert to the point where you messed up and reapply those changes on the proper branch.
Basically what you need to do is look at the changelog; probably by running hg out to see what's missing from the central repository. Make a note of each of the revs that you want to keep.
Next update to the last good revision. Make sure that you are on the branch you wanted your commits to be on.
Now you will apply each of the changes you made and commit each one. You can automate this process something like this:
BADREVS="123 124 125 126"
recommit() { hg di -c $1 | patch -p1; hg ci -m "$(hg log -r $1 --template '{desc}')";}
for rev in $BADREVS; do
recommit $rev
done
Now you've got your changes in your local repository twice; once as the commits on the weird branch and again on the right branch. You can push those changes to the central repo using hg push -b GOODBRANCH so that only the changes to the right branch go up; Alternatively, you can install the strip extension to remove the changes you didn't want from the local repo and then you can push as normal.
By the sound of it; you will still have to deal with the changes made to the central repository before you can push, since you pushed changes from another repo. You probably want to do this merging after you clean up the change history in the local repo.
Pull from remote and then update / merge / commit first. Then you won't make new branches.
I've had this happen when I missed a merge. I like the TortoiseHg workbench for this because it can be a little easier to find what you missed through visualization.
A good way to avoid this in the future, how I stopped getting this error, is the fetch extension. Set your post pull to fetch and it will automatically merge for you, which is very nice. If there's a conflict it brings up whatever conflict resolver you use.
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.
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.