In Mercurial, can obsolete changesets be forced to become not obsolete?
Asked Answered
V

5

17

In Mercurial changesets with a successor are marked obsolete.

Can this marker be (forcefully) removed somehow?

After using hg strip to remove the successor, the original changeset is still marked as obsolete and extinct). hg evolve refuses to re-create the successor.

Vining answered 9/4, 2015 at 15:6 Comment(0)
T
13

Yes! you can remove obsolescence markers now. Perhaps it wasn't possible in 2015, when the question was asked.

The solution is in the Apr 18, 2018 answer from user377178: hg --hidden debugobsolete --delete <revindex>

Note that you do not use a changeset ID. You must use an index number (at least, with Mercurial 4.1.3). Run hg --hidden debugobsolete --index to get a list of changesets with obsolescence markers. Find the index of the changeset that you want to become non-obsolete, then run hg --hidden debugobsolete --delete <revindex> with the index substituted for revindex. Then your obsolete changeset is no longer obsolete. (It might be in the list multiple times--I have not thoroughly investigated.)

The debugobsolete command is currently not listed in the evolve user guide, even in the section on recovering obsolete changesets. However, it is listed in the Evolve How To guide.

Many thanks to user377178.

Timorous answered 30/1, 2019 at 3:25 Comment(1)
"Find the index of the changeset that you want" is not completely obvious because it's not immediately clear how to read the output from hg --hidden debugobsolete --index. The format appears to be: index obsoleteHash replacementHash ..., where obsoleteHash is the hash for the change you want to un-obsolete.Hurleigh
S
16

You can't unmark a change as obsolete, but you can bring it back to life using "hg touch <rev> --hidden", where touch is a new command that is part of the evolve extension.

FWIW. It's also possible to rebase the obsolete change, but you'll probably get fewer complications if you use touch.

Sophomore answered 9/4, 2015 at 21:57 Comment(3)
Interesting. I tested with two obsolete changesets 2 and 3. hg touch 2::3 --hidden brings back both as 4::5. Just hg touch 2 --hidden and then hg touch 3 --hidden also brings them back as 4 and 5, but 5 is not a descendant of 4. For this reason (and the fact that touch is not available in TortoiseHG yet) I find rebase more convenient actually. Are there any specific complications with rebase to be aware of?Vining
Also for anyone wondering what exactly hg touch does internally, hg log --debug --hidden shows it adds a __touch-noise__=<somenumber> extra property so the changeset hash is different even if all other changeset properties remain the same.Vining
You should be able to add a custom toolbar command to THG which would call touchWorst
T
13

Yes! you can remove obsolescence markers now. Perhaps it wasn't possible in 2015, when the question was asked.

The solution is in the Apr 18, 2018 answer from user377178: hg --hidden debugobsolete --delete <revindex>

Note that you do not use a changeset ID. You must use an index number (at least, with Mercurial 4.1.3). Run hg --hidden debugobsolete --index to get a list of changesets with obsolescence markers. Find the index of the changeset that you want to become non-obsolete, then run hg --hidden debugobsolete --delete <revindex> with the index substituted for revindex. Then your obsolete changeset is no longer obsolete. (It might be in the list multiple times--I have not thoroughly investigated.)

The debugobsolete command is currently not listed in the evolve user guide, even in the section on recovering obsolete changesets. However, it is listed in the Evolve How To guide.

Many thanks to user377178.

Timorous answered 30/1, 2019 at 3:25 Comment(1)
"Find the index of the changeset that you want" is not completely obvious because it's not immediately clear how to read the output from hg --hidden debugobsolete --index. The format appears to be: index obsoleteHash replacementHash ..., where obsoleteHash is the hash for the change you want to un-obsolete.Hurleigh
F
3

I have come up with the following bash function - a hack and likely dependents on mercurial version but has been working well for years. Takes revset as parameter.

