TortoiseHG: cannot partially commit a merge - mercurial

I tried to merge two heads in Mercurial. After merging, I didn't commit and did some more changes. Then I tried to commit and got the following message:
abort: cannot partially commit a merge (do not specify files or patterns)
I'm using TortoiseHG as visual shell, and Beyond Compare for comparing and merging. And I'm relatively new to all of them.
What should I do to finish commit successfully?

Mercurial/TortoiseHg is correct in telling you that you should not partially commit a merge. Partial means that you do not commit all files at once.
The underlying reason for this message is that is gives you the wrong results. When you merge two changesets in Mercurial, you are creating a new changeset with two parent changesets. This merge changeset shows others how you want everybody else to combine the two changesets.
Let us imagine that you start with changesets A and B and want to merge them. This creates a graph like this:
... --- [A]
\
[M]
/
... --- [B]
Pretend that we added the line A! to a.txt in the A changeset and that we added B! to b.txt in the B changeset. Just two independent changes that does not conflict. If Mercurial allowed you to do a partial commit, then you could do this:
hg merge
hg commit -m 'Added A!' a.txt # creates M
hg commit -m 'Added B!' b.txt # creates M'
and the result is this graph:
... --- [A]
\
[M] --- [M']
/
... --- [B]
If you look at b.txt along the path B, M, M', then you will see that the line with B! was introduced in B, removed in M and reintroduced in M'!
This is not what you want from a merge changeset: a partial merge throws away changes from one branch just to introduce them again in a followup commit. Mercurial trusts you when you create M: it really believes that M contains the correct mix of A and B. In particular, if the B! line is removed in M, then it will remain gone when you merge M with other changesets.
So Mercurial is trying to protect you from creating a bad history by not allowing partial merges.

I think you have aliases in hgrc file. Try to remove [alias] section and commit again.

What should I do to finish commit
successfully?
One of the benefits of Mercurial (or git or any other DVCS) is that you can perform a commit at any point in your development process and it will be both fast and private. It will be fast because you should be committing to a local copy of the repository residing on your hard drive, and it will be private because no-one will see your change set until you push them to the server (or other master repository).
Therefore, to partially answer your question, the appropriate thing to do would have been to commit the merge without your addition changes, and then apply and commit your next wave of changes. If you are using TortoiseHG to peform the merge it will actually prompt you to commit the merge before leaving the GUI because this is the intended HG workflow.
That being said, I made some changes on a named branch (ie: new head), merged it back into the default branch, exited the TortoiseHG GUI without committing, made some more changes, and then committed with no problem. I will ask some clarifying questions below your original inquiry.

I had this problem because I had deleted some files. I reverted the files to restore them, then was able to commit. I then deleted the files and did a second commit.

I had the same problem and I was NOT specifying any files and using command-line.
The problem was the [default] section in my .hgrc
[defaults]
commit = -X project/web.config
So it added specific files to every commit-operation by default.
Review your defaults section for potential problems.

I had the same problem and the command I gave was
hg commit -m Merge with 1234
I figured it out after sometime that the commit message "Merge with 1234" has to be given in quotes as the command takes "with" and "1234" as file name params.
please check it in your case.

Related

Why is hg commit creating a new head?

I've added a bunch of files to my Mercurial repository, and when I now do hg commit -m "Bunch of new files" I get a message saying Created new head. I can't understand why this might be, unless my repository has somehow got corrupted. It's a pretty simple repo, with no branches, just default. I don't want to create a new head. Is there a way of forcing a commit which doesn't create a new head? (This is new behaviour, incidentally - I've been working with the repo for a couple of years, pushing changes to Bitbucket).
What probably happened is something like this...
Your starting point was a repo that had a few changesets:
a-b-c-*
(* is your local working folder - not a commit)
Later on, you did an hg pull which made your repo look like this:
a-b-c-d-e
\
*
because someone else had committed d & e in the meantime.
Then later when you hg commit, you get this:
a-b-c-d-e
\
f-*
And f is your new head. You can also think of f as the tip of an anonymous branch.
So this is just how Mercurial works (and its actually a very useful feature, when you want it).
At this point, you can either hg merge e and f, yielding:
a-b-c-d-e
\ \
f-----g-*
or you could hg rebase f onto e, to get:
a-b-c-d-e-f-*
(You can't really rebase the other way - to put d and e onto f, because they are 'public' having been pushed by someone else already.)
Both merge & rebase are fine to use and its a bit subjective which is "better". Merging preserves the actual history of what happened more closely, but also makes the history harder to follow.
I can't understand why this might be
New head (aka "anonymous branches") may appear in just one case: then parent of this new commit isn't HEAD at the moment of commit (HEAD of active branch, even if it's "default"). For "why not HEAD" can be at least two possible reasons:
active changeset wasn't head in working dir at start
some (new) changesets were pulled from upstream in the middle
BTW: AFAICR, "Creating new head" is error on push, not on local commit.
I don't want to create a new head. Is there a way of forcing a commit which doesn't create a new head?
Rebase diverged history in local repository before push to correct destination in order to eliminate branchpoint

