Angel Ezquerra  committed 8509864

qimport: do not fail to qimport a revision when there is a patch name collision

qimport uses the default names for patches, whose format is "REVISION_NUMBER.diff".
Until this patch if you tried to qimport a revision when there was an existing
mq patch with the same target name, the qimport operation would fail, and there
was no obvious way to work around this problem.

It is easy to come into this problem. For instance, this happens if you qimport
a revision, unapply it, perform a new commit and then you try to qimport the new

This patch solves the problem by checking for name collisions before executing
the qimport command. If there are name collisions it will fall back to a slower
qimport method in which each revision that must be qimported will be imported
individually (starting from the newest), and for each of them thg will try to
find a unique patch name.

  • Participants
  • Parent commits 898d259
  • Branches stable

Comments (0)

Files changed (1)

File tortoisehg/hgqt/

             endrev = 'qparent'
             endrev = ''
-        cmdline = ['qimport', '--rev', '%s::%s' % (self.rev, endrev),
-                   '--repository', self.repo.root]
-        self.runCommand(cmdline)
+        # Check whether there are existing patches in the MQ queue whose name
+        # collides with the revisions that are going to be imported
+        func = hglib.revsetmatch(self.repo.ui, '%s::%s' % (self.rev, endrev))
+        revList = [c for c in func(self.repo, range(len(self.repo)))]
+        revNameSet = set(['%d.diff' % rev for rev in revList])
+        collidingPatchSet = revNameSet.intersection(set(
+        if collidingPatchSet:
+            # We will qimport each revision one by one, starting from the newest
+            # To do so, we will find a valid and unique patch name for each
+            # revision that we must qimport
+            # and then we will import them one by one starting from the newest
+            # one, using these unique names
+            def getUniquePatchName(baseName):
+                patchName = baseName + '.diff'
+                if patchName in collidingPatchSet:
+                    maxRetries = 99
+                    for n in range(1, maxRetries):
+                        patchName = baseName + '_%02d.diff' % n
+                        if not patchName in collidingPatchSet:
+                            break
+                return patchName
+            patchNames = {}
+            revList.reverse()
+            for rev in revList:
+                patchNames[rev] = getUniquePatchName(str(rev))
+            for rev in revList:
+                cmdline = ['qimport', '--rev', '%s' % rev,
+                           '--repository', self.repo.root,
+                           '--name', patchNames[rev]]
+                self.runCommand(cmdline)
+        else:
+            # There were no collisions with existing patch names, we can
+            # simply qimport the whole revision set in a single go
+            cmdline = ['qimport', '--rev', '%s::%s' % (self.rev, endrev),
+                       '--repository', self.repo.root]
+            self.runCommand(cmdline)
     def qfinishRevision(self):
         """Finish applied patches up to and including selected revision"""