function hg_unhide() {
  for i in $(hg --hidden  log --template '{node}\n' -r "$1"); do
    hg --hidden debugobsolete --index | grep $i | awk '{ print $1;}' | \
      xargs -r hg --hidden debugobsolete --delete
  done
}
Fluctuation answered 18/4, 2018 at 14:31 Comment(2)
This worked for me on a merge changeset, which the hg touch command in the other answer fails for (see mercurial-scm.org/pipermail/mercurial-devel/2015-March/… )Flexuous
The link to the hg touch bug is dead. The bug moved to bz.mercurial-scm.org/show_bug.cgi?id=4561Vining
W
3

The current Mercurial documentation Evolve: User Guide has a discussion on this.

Recover an obsolete changeset

Sometimes you might obsolete a changeset, and then change your mind. You’ll probably start looking for an “unobsolete” command to restore a changeset to normal state. For complicated implementation reasons, that command doesn’t exist. ...

Instead, evolve provides a touch command to resurrect an obsolete changeset.

An unexpected quirk: you almost certainly need to use --hidden, since obsolete changesets tend to be hidden, and you can’t reference a hidden changeset otherwise.

Typical usage thus looks like

$ hg --hidden touch REV

This creates a new, normal changeset which is the same as REV—except with a different changeset ID. The new changeset will have the same parent as REV, and will be a successor of REV.

The current implementation of hg touch is not ideal, and is likely to change in the future. ...

(emphasis added)


That said, personally I have found it simpler to graft the obsolete changesets back into usage. You can do this easily in TortoiseHG for example by just selecting the obsoletes that you want and grafting them all in one batch. Grafting may technically work outside (or skirt around) the obsolescence system but given the complexities of using touch as alluded to above I find the simplicity worth it.

Worst answered 28/4, 2022 at 20:2 Comment(0)
W
1

The most current or maybe even "bleeding edge" approach to this seems to be using:

hg rewind

or its alias

hg undo

I say "bleeding edge" because although this command is released and seems to work, I can't find much documented about it, though the hg command line help does include it (below). It may still be considered experimental (as of 2022).

hg rewind seems potentially intended to replace hg touch.


Here's an example of it in use:

% hg rebase --dest=25707 --source=26017 
rebasing 26017:5c78e2af32cb "message 1"
rebasing 26018:f156002253b3 "message 2"
...
[command completed successfully Fri Apr 29 09:07:15 2022]

% hg rewind
rewound to 33 changesets
(33 changesets obsoleted)
working directory is now at 0ad018a90b93

The net effect of these commands were to leave things exactly equivalent to where I started. The rewind took about as long as the rebase.


Built in help states the following:

% hg undo --help
hg rewind [--as-divergence] [--exact] [--keep] [--to REV]... [--from REV]...

aliases: undo

rewind a stack of changesets to a previous state

    This command can be used to restore stacks of changesets to an obsolete
    state, creating identical copies.

    There are two main ways to select the rewind target. Rewinding "from"
    changesets will restore the direct predecessors of these changesets (and
    obsolete the changeset you rewind from). Rewinding "to" will restore the
    changeset you have selected (and obsolete their latest successors).

    By default, we rewind from the working directory parents, restoring its
    predecessor.

    ...


% hg --version
Mercurial Distributed SCM (version 5.9.2)
...

Importantly, the help also includes the following cautions:

Current rough edges:

  • fold: rewinding to only some of the initially folded changesets will be problematic. The fold result is marked obsolete and the part not rewinded to are "lost". Please use --as-divergence when you need to perform such operation.

  • 'hg rewind' might affect changesets outside the current stack. Without --exact, we also restore ancestors of the rewind target, obsoleting their latest successors (unless --as-divergent is provided). In some case, these latest successors will be on branches unrelated to the changeset you rewind from. (We plan to automatically detect this case in the future)


Some Mercurial developer-oriented notes about rewind are:

Worst answered 29/4, 2022 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.