[PATCH 2 of 2] mq: automatically upgrade to git patch when necessary (issue767)

Patrick Mezard pmezard at gmail.com
Wed Dec 30 11:38:23 CST 2009


# HG changeset patch
# User Patrick Mezard <pmezard at gmail.com>
# Date 1262194557 -3600
# Node ID 986e2d6e6eebc8acf5b07b9fb5298bcd2cef966e
# Parent  81c70639660b227332226cf2679e5c4f698fb486
mq: automatically upgrade to git patch when necessary (issue767)

diff --git a/hgext/mq.py b/hgext/mq.py
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -26,6 +26,18 @@
   add known patch to applied stack          qpush
   remove patch from applied stack           qpop
   refresh contents of top applied patch     qrefresh
+
+By default, mq will automatically use git patches when required to
+avoid losing changes to file modes, copy records or binary files. This
+behaviour can be configured with::
+
+  [mq]
+  git = auto/keep/yes/no
+
+If set to 'keep', mq will obey the [diff] section configuration while
+preserving existing git patches upon qrefresh. If set to 'yes' or
+'no', mq will override the [diff] section and always generate git or
+regular patches, possibly losing data in the second case.
 '''
 
 from mercurial.i18n import _
@@ -226,6 +238,14 @@
         self.active_guards = None
         self.guards_dirty = False
         self._diffopts = None
+        # Handle mq.git as a bool with extended values
+        try:
+            gitmode = ui.configbool('mq', 'git', None)
+            if gitmode is None:
+                raise error.ConfigError()
+            self.gitmode = gitmode and 'yes' or 'no'
+        except error.ConfigError:
+            self.gitmode = ui.config('mq', 'git', 'auto').lower()
 
     @util.propertycache
     def applied(self):
@@ -261,7 +281,17 @@
 
     def diffopts(self):
         if self._diffopts is None:
-            self._diffopts = patch.diffopts(self.ui)
+            opts = patch.diffopts(self.ui)
+            if self.gitmode == 'auto':
+                opts.upgrade = True
+            elif self.gitmode == 'keep':
+                pass
+            elif self.gitmode in ('yes', 'no'):
+                opts.git = self.gitmode == 'yes'
+            else:
+                raise util.Abort(_('mq.git option can be auto/keep/yes/no'
+                                   ' got %s') % self.gitmode)
+            self._diffopts = opts
         return self._diffopts
 
     def join(self, *p):
@@ -1167,12 +1197,13 @@
                 ph.setdate(newdate)
 
             # if the patch was a git patch, refresh it as a git patch
-            patchf = self.opener(patchfn, 'r')
-            for line in patchf:
-                if line.startswith('diff --git'):
-                    self.diffopts().git = True
-                    break
-            patchf.close()
+            if not self.diffopts().git and self.gitmode == 'keep':
+                patchf = self.opener(patchfn, 'r')
+                for line in patchf:
+                    if line.startswith('diff --git'):
+                        self.diffopts().git = True
+                        break
+                patchf.close()
 
             # only commit new patch when write is complete
             patchf = self.opener(patchfn, 'w', atomictemp=True)
@@ -1253,7 +1284,7 @@
                     patchf.write(chunk)
 
                 try:
-                    if self.diffopts().git:
+                    if self.diffopts().git or self.diffopts().upgrade:
                         copies = {}
                         for dst in a:
                             src = repo.dirstate.copied(dst)
diff --git a/tests/test-mq-eol b/tests/test-mq-eol
--- a/tests/test-mq-eol
+++ b/tests/test-mq-eol
@@ -4,6 +4,8 @@
 
 echo "[extensions]" >> $HGRCPATH
 echo "mq=" >> $HGRCPATH
+echo "[diff]" >> $HGRCPATH
+echo "nodates=1" >> $HGRCPATH
 
 cat > makepatch.py <<EOF
 f = file('eol.diff', 'wb')
diff --git a/tests/test-mq-eol.out b/tests/test-mq-eol.out
--- a/tests/test-mq-eol.out
+++ b/tests/test-mq-eol.out
@@ -23,7 +23,7 @@
 now at: eol.diff
 test message<LF>
 <LF>
-diff --git a/a b/a<LF>
+diff -r 0d0bf99a8b7a a<LF>
 --- a/a<LF>
 +++ b/a<LF>
 @@ -1,5 +1,5 @@<LF>
diff --git a/tests/test-mq-git b/tests/test-mq-git
new file mode 100755
--- /dev/null
+++ b/tests/test-mq-git
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+# Test the plumbing of mq.git option
+# Automatic upgrade itself is tested elsewhere.
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+echo "[diff]" >> $HGRCPATH
+echo "nodates=1" >> $HGRCPATH
+
+hg init repo-auto
+cd repo-auto
+echo '% git=auto: regular patch creation'
+echo exec > exec
+hg add exec
+hg qnew -d '0 0' -f exec
+cat .hg/patches/exec
+echo '% git=auto: git patch after qrefresh and execute bit'
+chmod +x exec
+hg qrefresh -d '0 0' 
+cat .hg/patches/exec
+echo '% git=auto: git patch when using --git'
+echo regular > regular
+hg add regular
+hg qnew -d '0 0' --git -f git
+cat .hg/patches/git
+echo '% git=auto: regular patch after qrefresh without --git'
+hg qrefresh -d '0 0' 
+cat .hg/patches/git
+cd ..
+
+hg init repo-keep
+cd repo-keep
+echo '[mq]' > .hg/hgrc
+echo 'git = KEEP' >> .hg/hgrc
+echo '% git=keep: git patch with --git'
+echo a > a
+hg add a
+hg qnew -d '0 0' -f --git git
+cat .hg/patches/git
+echo '% git=keep: git patch after qrefresh without --git'
+echo a >> a
+hg qrefresh -d '0 0'
+cat .hg/patches/git
+cd ..
+
+hg init repo-yes
+cd repo-yes
+echo '[mq]' > .hg/hgrc
+echo 'git = yes' >> .hg/hgrc
+echo '% git=yes: git patch'
+echo a > a
+hg add a
+hg qnew -d '0 0' -f git
+cat .hg/patches/git
+echo '% git=yes: git patch after qrefresh'
+echo a >> a
+hg qrefresh -d '0 0'
+cat .hg/patches/git
+cd ..
+
+hg init repo-no
+cd repo-no
+echo '[diff]' > .hg/hgrc
+echo 'git = True' >> .hg/hgrc
+echo '[mq]' > .hg/hgrc
+echo 'git = False' >> .hg/hgrc
+echo '% git=no: regular patch with execute bit'
+echo a > a
+chmod +x a
+hg add a
+hg qnew -d '0 0' -f regular
+cat .hg/patches/regular
+echo '% git=no: regular patch after qrefresh with execute bit'
+echo a >> a
+chmod +x a
+hg qrefresh -d '0 0'
+cat .hg/patches/regular
+cd ..
\ No newline at end of file
diff --git a/tests/test-mq-git.out b/tests/test-mq-git.out
new file mode 100644
--- /dev/null
+++ b/tests/test-mq-git.out
@@ -0,0 +1,99 @@
+% git=auto: regular patch creation
+# HG changeset patch
+# Date 0 0
+
+diff -r 000000000000 -r 644b415993cd exec
+--- /dev/null
++++ b/exec
+@@ -0,0 +1,1 @@
++exec
+% git=auto: git patch after qrefresh and execute bit
+# HG changeset patch
+# Date 0 0
+
+diff --git a/exec b/exec
+new file mode 100755
+--- /dev/null
++++ b/exec
+@@ -0,0 +1,1 @@
++exec
+% git=auto: git patch when using --git
+# HG changeset patch
+# Date 0 0
+
+diff --git a/regular b/regular
+new file mode 100644
+--- /dev/null
++++ b/regular
+@@ -0,0 +1,1 @@
++regular
+% git=auto: regular patch after qrefresh without --git
+# HG changeset patch
+# Date 0 0
+
+diff -r 871825a6bc1e regular
+--- /dev/null
++++ b/regular
+@@ -0,0 +1,1 @@
++regular
+% git=keep: git patch with --git
+# HG changeset patch
+# Date 0 0
+
+diff --git a/a b/a
+new file mode 100644
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++a
+% git=keep: git patch after qrefresh without --git
+# HG changeset patch
+# Date 0 0
+
+diff --git a/a b/a
+new file mode 100644
+--- /dev/null
++++ b/a
+@@ -0,0 +1,2 @@
++a
++a
+% git=yes: git patch
+# HG changeset patch
+# Date 0 0
+
+diff --git a/a b/a
+new file mode 100644
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++a
+% git=yes: git patch after qrefresh
+# HG changeset patch
+# Date 0 0
+
+diff --git a/a b/a
+new file mode 100644
+--- /dev/null
++++ b/a
+@@ -0,0 +1,2 @@
++a
++a
+% git=no: regular patch with execute bit
+# HG changeset patch
+# Date 0 0
+
+diff -r 000000000000 -r d27466151582 a
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++a
+% git=no: regular patch after qrefresh with execute bit
+# HG changeset patch
+# Date 0 0
+
+diff -r 000000000000 a
+--- /dev/null
++++ b/a
+@@ -0,0 +1,2 @@
++a
++a
diff --git a/tests/test-mq.out b/tests/test-mq.out
--- a/tests/test-mq.out
+++ b/tests/test-mq.out
@@ -21,6 +21,18 @@
   remove patch from applied stack           qpop
   refresh contents of top applied patch     qrefresh
 
+By default, mq will automatically use git patches when required to avoid
+losing changes to file modes, copy records or binary files. This behaviour can
+be configured with:
+
+  [mq]
+  git = auto/keep/yes/no
+
+If set to 'keep', mq will obey the [diff] section configuration while
+preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq
+will override the [diff] section and always generate git or regular patches,
+possibly losing data in the second case.
+
 list of commands:
 
  qapplied     print the patches already applied


More information about the Mercurial-devel mailing list