From: Catalin Marinas Date: Mon, 16 Oct 2006 18:36:49 +0000 (+0100) Subject: Add the '--interactive' option to 'resolved' X-Git-Tag: v0.14.3~461 X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/commitdiff_plain/1e0754060c4fbf7a35efc8557e8d798a49103324 Add the '--interactive' option to 'resolved' This options causes the 'resolved' command to run an interactive merge tool like xxdiff or emacs, defined by the 'imerger' variable in the .stgitrc config file. Signed-off-by: Catalin Marinas --- diff --git a/TODO b/TODO index f7e41fe..6e97fbb 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,6 @@ The TODO list before 1.0: - fix StGIT to run correctly in subdirectories - use a separate index for some commands (refresh, fold etc.) so that files already added/removed are not automatically checked in -- interactive resolve command to invoke xxdiff, emacs etc. - debian package support - man page - document the workflow on the StGIT wiki diff --git a/examples/stgitrc b/examples/stgitrc index ed8cc96..cd22e97 100644 --- a/examples/stgitrc +++ b/examples/stgitrc @@ -27,17 +27,18 @@ smtpserver: localhost:25 # this value overrides the default PAGER environment variable #pager: less -S -# Different three-way merge tools below. Uncomment the preferred one. -# Note that the 'output' file contains the same data as 'branch1'. This -# is useful for tools that do not take an output parameter +# The three-way merge tool. Note that the 'output' file contains the +# same data as 'branch1'. This is useful for tools that do not take an +# output parameter merger: diff3 -L current -L ancestor -L patched -m -E \ "%(branch1)s" "%(ancestor)s" "%(branch2)s" > "%(output)s" -#merger: xxdiff --title1 current --title2 ancestor --title3 patched \ +# Interactive three-way merge tool. It is executed by the 'resolved +# --interactive' command +#imerger: xxdiff --title1 current --title2 ancestor --title3 patched \ # --show-merged-pane -m -E -O -X -M "%(output)s" \ # "%(branch1)s" "%(ancestor)s" "%(branch2)s" - -#merger: emacs --eval '(ediff-merge-files-with-ancestor +#imerger: emacs --eval '(ediff-merge-files-with-ancestor # "%(branch1)s" "%(branch2)s" "%(ancestor)s" nil "%(output)s")' # Leave the original files in the working tree in case of a merge conflict diff --git a/stgit/commands/resolved.py b/stgit/commands/resolved.py index 186bc73..ae85f2b 100644 --- a/stgit/commands/resolved.py +++ b/stgit/commands/resolved.py @@ -22,7 +22,7 @@ from optparse import OptionParser, make_option from stgit.commands.common import * from stgit.utils import * from stgit import stack, git, basedir -from stgit.config import file_extensions +from stgit.config import config, file_extensions help = 'mark a file conflict as solved' @@ -37,8 +37,44 @@ options = [make_option('-a', '--all', help = 'mark all conflicts as solved', action = 'store_true'), make_option('-r', '--reset', metavar = '(ancestor|current|patched)', - help = 'reset the file(s) to the given state')] + help = 'reset the file(s) to the given state'), + make_option('-i', '--interactive', + help = 'run the interactive merging tool', + action = 'store_true')] +def interactive_merge(filename): + """Run the interactive merger on the given file + """ + try: + imerger = config.get('stgit', 'imerger') + except Exception, err: + raise CmdException, 'Configuration error: %s' % err + + extensions = file_extensions() + + ancestor = filename + extensions['ancestor'] + current = filename + extensions['current'] + patched = filename + extensions['patched'] + + # check whether we have all the files for a three-way merge + for fn in [filename, ancestor, current, patched]: + if not os.path.isfile(fn): + raise CmdException, \ + 'Cannot run the interactive merger: "%s" missing' % fn + + mtime = os.path.getmtime(filename) + + err = os.system(imerger % {'branch1': current, + 'ancestor': ancestor, + 'branch2': patched, + 'output': filename}) + + if err != 0: + raise CmdException, 'The interactive merger failed: %d' % err + if not os.path.isfile(filename): + raise CmdException, 'The "%s" file is missing' % filename + if mtime == os.path.getmtime(filename): + raise CmdException, 'The "%s" file was not modified' % filename def func(parser, options, args): """Mark the conflict as resolved @@ -47,29 +83,41 @@ def func(parser, options, args): and options.reset not in file_extensions(): raise CmdException, 'Unknown reset state: %s' % options.reset - if options.all: + if options.all and not options.interactive: resolved_all(options.reset) return - if len(args) == 0: + conflicts = git.get_conflicts() + + if len(args) != 0: + files = args + elif options.all: + files = conflicts + else: parser.error('incorrect number of arguments') - conflicts = git.get_conflicts() if not conflicts: raise CmdException, 'No more conflicts' + # check for arguments validity - for filename in args: - if not filename in conflicts: - raise CmdException, 'No conflicts for "%s"' % filename - # resolved - for filename in args: - resolved(filename, options.reset) - del conflicts[conflicts.index(filename)] + if not options.all: + for filename in files: + if not filename in conflicts: + raise CmdException, 'No conflicts for "%s"' % filename - # save or remove the conflicts file - if conflicts == []: - os.remove(os.path.join(basedir.get(), 'conflicts')) - else: - f = file(os.path.join(basedir.get(), 'conflicts'), 'w+') - f.writelines([line + '\n' for line in conflicts]) - f.close() + # resolved + try: + for filename in files: + if options.interactive: + interactive_merge(filename) + resolved(filename, options.reset) + del conflicts[conflicts.index(filename)] + finally: + # save or remove the conflicts file. Needs a finally clause to + # ensure that already solved conflicts are marked + if conflicts == []: + os.remove(os.path.join(basedir.get(), 'conflicts')) + else: + f = file(os.path.join(basedir.get(), 'conflicts'), 'w+') + f.writelines([line + '\n' for line in conflicts]) + f.close() diff --git a/stgit/gitmergeonefile.py b/stgit/gitmergeonefile.py index 136552b..47ad8b8 100644 --- a/stgit/gitmergeonefile.py +++ b/stgit/gitmergeonefile.py @@ -61,18 +61,20 @@ def __checkout_files(orig_hash, file1_hash, file2_hash, """ global orig, src1, src2 + extensions = file_extensions() + if orig_hash: - orig = path + file_extensions()['ancestor'] + orig = path + extensions['ancestor'] tmp = __output('git-unpack-file %s' % orig_hash) os.chmod(tmp, int(orig_mode, 8)) os.renames(tmp, orig) if file1_hash: - src1 = path + file_extensions()['current'] + src1 = path + extensions['current'] tmp = __output('git-unpack-file %s' % file1_hash) os.chmod(tmp, int(file1_mode, 8)) os.renames(tmp, src1) if file2_hash: - src2 = path + file_extensions()['patched'] + src2 = path + extensions['patched'] tmp = __output('git-unpack-file %s' % file2_hash) os.chmod(tmp, int(file2_mode, 8)) os.renames(tmp, src2)