Breaking Mercurial file "links"?

We seem to have messed up some of our HG configuration.
When merging we see a few of these entries:
warning: detected divergent renames of core/src/main/java/x/y/z/MyFile.java to:
core/src/main/java/x/y/z/NewFileA.java
core/src/main/java/x/y/z/NewFileB.java
MyFile should not be linked to the "new files". How can you break this link?
You cannot break the link after the fact. The link was created when you (most likely) did
$ hg rename MyFile.java NewFileA.java
in one branch and someone did
$ hg rename MyFile.java NewFileB.java
in another. When merging the two branches, you will end up with both NewFileA.java and NewFileB.java. Some might consider that a conflict, hence the warning.
It's also possible that you did
$ hg copy MyFile.java NewFileA.java
$ hg copy MyFile.java NewFileB.java
and did so on purpose. In that case there's no conflict and the warning is unneeded. Mercurial cannot distinguish the two cases internally since hg rename X Y is the same as hg copy X Y; hg remove X. See my other answer for information about what hg copy really does.
So, don't worry, nothing is messed up. After you merge you wont see the warning again — the warning only appears if you merge with a branch where MyFile.java still exists.
Unless there's some negative repercussion that I'm not aware of, you can break the link by doing a remove or forget of the inadvertent copy target file, committing that, and then re-adding the file (with the same content). Changes to the original copy source will not be merged to the re-added file.
In Mercurial 3.7.2 I have been able to reproduce subsequent merges (not just the first merge) applying changes to the copy target, which is counter to the documentation, although I have not dug into this further. Here I am referring to merges to the branch where the copy was committed, not the other direction.

merge in mercurial with automatic comment listing changeset ids/guids for the two heads

I stopped using hg fetch to pull and merge in another head for a Mercurial repository because I like to make the commit message say what is merging with what. Furthermore, I am moving from "merge repo1 -> repo2" to a more specific "merge head1guid -> head2guid" format.
How can I automate this so I don't have to list the heads with hg heads then copy and paste the guids for the two changesets into my commit message?
As others have pointed out in comments the one or two parents of a changeset are already stored in a changeset and shown in hg log and other command line views -- You're probably better off not re-storing them.
If you really wanted to you could do something like:
hg commit -m "merging $(hg log -r . --template '{parents}')"
but I always try to put something actually useful in the message like "Merging Jim's work on foo into Alice's work on bar"; there's no new information in re-storing the nodeids of the parents.
Note that command only works when you're committing a merge -- it'll be empty otherise.

Mercurial: how to amend the last commit?

