Bug 4121 - rebase is halt in confusion when cwd doesn't exist on destination.
Summary: rebase is halt in confusion when cwd doesn't exist on destination.
Status: RESOLVED FIXED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: rebase (show other bugs)
Version: earlier
Hardware: PC Linux
: normal bug
Assignee: Bugzilla
URL:
Keywords:
Depends on:
Blocks: 4869
  Show dependency tree
 
Reported: 2013-12-04 14:31 UTC by Pierre-Yves David
Modified: 2015-09-30 13:12 UTC (History)
2 users (show)

See Also:
Python Version: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Pierre-Yves David 2013-12-04 14:31 UTC
if `--dest` does not contains the current working direct rebase crash and leave the user in a complicated situation. going to repository root and using rebase --continue seems to work fine.

I suspect other command to be affected.

We have multiple options here:
1. automatically update to parent directory if cwd is deleted
2. don't delete the parent directory in that case
3. warn before doing the rebase
4. cleanly abort during the process.
Comment 1 Matt Mackall 2013-12-04 15:00 UTC
What precisely causes the crash? Can you include a trace?

The ideal solution would simply be "don't crash." Deleting the current working directory doesn't usually need to be fatal.
Comment 2 Matt Mackall 2013-12-09 15:39 UTC
Ping.
Comment 3 Pierre-Yves David 2013-12-09 20:54 UTC
I'm using this test script for testing:


  $ cat >> $HGRCPATH <<EOF
  > [extensions]
  > rebase=
  > 
  > [alias]
  > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
  > EOF


  $ hg init a
  $ cd a
  $ touch initial-file
  $ hg add initial-file
  $ hg commit -m 'initial commit'
  $ touch dest-file
  $ hg add dest-file
  $ hg commit -m 'dest commit'
  $ hg up 0
  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
  $ touch other-file
  $ hg add other-file
  $ hg commit -m 'first source commit'
  created new head
  $ mkdir subdir
  $ cd subdir
  $ touch subfile
  $ hg add subfile
  $ hg commit -m 'second source with subdir'
  $ hg rebase -b . -d 1 --traceback


I'm getting the following traceback


+  Traceback (most recent call last):
+    File "/home/pyd/src/mercurial-dev/mercurial/dispatch.py", line 134, in _runcatch
+      return _dispatch(req)
+    File "/home/pyd/src/mercurial-dev/mercurial/dispatch.py", line 807, in _dispatch
+      cmdpats, cmdoptions)
+    File "/home/pyd/src/mercurial-dev/mercurial/dispatch.py", line 586, in runcommand
+      ret = _runcommand(ui, options, cmd, d)
+    File "/home/pyd/src/mercurial-dev/mercurial/dispatch.py", line 898, in _runcommand
+      return checkargs()
+    File "/home/pyd/src/mercurial-dev/mercurial/dispatch.py", line 869, in checkargs
+      return cmdfunc()
+    File "/home/pyd/src/mercurial-dev/mercurial/dispatch.py", line 804, in <lambda>
+      d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
+    File "/home/pyd/src/mercurial-dev/mercurial/util.py", line 512, in check
+      return func(*args, **kwargs)
+    File "/home/pyd/src/mercurial-dev/hgext/rebase.py", line 308, in rebase
+      stats = rebasenode(repo, rev, p1, state, collapsef)
+    File "/home/pyd/src/mercurial-dev/hgext/rebase.py", line 494, in rebasenode
+      return merge.update(repo, rev, True, True, False, base, collapse)
+    File "/home/pyd/src/mercurial-dev/mercurial/merge.py", line 756, in update
+      branchmerge, force, partial, mergeancestor)
+    File "/home/pyd/src/mercurial-dev/mercurial/merge.py", line 566, in calculateupdates
+      partial, acceptremote)
+    File "/home/pyd/src/mercurial-dev/mercurial/merge.py", line 228, in manifestmerge
+      ret = copies.mergecopies(repo, wctx, p2, pa)
+    File "/home/pyd/src/mercurial-dev/mercurial/copies.py", line 208, in mergecopies
+      m1 = c1.manifest()
+    File "/home/pyd/src/mercurial-dev/mercurial/context.py", line 77, in manifest
+      return self._manifest
+    File "/home/pyd/src/mercurial-dev/mercurial/util.py", line 281, in __get__
+      result = self.func(obj)
+    File "/home/pyd/src/mercurial-dev/mercurial/context.py", line 935, in _manifest
+      modified, added, removed, deleted = self._status
+    File "/home/pyd/src/mercurial-dev/mercurial/util.py", line 281, in __get__
+      result = self.func(obj)
+    File "/home/pyd/src/mercurial-dev/mercurial/context.py", line 953, in _status
+      return self._repo.status()[:4]
+    File "/home/pyd/src/mercurial-dev/mercurial/localrepo.py", line 1485, in status
+      match = match or matchmod.always(self.root, self.getcwd())
+    File "/home/pyd/src/mercurial-dev/mercurial/localrepo.py", line 749, in getcwd
+      return self.dirstate.getcwd()
+    File "/home/pyd/src/mercurial-dev/mercurial/dirstate.py", line 166, in getcwd
+      cwd = os.getcwd()
+  OSError: [Errno 2] No such file or directory

So the first to fail is the dirstate code.
Comment 4 Matt Mackall 2014-01-24 17:55 UTC
Possible fix:

diff -r 427d672c0e4e mercurial/dirstate.py
--- a/mercurial/dirstate.py	Sun Nov 24 02:17:17 2013 +0100
+++ b/mercurial/dirstate.py	Fri Jan 24 16:51:20 2014 -0600
@@ -162,8 +162,12 @@
         else:
             return fallback
 
+    @propertycache
+    def _cwd(self):
+        return os.getcwd()
+
     def getcwd(self):
-        cwd = os.getcwd()
+        cwd = self._cwd
         if cwd == self._root:
             return ''
         # self._root ends with a path separator if self._root is '/' or 'C:\'


This caches our notion of cwd at first use. Since we're primarily using this to understand relative paths given as args, this should be fine. But there seem to be a bunch of other getcwd calls around.
Comment 5 Pierre-Yves David 2014-01-31 17:54 UTC
Requires this fix to record


diff --git a/hgext/record.py b/hgext/record.py
--- a/hgext/record.py
+++ b/hgext/record.py
@@ -599,16 +599,12 @@ def dorecord(ui, repo, commitfunc, cmdsu
             #    commit/qrefresh or the like!
 
             # it is important to first chdir to repo root -- we'll call
             # a highlevel command with list of pathnames relative to
             # repo root
-            cwd = os.getcwd()
-            os.chdir(repo.root)
-            try:
-                commitfunc(ui, repo, *newfiles, **opts)
-            finally:
-                os.chdir(cwd)
+            newfiles = [repo.wjoin(nf) for nf in newfiles]
+            commitfunc(ui, repo, *newfiles, **opts)
 
             return 0
         finally:
             # 5. finally restore backed-up files
             try:
Comment 6 HG Bot 2014-01-31 18:45 UTC
Fixed by http://selenic.com/repo/hg/rev/e40520642e64
Pierre-Yves David <pierre-yves.david@logilab.fr>
rebase: do not crash in panic when cwd disapear in the process (issue4121)

Before this patch rebase crashed badly when it happend. (not abort, crash).

Fix courtesy of Matt Mackall.

(please test the fix)