hg unshelve error handling - an example
Faheem Mitha
faheem at faheem.info
Wed May 12 13:45:35 UTC 2021
I recently unshelved in a working directory with the wrong
parent. This is quite easy to do. But it's not so easy to recover
from. The scripts below illustrate the situation I accidentally
created.
The Expect script `shelveinterrupt.exp` calls the shell script
`shelveinterrupt.sh`.
What happened here is that a patch to the file 'foo' was unshelved in
a working directory with a parent that doesn't contain 'foo'. So of
course this caused a problem when trying to merge the patch.
Suppose one does a Ctrl-C on the following dialog.
file 'foo' was deleted in local [working-copy] but was modified in
other [shelve]. You can use (c)hanged version, leave (d)eleted,
or leave (u)nresolved. What do you want to do? interrupted!
This results in a state of conflict.
hg status
# The repository is in an unfinished *update* state.
# Unresolved merge conflicts:
#
# foo
#
# To mark files as resolved: hg resolve --mark FILE
# To continue: hg update .
It requires some effort to return the repository to a sane state.
As can be seen below, one needs to do the following, in that order.
hg resolve -m foo
hg update
hg unshelve # respond with "u"
hg abort
This is perhaps not an entirely obvious sequence of operations. Also,
I believe `hg abort` is relatively new. I'm also not clear why `hg
update` is necessary in this case, as it doesn't actually do anything,
as far as I can tell.
Perhaps Ctrl-C could leave the repository in a better state?
And is there a slicker/better way to fix this situation?
I have written before that I wished that `hg shelve` was a bit more
error-proof, and knowing which parent it belonged to would be a good
start. Or if that was not possible, perhaps it could keep track of
branch or topic name and give a warning if they differ on unshelve?
See for example https://bz.mercurial-scm.org/show_bug.cgi?id=6123.
Regards, Faheem Mitha
#############################
shelveinterrupt.sh
#############################
#!/bin/bash
rm -rf test-shelveinterrupt
hg init test-shelveinterrupt
cd test-shelveinterrupt
hg topics foo
echo "First line of foo" >> foo
hg add foo
hg ci -m "First line of foo" foo
echo "Second line of foo" >> foo
hg shelve
hg up null
hg topics bar
echo "First line of bar" >> bar
hg add bar
hg ci -m "First line of bar" bar
hg unshelve
#############################
#############################
shelveinterrupt.exp
#############################
#!/usr/bin/expect -f
#exp_internal 1
puts "RUNNING SHELVEINTERRUPT.SH SCRIPT"
spawn ./shelveinterrupt.sh
puts "INTERRUPTING PROMPT"
expect "What do you want to do?"
send -- ""
expect eof
cd test-shelveinterrupt
puts "CALLING HG STATUS"
exec hg status >@ stdout 2>@ stderr
puts "CALLING HG RESOLVE -M FOO"
exec hg resolve -m foo >@ stdout 2>@ stderr
puts "CALLING HG UPDATE"
exec hg update >@ stdout 2>@ stderr
puts "CALLING HG UNSHELVE"
spawn hg unshelve
puts "SENDING U TO THE PROMPT"
expect "What do you want to do?"
send -- "u\r"
expect eof
puts "CALLING HG ABORT"
exec hg abort >@ stdout 2>@ stderr
##################################
Output of: TERM=dumb ./shelveinterrupt.exp &> shelveinterrupt.out
##############################################
RUNNING SHELVEINTERRUPT.SH SCRIPT
spawn ./shelveinterrupt.sh
INTERRUPTING PROMPT
marked working directory as topic: foo
active topic 'foo' grew its first changeset
(see 'hg help topics' for more information)
shelved as default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
marked working directory as topic: bar
active topic 'bar' grew its first changeset
(see 'hg help topics' for more information)
unshelving change 'default'
rebasing shelved changes
file 'foo' was deleted in local [working-copy] but was modified in other [shelve].
You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
What do you want to do? interrupted!
CALLING HG STATUS
# The repository is in an unfinished *update* state.
# Unresolved merge conflicts:
#
# foo
#
# To mark files as resolved: hg resolve --mark FILE
# To continue: hg update .
CALLING HG RESOLVE -M FOO
(no more unresolved files)
CALLING HG UPDATE
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
CALLING HG UNSHELVE
spawn hg unshelve
SENDING U TO THE PROMPT
unshelving change 'default'
rebasing shelved changes
file 'foo' was deleted in local [working-copy] but was modified in other [shelve].
You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
What do you want to do? u
unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue')
CALLING HG ABORT
unshelve of 'default' aborted
More information about the Mercurial
mailing list