How to merge to get rid of head with Mercurial command line, like I can do with TortoiseHg?
Asked Answered
C

3

39

My question is this:

  • If I have two heads (branches with changes) in my Mercurial repository, and I'd like to get rid of one of them, but discard all the changes from that branch instead of merging them into the other, and I can't strip out those changesets so I have to merge, how can I do that with the command line client?

If I have two heads in my Mercurial repository, and use TortoiseHg as my client, the repository might look like this:

two heads

Then I can get rid of the test2 head by doing a merge and discarding. First I would update to the head I'd like to keep (test3 in this case, which in the image above is already the current parent of my working folder). Then I would right-click and select "Merge with...":

merge with...

and in the dialog that pops up I would choose to discard the changes from the merge target (ie. the branch I'd like to discard all the changes from):

merge dialog

After this merge has gone through, all the changes in the test2 head has been discarded, and I can commit. The head has now disappeared, but the changeset is still part of history.

My question is this: How can I do the same thing using only the command line client? I can't find any matching options to the hg merge command:

hg merge [-P] [-f] [[-r] REV]

merge working directory with another revision

... snipped text

options:

 -f --force       force a merge with outstanding changes
 -t --tool VALUE  specify merge tool
 -r --rev REV     revision to merge
 -P --preview     review revisions to merge (no merge is performed)
    --mq          operate on patch repository

use "hg -v help merge" to show global options

Edit: debugsetparents worked nicely:

hg debugsetparents . 1
hg commit -m "merged to get rid of changeset #1"

Edit: Attempt to use the --tool internal:local according to one of the answers:

@echo off

setlocal
if exist repo rd /s /q repo
hg init repo
cd repo

rem revision 0
echo >test1.txt
hg commit -m "test1" --addremove

rem revision 1
echo >test2.txt
hg commit -m "test2" --addremove

rem revision 2
hg update 0
echo >test3.txt
hg commit -m "test3" --addremove

rem now let's get rid of change in revision 1 with merge
hg merge --tool internal:local -r 1
hg commit -m "merged"

dir

output of execution:

[C:\Temp] :test
adding test1.txt
adding test2.txt
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
adding test3.txt
created new head
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

 Volume in drive C is unlabeled      Serial number is 0e17:6aba
 Directory of  C:\Temp\repo\*

16.11.2010  20:05             .
16.11.2010  20:05             ..
16.11.2010  20:05             .hg
16.11.2010  20:05              13  test1.txt
16.11.2010  20:05              13  test2.txt
16.11.2010  20:05              13  test3.txt
                39 bytes in 3 files and 3 dirs    12 288 bytes allocated
    66 600 316 928 bytes free

Here the changes introduced in the 2nd changeset (the one with revision number 1), is now present in the merged changeset. This is not what i wanted.

Cathern answered 16/11, 2010 at 18:41 Comment(0)
S
32

According to TortoiseHG's source, when you check Discard all changes from merge target (other) revision, it uses the hg debugsetparents command:

hg debugsetparents REV1 [REV2]

manually set the parents of the current working directory

    This is useful for writing repository conversion tools, but should be used with care.

    Returns 0 on success.

use "hg -v help debugsetparents" to show global options

To use:

    hg up <revision-to-keep>
    hg debugsetparents <revision-to-keep> <revision-to-throw-away>
    hg commit -m "Merge to discard ..."
Slowly answered 16/11, 2010 at 18:59 Comment(5)
hg debugsetparents . REV2 followed by a hg merge worked nicely, thanks.Cathern
Very useful for an iOS developer we have using MacHG which does not support the "Discard all changes from merge target(other) revision" feature.Idiophone
Just for my own reference (as I am often back here, trying to remember this): one wants to run hg debugsetparents <revision-to-keep> <revision-to-throw-away>. This can be deduced from the help docs but is not exactly obvious.Nolin
I had to use hg debugsetparents . <revision-to-throw-away> followed by hg commit (not merge as stated above), but otherwise no problems.Starknaked
Echoing @WilliamPrice, I thought I'd need to create an empty changeset first and "turn that" into a merge. This acts on the workspace, so you just dbsetparents <keep> <junk> and then commit the merge state with a message about the discard merge.Melodrama
O
4

If you don't want to use debugsetparents, you can manually revert to the changeset you want to keep before committing:

hg merge --tool internal:local -r HEAD_YOU_WANT_TO_DISCARD
hg revert -r 'tip^'
hg commit

Note, however, that this technique is not necessarily the best approach. You may be better off just closing the head:

hg up HEAD_YOU_WANT_TO_DISCARD
hg commit --close-branch

The documentation here is a little misleading; this only closes the specific head, not the entire branch.

Oestrin answered 4/5, 2015 at 14:41 Comment(5)
tip^ didn't work for me, but specifying branch_to_keep instead did. You can also do the revert file-by-file, in case there are some you wanted to keep.Guidry
To get this to work, I had to add -a (--all) to the hg revert before it was willing to run. The result seems to be similar to debugsetparents but just requires more work for me.Tipster
hg revert doesn't remove new files created on discarded branch. So after reverting, and before commit, one must also hg rm all those.Eldest
Regarding close-branch: this is not the same. I use merge in such cases to mark that given version contains equivalent code, or was reviewed to contain all valuable things from closed branch, etc. Also, merging dead branches is more hg heads friendly.Eldest
@Mekk: Of course close-branch is not the same, that's why I prefixed with "merge may not be the best approach." I'm not interested in debating the best option, I'm just trying to show different approaches to the issue. Finally, close-branch removes the head from hg heads, so I have no idea what you mean by "more friendly."Oestrin
A
1

For what it's worth, the latest version of TortoiseHg (5.5.2) doesn't use debugsetparents for this any longer. Its logging output window shows something similar to Kevin's answer:

(For SO purposes, <other_rev> is what's being merged and discarded.)
% hg merge --config=ui.interactive=False --tool=:local --verbose <other_rev>
.... many lines of output ....
% hg revert --all --rev=.
.... many lines of output ....
Arbalest answered 7/10, 2020 at 17:1 Comment(1)
Hm, OK. That probably explains why it doesn't really seem to work properly anymore. Using that option in TortoiseHg now, still results in merge conflicts (!)Turgescent

© 2022 - 2024 — McMap. All rights reserved.