I'm looking for a counter-part of git commit --amend in Mercurial, i.e. a way to modify the commit which my working copy is linked to. I'm only interested in the last commit, not an arbitrary earlier commit.
The requirements for this amend-procedure are:
if possible, it should not require any extensions. It must not require non-default extensions, i.e. extensions which do not come with an official Mercurial installation.
if the commit to amend is one head of my current branch, no new head should be created. If the commit is not head, a new head may be created.
the procedure should be safe in a way that if for whatever reasons the amending fails, I want to have the same working copy and repository state restored as before the amending. With other words, if the amending itself can fail, there should be a fail-safe procedure to restore the working copy and repository state. I'm referring to "failures" which lie in the nature of the amend-procedure (like e.g. conflicts), not to file-system-related problems (like access restrictions, not being able to lock a file for writing, ...)
Update (1):
the procedure must be automatable, so it can be performed by a GUI client without any user interaction required.
Update (2):
files in the working directory must not be touched (there may be file system locks on certain modified files). This especially means, that a possible approach may at no point require a clean working directory.
With the release of Mercurial 2.2, you can use the --amend option with hg commit to update the last commit with the current working directory
From the command line reference:
The --amend flag can be used to amend the parent of the working directory with a new commit that contains the changes in the parent in addition to those currently reported by hg status, if there are any. The old commit is stored in a backup bundle in .hg/strip-backup (see hg help bundle and hg help unbundle on how to restore it).
Message, user and date are taken from the amended commit unless specified. When a message isn't specified on the command line, the editor will open with the message of the amended commit.
The great thing is that this mechanism is "safe", because it relies on the relatively new "Phases" feature to prevent updates that would change history that's already been made available outside of the local repository.
You have 3 options to edit commits in Mercurial:
hg strip --keep --rev -1 undo the last (1) commit(s), so you can do it again (see this answer for more information).
Using the MQ extension, which is shipped with Mercurial
Even if it isn't shipped with Mercurial, the Histedit extension is worth mentioning
You can also have a look on the Editing History page of the Mercurial wiki.
In short, editing history is really hard and discouraged. And if you've already pushed your changes, there's barely nothing you can do, except if you have total control of all the other clones.
I'm not really familiar with the git commit --amend command, but AFAIK, Histedit is what seems to be the closest approach, but sadly it isn't shipped with Mercurial. MQ is really complicated to use, but you can do nearly anything with it.
GUI equivalent for hg commit --amend:
This also works from TortoiseHG's GUI (I'm using v2.5):
Swich to the 'Commit' view or, in the workbench view, select the 'working directory' entry.
The 'Commit' button has an option named 'Amend current revision' (click the button's drop-down arrow to find it).
||
||
\/
Caveat emptor:
This extra option will only be enabled if the mercurial version is at least
2.2.0, and if the current revision is not public, is not a patch and has no
children. [...]
Clicking the button will call
'commit --amend' to 'amend' the revision.
More info about this on the THG dev channel
I'm tuning into what krtek has written. More specifically solution 1:
Assumptions:
you've committed one (!) changeset but have not pushed it yet
you want to modify this changeset (e.g. add, remove or change files and/or the commit message)
Solution:
use hg rollback to undo the last commit
commit again with the new changes in place
The rollback really undoes the last operation. Its way of working is quite simple: normal operations in HG will only append to files; this includes a commit. Mercurial keeps track of the file lengths of the last transaction and can therefore completely undo one step by truncating the files back to their old lengths.
Assuming that you have not yet propagated your changes, here is what you can do.
Add to your .hgrc:
[extensions]
mq =
In your repository:
hg qimport -r0:tip
hg qpop -a
Of course you need not start with revision zero or pop all patches, for the last just one pop (hg qpop) suffices (see below).
remove the last entry in the .hg/patches/series file, or the patches you do not like. Reordering is possible too.
hg qpush -a; hg qfinish -a
remove the .diff files (unapplied patches) still in .hg/patches (should be one in your case).
If you don't want to take back all of your patch, you can edit it by using hg qimport -r0:tip (or similar), then edit stuff and use hg qrefresh to merge the changes into the topmost patch on your stack. Read hg help qrefresh.
By editing .hg/patches/series, you can even remove several patches, or reorder some. If your last revision is 99, you may just use hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.
Of course, this procedure is highly discouraged and risky. Make a backup of everything before you do this!
As a sidenote, I've done it zillions of times on private-only repositories.
Recent versions of Mercurial include the evolve extension which provides the hg amend command. This allows amending a commit without losing the pre-amend history in your version control.
hg amend [OPTION]... [FILE]...
aliases: refresh
combine a changeset with updates and replace it with a new one
Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.
See 'hg commit' for details about committing changes.
If you don't specify -m, the parent's message will be reused.
Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).
See https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolve for a complete description of the evolve extension.
Might not solve all the problems in the original question, but since this seems to be the de facto post on how mercurial can amend to previous commit, I'll add my 2 cents worth of information.
If you are like me, and only wish to modify the previous commit message (fix a typo etc) without adding any files, this will work
hg commit -X 'glob:**' --amend
Without any include or exclude patterns hg commit will by default include all files in working directory. Applying pattern -X 'glob:**' will exclude all possible files, allowing only to modify the commit message.
Functionally it is same as git commit --amend when there are no files in index/stage.
Another solution could be use the uncommit command to exclude specific file from current commit.
hg uncommit [file/directory]
This is very helpful when you want to keep current commit and deselect some files from commit (especially helpful for files/directories have been deleted).

