Merge with TAH.
authorBryan O'Sullivan <bos@serpentine.com>
Sat, 13 Aug 2005 15:23:06 -0800
changeset 894 62ec665759f25731cba7287407043b754c539d98
parent 893 36c991554ebb92feae80576ec0c9cc4dccb37e61 (current diff)
parent 866 6d6095823b82f32c7d20230c4b7fc18fe6343dae (diff)
child 895 77b52b864249768a0ec615af331be778fdbb65e9
push id1
push usergszorc@mozilla.com
push dateWed, 18 Mar 2015 16:34:57 +0000
Merge with TAH.
.hgignore
CONTRIBUTORS
TODO
doc/hg.1.txt
mercurial/commands.py
mercurial/hg.py
mercurial/hgweb.py
mercurial/revlog.py
mercurial/util.py
templates/map
tests/test-help
tests/test-help.out
tests/test-merge-revert.out
tests/test-merge-revert2
tests/test-merge-revert2.out
--- a/doc/hg.1.txt
+++ b/doc/hg.1.txt
@@ -504,17 +504,17 @@ SPECIFYING MULTIPLE REVISIONS
     are revision identifiers.  Both BEGIN and END are optional.  If
     BEGIN is not specified, it defaults to revision number 0.  If END
     is not specified, it defaults to the tip.  The range ":" thus
     means "all revisions".
 
     If BEGIN is greater than END, revisions are treated in reverse
     order.
 
-    A range acts as an open interval.  This means that a range of 3:5
+    A range acts as a closed interval.  This means that a range of 3:5
     gives 3, 4 and 5.  Similarly, a range of 4:2 gives 4, 3, and 2.
 
 ENVIRONMENT VARIABLES
 ---------------------
 
 HGEDITOR::
     This is the name of the editor to use when committing. Defaults to the
     value of EDITOR. 
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -392,32 +392,34 @@ class dirstate:
     def copy(self, source, dest):
         self.read()
         self.markdirty()
         self.copies[dest] = source
 
     def copied(self, file):
         return self.copies.get(file, None)
 
-    def update(self, files, state):
+    def update(self, files, state, **kw):
         ''' current states:
         n  normal
         m  needs merging
         r  marked for removal
         a  marked for addition'''
 
         if not files: return
         self.read()
         self.markdirty()
         for f in files:
             if state == "r":
                 self.map[f] = ('r', 0, 0, 0)
             else:
                 s = os.stat(os.path.join(self.root, f))
-                self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime)
+                st_size = kw.get('st_size', s.st_size)
+                st_mtime = kw.get('st_mtime', s.st_mtime)
+                self.map[f] = (state, s.st_mode, st_size, st_mtime)
 
     def forget(self, files):
         if not files: return
         self.read()
         self.markdirty()
         for f in files:
             try:
                 del self.map[f]
@@ -539,46 +541,54 @@ class dirstate:
         for src, fn in util.unique(traverse()):
             fn = util.normpath(fn)
             if seen(fn): continue
             if fn not in dc and self.ignore(fn):
                 continue
             if match(fn):
                 yield src, fn
 
-    def changes(self, files = None, match = util.always):
+    def changes(self, files=None, match=util.always):
         self.read()
         if not files:
             dc = self.map.copy()
         else:
             dc = self.filterfiles(files)
-        lookup, changed, added, unknown = [], [], [], []
+        lookup, modified, added, unknown = [], [], [], []
+        removed, deleted = [], []
 
         for src, fn in self.walk(files, match, dc=dc):
-            try: s = os.stat(os.path.join(self.root, fn))
-            except: continue
-
-            if fn in dc:
-                c = dc[fn]
+            try:
+                s = os.stat(os.path.join(self.root, fn))
+            except OSError:
+                continue
+            if not stat.S_ISREG(s.st_mode):
+                continue
+            c = dc.get(fn)
+            if c:
                 del dc[fn]
-
                 if c[0] == 'm':
-                    changed.append(fn)
+                    modified.append(fn)
                 elif c[0] == 'a':
                     added.append(fn)
                 elif c[0] == 'r':
                     unknown.append(fn)
                 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
-                    changed.append(fn)
-                elif c[1] != s.st_mode or c[3] != s.st_mtime:
+                    modified.append(fn)
+                elif c[3] != s.st_mtime:
                     lookup.append(fn)
             else:
-                if match(fn): unknown.append(fn)
+                unknown.append(fn)
 
-        return (lookup, changed, added, filter(match, dc.keys()), unknown)
+        for fn, c in [(fn, c) for fn, c in dc.items() if match(fn)]:
+            if c[0] == 'r':
+                removed.append(fn)
+            else:
+                deleted.append(fn)
+        return (lookup, modified, added, removed + deleted, unknown)
 
 # used to avoid circular references so destructors work
 def opener(base):
     p = base
     def o(path, mode="r"):
         if p.startswith("http://"):
             f = os.path.join(p, urllib.quote(path))
             return httprangereader.httprangereader(f)
