{"thread":{"id":"17700","subject":"[StGit PATCH] Add mergetool support to the classic StGit infrastructure","startedAt":"2009-02-10T14:14:17Z","lastAt":"2009-02-11T09:27:41Z","messageCount":3,"participants":["Catalin Marinas","Karl Hasselström"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"104011","messageId":"20090210141413.28782.19243.stgit@pc1117.cambridge.arm.com","threadId":"17700","inReplyTo":null,"subject":"[StGit PATCH] Add mergetool support to the classic StGit infrastructure","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@arm.com","sentAt":"2009-02-10T14:14:17Z","receivedAt":"2009-02-10T14:14:17Z","isPatch":true,"sender":{"key":"catalin.marinas@arm.com","avatar":null},"body":"Since Git already has a tool for interactively solving conflicts which\nis highly customisable, there is no need to duplicate this feature via\nthe i3merge and i2merge configuration options. The user-visible change\nis that now mergetool is invoked rather than the previously customised\ninteractive merging tool.\n\nThe stgit.keeporig option is no longer available to be more consistent\nwith the Git behaviour.\n\nSigned-off-by: Catalin Marinas <catalin.marinas@gmail.com>\n---\n examples/gitconfig         |   21 +-----\n stgit/commands/resolved.py |    5 -\n stgit/config.py            |    1 \n stgit/git.py               |   17 +++--\n stgit/gitmergeonefile.py   |  150 --------------------------------------------\n t/t0002-status.sh          |    3 -\n 6 files changed, 13 insertions(+), 184 deletions(-)\n delete mode 100644 stgit/gitmergeonefile.py\n\ndiff --git a/examples/gitconfig b/examples/gitconfig\nindex 9efc089..2afc87a 100644\n--- a/examples/gitconfig\n+++ b/examples/gitconfig\n@@ -64,27 +64,10 @@\n \t# To support local parent branches:\n \t#pull-policy = rebase\n \n-\t# Interactive two/three-way merge tool. It is executed by the\n-\t# 'resolved --interactive' command\n-\t#i3merge = xxdiff --title1 current --title2 ancestor --title3 patched \\\n-\t#\t--show-merged-pane -m -E -O -X -M \\\"%(output)s\\\" \\\n-\t#\t\\\"%(branch1)s\\\" \\\"%(ancestor)s\\\" \\\"%(branch2)s\\\"\n-\t#i2merge = xxdiff --title1 current --title2 patched \\\n-\t#\t--show-merged-pane -m -E -O -X -M \\\"%(output)s\\\" \\\n-\t#\t\\\"%(branch1)s\\\" \\\"%(branch2)s\\\"\n-\t#i3merge = emacs --eval '(ediff-merge-files-with-ancestor \\\n-\t#\t\\\"%(branch1)s\\\" \\\"%(branch2)s\\\" \\\"%(ancestor)s\\\" nil \\\n-\t#\t\\\"%(output)s\\\")'\n-\t#i2merge = emacs --eval '(ediff-merge-files \\\n-\t#\t\\\"%(branch1)s\\\" \\\"%(branch2)s\\\" nil \\\"%(output)s\\\")'\n-\n-\t# Automatically invoke the interactive merger in case of conflicts\n+\t# Automatically invoke the interactive merger (git mergetool) in case\n+\t# of conflicts\n \t#autoimerge = no\n \n-\t# Leave the original files in the working tree in case of a\n-\t# merge conflict\n-\t#keeporig = yes\n-\n \t# Optimize (repack) the object store after every pull\n \t#keepoptimized = yes\n \ndiff --git a/stgit/commands/resolved.py b/stgit/commands/resolved.py\nindex 2ce7ec3..eba778d 100644\n--- a/stgit/commands/resolved.py\n+++ b/stgit/commands/resolved.py\n@@ -22,7 +22,6 @@ from stgit.commands.common import *\n from stgit.utils import *\n from stgit import argparse, stack, git, basedir\n from stgit.config import config, file_extensions\n-from stgit.gitmergeonefile import interactive_merge\n \n help = 'Mark a file conflict as solved'\n kind = 'wc'\n@@ -78,8 +77,6 @@ def func(parser, options, args):\n \n     # resolved\n     if options.interactive:\n-        for filename in files:\n-            interactive_merge(filename)\n-            git.resolved([filename])\n+        git.mergetool(files)\n     else:\n         git.resolved(files, options.reset)\ndiff --git a/stgit/config.py b/stgit/config.py\nindex 05ef624..efce097 100644\n--- a/stgit/config.py\n+++ b/stgit/config.py\n@@ -35,7 +35,6 @@ class GitConfig:\n         'stgit.fetchcmd':\t'git fetch',\n         'stgit.pull-policy':\t'pull',\n         'stgit.autoimerge':\t'no',\n-        'stgit.keeporig':\t'yes',\n         'stgit.keepoptimized':\t'no',\n         'stgit.extensions':\t'.ancestor .current .patched',\n         'stgit.shortnr':\t '5'\ndiff --git a/stgit/git.py b/stgit/git.py\nindex 4d01fc2..fb3932d 100644\n--- a/stgit/git.py\n+++ b/stgit/git.py\n@@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n \"\"\"\n \n-import sys, os, re, gitmergeonefile\n+import sys, os, re\n from shutil import copyfile\n \n from stgit.exception import *\n@@ -635,16 +635,20 @@ def merge_recursive(base, head1, head2):\n         conflicts = [l.strip() for l in output if l.startswith('CONFLICT')]\n         out.info(*conflicts)\n \n-        # try the interactive merge or stage checkout (if enabled)\n-        for filename in get_conflicts():\n-            if (gitmergeonefile.merge(filename)):\n-                # interactive merge succeeded\n-                resolved([filename])\n+        # try the interactive merge (if enabled)\n+        if config.get('stgit.autoimerge') == 'yes':\n+            mergetool()\n \n         # any conflicts left unsolved?\n         cn = len(get_conflicts())\n         if cn:\n             raise GitException, \"%d conflict(s)\" % cn\n+ \n+def mergetool(self, files = []):\n+    \"\"\"Invoke 'git mergetool' to resolve any outstanding conflicts.\"\"\"\n+    err = os.system('git mergetool %s' % ' '.join(files))\n+    if err:\n+        raise GitException('\"git mergetool\" failed, exit code: %d' % err)\n \n def diff(files = None, rev1 = 'HEAD', rev2 = None, diff_flags = [],\n          binary = True):\n@@ -754,7 +758,6 @@ def resolved(filenames, reset = None):\n              '--stdin', '-z').input_nulterm(filenames).no_output()\n     GRun('update-index', '--add', '--').xargs(filenames)\n     for filename in filenames:\n-        gitmergeonefile.clean_up(filename)\n         # update the access and modificatied times\n         os.utime(filename, None)\n \ndiff --git a/stgit/gitmergeonefile.py b/stgit/gitmergeonefile.py\ndeleted file mode 100644\nindex 1fe226e..0000000\n--- a/stgit/gitmergeonefile.py\n+++ /dev/null\n@@ -1,150 +0,0 @@\n-\"\"\"Performs a 3-way merge for GIT files\n-\"\"\"\n-\n-__copyright__ = \"\"\"\n-Copyright (C) 2006, Catalin Marinas <catalin.marinas@gmail.com>\n-\n-This program is free software; you can redistribute it and/or modify\n-it under the terms of the GNU General Public License version 2 as\n-published by the Free Software Foundation.\n-\n-This program is distributed in the hope that it will be useful,\n-but WITHOUT ANY WARRANTY; without even the implied warranty of\n-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n-GNU General Public License for more details.\n-\n-You should have received a copy of the GNU General Public License\n-along with this program; if not, write to the Free Software\n-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n-\"\"\"\n-\n-import sys, os\n-from stgit.exception import *\n-from stgit import basedir\n-from stgit.config import config, file_extensions, ConfigOption\n-from stgit.utils import append_string\n-from stgit.out import *\n-from stgit.run import *\n-\n-class GitMergeException(StgException):\n-    pass\n-\n-\n-#\n-# Options\n-#\n-autoimerge = ConfigOption('stgit', 'autoimerge')\n-keeporig = ConfigOption('stgit', 'keeporig')\n-\n-#\n-# Utility functions\n-#\n-def __str2none(x):\n-    if x == '':\n-        return None\n-    else:\n-        return x\n-\n-class MRun(Run):\n-    exc = GitMergeException # use a custom exception class on errors\n-\n-def __checkout_stages(filename):\n-    \"\"\"Check-out the merge stages in the index for the give file\n-    \"\"\"\n-    extensions = file_extensions()\n-    line = MRun('git', 'checkout-index', '--stage=all', '--', filename\n-                ).output_one_line()\n-    stages, path = line.split('\\t')\n-    stages = dict(zip(['ancestor', 'current', 'patched'],\n-                      stages.split(' ')))\n-\n-    for stage, fn in stages.iteritems():\n-        if stages[stage] == '.':\n-            stages[stage] = None\n-        else:\n-            newname = filename + extensions[stage]\n-            if os.path.exists(newname):\n-                # remove the stage if it is already checked out\n-                os.remove(newname)\n-            os.rename(stages[stage], newname)\n-            stages[stage] = newname\n-\n-    return stages\n-\n-def __remove_stages(filename):\n-    \"\"\"Remove the merge stages from the working directory\n-    \"\"\"\n-    extensions = file_extensions()\n-    for ext in extensions.itervalues():\n-        fn = filename + ext\n-        if os.path.isfile(fn):\n-            os.remove(fn)\n-\n-def interactive_merge(filename):\n-    \"\"\"Run the interactive merger on the given file. Stages will be\n-    removed according to stgit.keeporig. If successful and stages\n-    kept, they will be removed via git.resolved().\n-    \"\"\"\n-    stages = __checkout_stages(filename)\n-\n-    try:\n-        # Check whether we have all the files for the merge.\n-        if not (stages['current'] and stages['patched']):\n-            raise GitMergeException('Cannot run the interactive merge')\n-\n-        if stages['ancestor']:\n-            three_way = True\n-            files_dict = {'branch1': stages['current'],\n-                          'ancestor': stages['ancestor'],\n-                          'branch2': stages['patched'],\n-                          'output': filename}\n-            imerger = config.get('stgit.i3merge')\n-        else:\n-            three_way = False\n-            files_dict = {'branch1': stages['current'],\n-                          'branch2': stages['patched'],\n-                          'output': filename}\n-            imerger = config.get('stgit.i2merge')\n-\n-        if not imerger:\n-            raise GitMergeException, 'No interactive merge command configured'\n-\n-        mtime = os.path.getmtime(filename)\n-\n-        out.start('Trying the interactive %s merge'\n-                  % (three_way and 'three-way' or 'two-way'))\n-        err = os.system(imerger % files_dict)\n-        out.done()\n-        if err != 0:\n-            raise GitMergeException, 'The interactive merge failed'\n-        if not os.path.isfile(filename):\n-            raise GitMergeException, 'The \"%s\" file is missing' % filename\n-        if mtime == os.path.getmtime(filename):\n-            raise GitMergeException, 'The \"%s\" file was not modified' % filename\n-    finally:\n-        # keep the merge stages?\n-        if str(keeporig) != 'yes':\n-            __remove_stages(filename)\n-\n-def clean_up(filename):\n-    \"\"\"Remove merge conflict stages if they were generated.\n-    \"\"\"\n-    if str(keeporig) == 'yes':\n-        __remove_stages(filename)\n-\n-def merge(filename):\n-    \"\"\"Merge one file if interactive is allowed or check out the stages\n-    if keeporig is set.\n-    \"\"\"\n-    if str(autoimerge) == 'yes':\n-        try:\n-            interactive_merge(filename)\n-        except GitMergeException, ex:\n-            out.error(str(ex))\n-            return False\n-        return True\n-\n-    if str(keeporig) == 'yes':\n-        __checkout_stages(filename)\n-\n-    return False\ndiff --git a/t/t0002-status.sh b/t/t0002-status.sh\nindex ac92aa8..d95a83b 100755\n--- a/t/t0002-status.sh\n+++ b/t/t0002-status.sh\n@@ -107,9 +107,6 @@ test_expect_success 'Make a conflicting patch' '\n '\n \n cat > expected.txt <<EOF\n-? foo/bar.ancestor\n-? foo/bar.current\n-? foo/bar.patched\n A fie\n C foo/bar\n EOF\n"},{"id":"104157","messageId":"20090211092513.GD26136@diana.vm.bytemark.co.uk","threadId":"17700","inReplyTo":"20090210141413.28782.19243.stgit@pc1117.cambridge.arm.com","subject":"Re: [StGit PATCH] Add mergetool support to the classic StGit infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2009-02-11T09:25:13Z","receivedAt":"2009-02-11T09:25:13Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2009-02-10 14:14:17 +0000, Catalin Marinas wrote:\n\n> Since Git already has a tool for interactively solving conflicts\n> which is highly customisable, there is no need to duplicate this\n> feature via the i3merge and i2merge configuration options. The\n> user-visible change is that now mergetool is invoked rather than the\n> previously customised interactive merging tool.\n\nVery good.\n\n> +def mergetool(self, files = []):\n> +    \"\"\"Invoke 'git mergetool' to resolve any outstanding conflicts.\"\"\"\n> +    err = os.system('git mergetool %s' % ' '.join(files))\n> +    if err:\n> +        raise GitException('\"git mergetool\" failed, exit code: %d' % err)\n\nAgain, what happens if \"files\" is not given?\n\n> @@ -754,7 +758,6 @@ def resolved(filenames, reset = None):\n>               '--stdin', '-z').input_nulterm(filenames).no_output()\n>      GRun('update-index', '--add', '--').xargs(filenames)\n>      for filename in filenames:\n> -        gitmergeonefile.clean_up(filename)\n>          # update the access and modificatied times\n>          os.utime(filename, None)\n\nHmm, what does this line do, and why isn't it needed anymore? I don't\nknow this part of StGit, I'm just curious ...\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"104159","messageId":"20090211092741.GE26136@diana.vm.bytemark.co.uk","threadId":"17700","inReplyTo":"20090211092513.GD26136@diana.vm.bytemark.co.uk","subject":"Re: [StGit PATCH] Add mergetool support to the classic StGit infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2009-02-11T09:27:41Z","receivedAt":"2009-02-11T09:27:41Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2009-02-11 10:25:13 +0100, Karl Hasselström wrote:\n\n> On 2009-02-10 14:14:17 +0000, Catalin Marinas wrote:\n>\n> > @@ -754,7 +758,6 @@ def resolved(filenames, reset = None):\n> >               '--stdin', '-z').input_nulterm(filenames).no_output()\n> >      GRun('update-index', '--add', '--').xargs(filenames)\n> >      for filename in filenames:\n> > -        gitmergeonefile.clean_up(filename)\n> >          # update the access and modificatied times\n> >          os.utime(filename, None)\n>\n> Hmm, what does this line do, and why isn't it needed anymore? I\n> don't know this part of StGit, I'm just curious ...\n\nOh, right, it removes the .current/.patched/.ancestor files.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"}]}