Mercurial cherry picking changes for commit

Say, I made many changes to my code and only need to commit a few of those changes. Is there a way to do it in mercurial? I know that darcs has a feature like this one.
I know hg transplant can do this between branches, but I need something like this for committing code in the present branch and not when adding change sets from some other branch.
If you are using TortoiseHg 1.x for Windows, this feature is implemented beautifully right out of the box (no extensions required).
Run the TortoiseHg Commit Tool.
Choose a file for which you only
want to commit a subset of its
changes.
Click on the Hunk
Selection tab in the preview pane.
Double-click or use the spacebar to
toggle which change hunks should be
included in the commit.
For TortoiseHg 2.x, the Hunk Selection tab is now gone. In its place, is the Shelve tool. It has a few more features than the old hunk selection. Those new features come at the cost of some added complexity.
Note that there is no need to explicitly enable the Mercurial Shelve extension when using this feature. According to Steve Borho (lead TortoiseHg developer) in response to a different TortoiseHg question: "We have a local copy of the shelve extension and call into it directly."
For TortoiseHg 2.7+, this functionality has been improved and re-introduced. It is now built directly into the Commit tool:
Notice in the file list on the left that the top file is checked to indicate it will be included, the second file is unchecked because it will not be included, and the third file, Sample.txt, is filled (the Null checkbox indicator) because only select changes from that file will be included in the commit.
The change to Sample.txt that will be included is checked in the lower-right change selection portion of the image. The change that will be excluded is unchecked and the diff view is grayed out. Also notice that the icon for the shelve tool is still readily available.
MQ as Chad mentioned are one way. There's also more lightweight solutions:
Record extension which works roughly the same way as darcs record. It's distributed with mercurial.
Shelve extension which allows you to "shelve" certain changes, allowing you to commit only a subset of your changes (the ones that are not shelved)
I feel like I'm missing something because nobody has suggested this already.
The normal "hg commit" command can be used to selectively choose what to commit (you don't have to commit all pending changes in the local working directory).
If you have a set of changes like so:
M ext-web/docroot/WEB-INF/liferay-display.xml
M ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
M ext-web/docroot/WEB-INF/portlet-ext.xml
You can commit just two of those changes with...
hg commit -m "partial commit of working dir changes" ext-web/docroot/WEB-INF/liferay-display.xml ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
Not super convenient from the command line because you have to hand-type the files to selectively commit (vs a GUI check-box process like tortoise) but it's about as straightforward as it gets and requires no extensions. And file-globbing can probably help reduce typing (as it would above, both committed files uniquely share "liferay" in their pathnames.
The Mercurial Queues tutorial is terrible for this use case. All the examples I have seen assume you have yet to make a commit and you are refreshing a single patch. Most of the time this is not the case, and you have 2 or 3 commits that you want to squash together or change in some other way.
Lets say you have this sort of history:
---O---O---A---B---C
The first example is to squash commits A, B, and C. First init mq:
$ hg qinit
Now we need to "import" the commits A, B and C into the patch queue. Lets assume they are the last 3 commits. We can use the "-N" revision syntax to import them like so:
$ hg qimport -r -3:-1
That means import as patches from 3 patches back up to the last commit. You can check the status of these patches with hg qseries. It should show something like this:
$ hg qseries
101.diff
102.diff
103.diff
Where the numbers 101, 102 and 103 correspond to the local revision numbers of the commits A, B and C. Now these patches are applied, which means the changes that they describe are already in the working copy. You can get rid of the changes the working copy and remove them from the history of commits, saving them in patch form only, by using hg qpop. You can either say hg qpop; hg qpop to pop changes C and B off the stack, or specify a patch to "pop to". In this case, it would be something like this:
$ hg qpop 101.diff
now at: 101.diff
You now have the patches for commits B and C in the patch queue, but they are not applied (their changes have been "lost" - they only exist in the patch queue area). Now you can fold these patches into the last one, i.e. we create a new commit that is the equivalent of the sum of the changes A+B+C.
$ hg qfold -e 102.diff 103.diff
This will show your editor so you can change the commit message. By default the message will be the concatenation of the commit messages for the changes A, B and C, separated by asterisks. The nice thing here is that hg qfold will tab-complete the patches if you are using bash and have the hg-completion script sourced. This leaves the history like this, where A+B+C is a single commit that is the combination of the 3 patches that interest us:
---O---O---A+B+C
Another use case is if we have the same sort of history as before, but we want to drop patch B and merge A+C. This is pretty similar to above actually. When you get to the qfold step, you would simply fold in the last commit rather than the last 2 commits:
$ hg qfold -e 103.diff
This leaves the change for B in the patch queue, but it is not applied to the working copy and its commit is not in the history. You can see this by running:
$ hg qunapplied
102.diff
The history now looks like this, where A+C is a single commit that combines changes A and C:
---O---O---A+C
A final use case might be that you need to apply only commit C. You'd do this by running the qimport as above, and you would pop off all patches you didn't want:
$ hg qpop -a
The -a flag means pop off all patches. Now you can apply just the one you do want:
$ hg qpush 103.diff
This leaves you with this history:
---O---O---C
Once you are done with all this, you need to finish off the queue fiddling. This can be done with:
$ hg qfinish -a
So there we are. You can now run hg push and only commit exactly what you want, or hg email a coherent patch to the mailing list.
Some time has passed. Seems the best option now is hg commit --interactive
You can use the record extension, which is distributed with Mercurial.
You need to enable it in your ~/.hgrc file first, by adding it to the [extensions] section:
[extensions]
record=
Then, just type hg record instead of hg commit, and you will be able to select which changes to which files you want to commit.
You can also use the crecord extension which provides a nicer interface to review and select the changes. (It is not distributed with Mercurial, though, and I've seen it occasionally mess up a commit so it's not completely bug-free.)
I believe Mercurial Queues fills this role for Mercurial. There's a pretty good tutorial linked there.
Try qct (Qt Commit Tool). It has a "select changes" feature that starts up a 3-way merge tool for you to undo individual changes. After you commit, those changes you "undid" come back.
I use commit-patch. It's a script that lets you edit the diff before committing. It's really nice with Emacs's diff-mode and vc-mode.
In the past I used crecord, but it has bugs related to unicode (actually the record extension has the bugs, which crecord depends on).
First you must forget everything you ever knew about GUI's and return to the commandline. Next from the commandline do this:
hg stat > filelist.txt
This pipes all your modified files into a text file called filelist.txt
Next edit your filelist to include only the files you wish to commit.
Finally commit using the fileset sytnax:
hg commit "set: 'listfile:test.txt'"