@@ -1619,20 +1629,30 @@ class localrepository:
         # merge the tricky bits
         files = merge.keys()
         files.sort()
         for f in files:
             self.ui.status("merging %s\n" % f)
             m, o, flag = merge[f]
             self.merge3(f, m, o)
             util.set_exec(self.wjoin(f), flag)
-            if moddirstate and mode == 'm':
-                # only update dirstate on branch merge, otherwise we
-                # could mark files with changes as unchanged
-                self.dirstate.update([f], mode)
+            if moddirstate:
+                if mode == 'm':
+                    # only update dirstate on branch merge, otherwise we
+                    # could mark files with changes as unchanged
+                    self.dirstate.update([f], mode)
+                elif p2 == nullid:
+                    # update dirstate from parent1's manifest
+                    m1n = self.changelog.read(p1)[0]
+                    m1 = self.manifest.read(m1n)
+                    f_len = len(self.file(f).read(m1[f]))
+                    self.dirstate.update([f], mode, st_size=f_len, st_mtime=0)
+                else:
+                    self.ui.warn("Second parent without branch merge!?\n"
+                                 "Dirstate for file %s may be wrong.\n" % f)
 
         remove.sort()
         for f in remove:
             self.ui.note("removing %s\n" % f)
             try:
                 os.unlink(f)
             except OSError, inst:
                 self.ui.warn("update failed to remove %s: %s!\n" % (f, inst))
--- a/tests/test-merge-revert.out
+++ b/tests/test-merge-revert.out
@@ -21,17 +21,16 @@ 8633637036c1
 + hg diff
 + hg status
 + hg id
 3aa14bbc23d9 tip
 + hg update -C 0
 + hg update
 merging file1
 + hg diff
-FIXME: This is a known bug:
 + hg status
 + hg id
 3aa14bbc23d9 tip
 + hg revert
 + hg diff
 + hg status
 + hg id
 3aa14bbc23d9 tip
--- a/tests/test-merge-revert2
+++ b/tests/test-merge-revert2
@@ -1,14 +1,15 @@
 #!/bin/sh
 
 mkdir t
 cd t
 hg init
 echo "added file1" > file1
+echo "another line of text" >> file1
 echo "added file2" > file2
 hg add file1 file2
 hg commit -m "added file1 and file2" -d "0 0" -u user
 echo "changed file1" >> file1
 hg commit -m "changed file1" -d "0 0" -u user
 hg -q log
 hg id
 hg update -C 0
--- a/tests/test-merge-revert2.out
+++ b/tests/test-merge-revert2.out
@@ -1,60 +1,60 @@
 + hg init
 + hg add file1 file2
 + hg commit -m added file1 and file2 -d 0 0 -u user
 + hg commit -m changed file1 -d 0 0 -u user
 + hg -q log
-1:3aa14bbc23d90e3f8b5b639b4a43d76509bae76c
-0:8633637036c18f021d771208e16ae3508ab81d28
+1:f4d7a8c73d231bc078e2a5e791325e55e8a4c252
+0:232e179b3f294d467cfa66e1439bc5b0d44e4a93
 + hg id
-3aa14bbc23d9 tip
+f4d7a8c73d23 tip
 + hg update -C 0
 + hg id
-8633637036c1
+232e179b3f29
 + hg id
-8633637036c1+
+232e179b3f29+
 + hg revert
 + hg diff
 + hg status
 + hg id
-8633637036c1
+232e179b3f29
 + hg update
 + hg diff
 + hg status
 + hg id
-3aa14bbc23d9 tip
+f4d7a8c73d23 tip
 + hg update -C 0
 + hg update
 merge: warning: conflicts during merge
 merging file1
 merging file1 failed!
 + hg diff
-diff -r 3aa14bbc23d9 file1
+diff -r f4d7a8c73d23 file1
 --- a/file1
 +++ b/file1
-@@ -1,2 +1,6 @@
+@@ -1,3 +1,7 @@
  added file1
+ another line of text
 +<<<<<<<
 +changed file1 different
 +=======
  changed file1
 +>>>>>>>
 + hg status
 M file1
 + hg id
-3aa14bbc23d9+ tip
+f4d7a8c73d23+ tip
 + hg revert
 + hg diff
-FIXME: This is a known bug:
 + hg status
 + hg id
-3aa14bbc23d9 tip
+f4d7a8c73d23 tip
 + hg revert -r tip
 + hg diff
 + hg status
 + hg id
-3aa14bbc23d9 tip
+f4d7a8c73d23 tip
 + hg update -C
 + hg diff
 + hg status
 + hg id
-3aa14bbc23d9 tip
+f4d7a8c73d23 tip