All of lore.kernel.org
 help / color / mirror / Atom feed
* [StGit PATCH 0/5] Various StGit patches
@ 2009-03-12 12:08 Catalin Marinas
  2009-03-12 12:08 ` [StGit PATCH 1/5] Check for local changes with "goto" Catalin Marinas
                   ` (4 more replies)
  0 siblings, 5 replies; 19+ messages in thread
From: Catalin Marinas @ 2009-03-12 12:08 UTC (permalink / raw)
  To: git, Karl Hasselström

Some of these patches were posted before and there were some suggestions
which I added. The "Check for local changes with goto" patch was
slightly improved so that the "stgit.keep" option could be set to "yes"
if this is preferred as a default behaviour.

I plan to implement transition as many commands as possible to the new
infrastructure. For some of them it should be trivial. The "status"
command needs some support in stgit.lib.


Catalin Marinas (5):
      Convert "float" to the lib infrastructure
      Convert "sink" to the new infrastructure
      Add automatic git-mergetool invocation to the new infrastructure
      Add mergetool support to the classic StGit infrastructure
      Check for local changes with "goto"


 examples/gitconfig         |   24 +------
 stgit/argparse.py          |    5 +
 stgit/commands/edit.py     |    2 -
 stgit/commands/float.py    |   75 +++++++++-------------
 stgit/commands/goto.py     |    9 ++-
 stgit/commands/resolved.py |    5 -
 stgit/commands/sink.py     |   86 +++++++++++--------------
 stgit/config.py            |    1 
 stgit/git.py               |   33 ++++++----
 stgit/gitmergeonefile.py   |  150 --------------------------------------------
 stgit/lib/git.py           |   35 +++++++++-
 stgit/lib/transaction.py   |   17 ++++-
 t/t0002-status.sh          |    3 -
 t/t1501-sink.sh            |    2 -
 t/t2300-refresh-subdir.sh  |    2 -
 t/t2800-goto-subdir.sh     |    4 +
 t/t3000-dirty-merge.sh     |    2 -
 17 files changed, 153 insertions(+), 302 deletions(-)
 delete mode 100644 stgit/gitmergeonefile.py

-- 
Catalin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [StGit PATCH 1/5] Check for local changes with "goto"
  2009-03-12 12:08 [StGit PATCH 0/5] Various StGit patches Catalin Marinas
@ 2009-03-12 12:08 ` Catalin Marinas
  2009-03-13  1:57   ` Karl Hasselström
  2009-03-12 12:09 ` [StGit PATCH 2/5] Add mergetool support to the classic StGit infrastructure Catalin Marinas
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-12 12:08 UTC (permalink / raw)
  To: git, Karl Hasselström

This is done by default, unless the --keep option is passed, for
consistency with the "pop" command. The index is checked in the
Transaction.run() function so that other commands could benefit from
this feature (off by default).

This behaviour can be overridden by setting the stgit.autokeep option.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
 examples/gitconfig        |    3 +++
 stgit/argparse.py         |    5 +++++
 stgit/commands/goto.py    |    7 +++++--
 stgit/lib/git.py          |   14 ++++++++++++--
 stgit/lib/transaction.py  |   10 +++++++++-
 t/t2300-refresh-subdir.sh |    2 +-
 t/t2800-goto-subdir.sh    |    4 ++--
 t/t3000-dirty-merge.sh    |    2 +-
 8 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/examples/gitconfig b/examples/gitconfig
index 9efc089..2fc5f52 100644
--- a/examples/gitconfig
+++ b/examples/gitconfig
@@ -103,6 +103,9 @@
 	# -O/--diff-opts). For example, -M turns on rename detection.
 	#diff-opts = -M
 
+	# Behave as if the --keep option is always passed
+	#autokeep = no
+
 [mail "alias"]
 	# E-mail aliases used with the 'mail' command
 	git = git@vger.kernel.org
diff --git a/stgit/argparse.py b/stgit/argparse.py
index 418a506..85ee6e3 100644
--- a/stgit/argparse.py
+++ b/stgit/argparse.py
@@ -220,6 +220,11 @@ def _person_opts(person, short):
 def author_options():
     return _person_opts('author', 'auth')
 
+def keep_option():
+    return [opt('-k', '--keep', action = 'store_true',
+                short = 'Keep the local changes',
+                default = config.get('stgit.autokeep') == 'yes')]
+
 class CompgenBase(object):
     def actions(self, var): return set()
     def words(self, var): return set()
diff --git a/stgit/commands/goto.py b/stgit/commands/goto.py
index 60a917e..0f67314 100644
--- a/stgit/commands/goto.py
+++ b/stgit/commands/goto.py
@@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 from stgit.commands import common
 from stgit.lib import transaction
 from stgit import argparse
+from stgit.argparse import opt
 
 help = 'Push or pop patches to the given one'
 kind = 'stack'
@@ -27,7 +28,7 @@ Push/pop patches to/from the stack until the one given on the command
 line becomes current."""
 
 args = [argparse.other_applied_patches, argparse.unapplied_patches]
-options = []
+options = argparse.keep_option()
 
 directory = common.DirectoryHasRepositoryLib()
 
@@ -38,7 +39,9 @@ def func(parser, options, args):
 
     stack = directory.repository.current_stack
     iw = stack.repository.default_iw
-    trans = transaction.StackTransaction(stack, 'goto')
+    clean_iw = not options.keep and iw or None
+    trans = transaction.StackTransaction(stack, 'goto',
+                                         check_clean_iw = clean_iw)
     if patch in trans.applied:
         to_pop = set(trans.applied[trans.applied.index(patch)+1:])
         assert not trans.pop_patches(lambda pn: pn in to_pop)
diff --git a/stgit/lib/git.py b/stgit/lib/git.py
index e2b4266..07079b8 100644
--- a/stgit/lib/git.py
+++ b/stgit/lib/git.py
@@ -706,9 +706,11 @@ class Index(RunWithEnv):
                     ).output_one_line())
         except run.RunException:
             raise MergeException('Conflicting merge')
-    def is_clean(self):
+    def is_clean(self, tree):
+        """Check whether the index is clean relative to the given treeish."""
         try:
-            self.run(['git', 'update-index', '--refresh']).discard_output()
+            self.run(['git', 'diff-index', '--quiet', '--cached', tree.sha1]
+                    ).discard_output()
         except run.RunException:
             return False
         else:
@@ -858,6 +860,14 @@ class IndexAndWorktree(RunWithEnvCwd):
         cmd = ['git', 'update-index', '--remove']
         self.run(cmd + ['-z', '--stdin']
                  ).input_nulterm(paths).discard_output()
+    def worktree_clean(self):
+        """Check whether the worktree is clean relative to index."""
+        try:
+            self.run(['git', 'update-index', '--refresh']).discard_output()
+        except run.RunException:
+            return False
+        else:
+            return True
 
 class Branch(object):
     """Represents a Git branch."""
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 54de127..5a81f9d 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -75,7 +75,8 @@ class StackTransaction(object):
       your refs and index+worktree, or fail without having done
       anything."""
     def __init__(self, stack, msg, discard_changes = False,
-                 allow_conflicts = False, allow_bad_head = False):
+                 allow_conflicts = False, allow_bad_head = False,
+                 check_clean_iw = None):
         """Create a new L{StackTransaction}.
 
         @param discard_changes: Discard any changes in index+worktree
@@ -102,6 +103,8 @@ class StackTransaction(object):
         self.__temp_index = self.temp_index_tree = None
         if not allow_bad_head:
             self.__assert_head_top_equal()
+        if check_clean_iw:
+            self.__assert_index_worktree_clean(check_clean_iw)
     stack = property(lambda self: self.__stack)
     patches = property(lambda self: self.__patches)
     def __set_applied(self, val):
@@ -147,6 +150,11 @@ class StackTransaction(object):
                 'This can happen if you modify a branch with git.',
                 '"stg repair --help" explains more about what to do next.')
             self.__abort()
+    def __assert_index_worktree_clean(self, iw):
+        if not iw.worktree_clean() or \
+           not iw.index.is_clean(self.stack.head):
+            self.__halt('Repository not clean. Use "refresh" or '
+                        '"status --reset"')
     def __checkout(self, tree, iw, allow_bad_head):
         if not allow_bad_head:
             self.__assert_head_top_equal()
diff --git a/t/t2300-refresh-subdir.sh b/t/t2300-refresh-subdir.sh
index d731a11..89c95db 100755
--- a/t/t2300-refresh-subdir.sh
+++ b/t/t2300-refresh-subdir.sh
@@ -65,7 +65,7 @@ test_expect_success 'refresh -u -p <subdir>' '
 
 test_expect_success 'refresh an unapplied patch' '
     stg refresh -u &&
-    stg goto p0 &&
+    stg goto --keep p0 &&
     test "$(stg status)" = "M foo.txt" &&
     stg refresh -p p1 &&
     test "$(stg status)" = "" &&
diff --git a/t/t2800-goto-subdir.sh b/t/t2800-goto-subdir.sh
index 28b8292..855972b 100755
--- a/t/t2800-goto-subdir.sh
+++ b/t/t2800-goto-subdir.sh
@@ -25,7 +25,7 @@ cat > expected2.txt <<EOF
 bar
 EOF
 test_expect_success 'Goto in subdirectory (just pop)' '
-    (cd foo && stg goto p1) &&
+    (cd foo && stg goto --keep p1) &&
     cat foo/bar > actual.txt &&
     test_cmp expected1.txt actual.txt &&
     ls foo > actual.txt &&
@@ -48,7 +48,7 @@ cat > expected2.txt <<EOF
 bar
 EOF
 test_expect_success 'Goto in subdirectory (conflicting push)' '
-    (cd foo && stg goto p3) ;
+    (cd foo && stg goto --keep p3) ;
     [ $? -eq 3 ] &&
     cat foo/bar > actual.txt &&
     test_cmp expected1.txt actual.txt &&
diff --git a/t/t3000-dirty-merge.sh b/t/t3000-dirty-merge.sh
index f0f79d5..419d86e 100755
--- a/t/t3000-dirty-merge.sh
+++ b/t/t3000-dirty-merge.sh
@@ -26,7 +26,7 @@ test_expect_success 'Push with dirty worktree' '
     echo 4 > a &&
     [ "$(echo $(stg series --applied --noprefix))" = "p1" ] &&
     [ "$(echo $(stg series --unapplied --noprefix))" = "p2" ] &&
-    conflict stg goto p2 &&
+    conflict stg goto --keep p2 &&
     [ "$(echo $(stg series --applied --noprefix))" = "p1" ] &&
     [ "$(echo $(stg series --unapplied --noprefix))" = "p2" ] &&
     [ "$(echo $(cat a))" = "4" ]

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [StGit PATCH 2/5] Add mergetool support to the classic StGit infrastructure
  2009-03-12 12:08 [StGit PATCH 0/5] Various StGit patches Catalin Marinas
  2009-03-12 12:08 ` [StGit PATCH 1/5] Check for local changes with "goto" Catalin Marinas
@ 2009-03-12 12:09 ` Catalin Marinas
  2009-03-13  2:02   ` Karl Hasselström
  2009-03-12 12:09 ` [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure Catalin Marinas
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-12 12:09 UTC (permalink / raw)
  To: git, Karl Hasselström

Since Git already has a tool for interactively solving conflicts which
is highly customisable, there is no need to duplicate this feature via
the i3merge and i2merge configuration options. The user-visible change
is that now mergetool is invoked rather than the previously customised
interactive merging tool.

The stgit.keeporig option is no longer available to be more consistent
with the Git behaviour.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
 examples/gitconfig         |   21 +-----
 stgit/commands/resolved.py |    5 -
 stgit/config.py            |    1 
 stgit/git.py               |   33 ++++++----
 stgit/gitmergeonefile.py   |  150 --------------------------------------------
 t/t0002-status.sh          |    3 -
 6 files changed, 22 insertions(+), 191 deletions(-)
 delete mode 100644 stgit/gitmergeonefile.py

diff --git a/examples/gitconfig b/examples/gitconfig
index 2fc5f52..f6e3a79 100644
--- a/examples/gitconfig
+++ b/examples/gitconfig
@@ -64,27 +64,10 @@
 	# To support local parent branches:
 	#pull-policy = rebase
 
-	# Interactive two/three-way merge tool. It is executed by the
-	# 'resolved --interactive' command
-	#i3merge = xxdiff --title1 current --title2 ancestor --title3 patched \
-	#	--show-merged-pane -m -E -O -X -M \"%(output)s\" \
-	#	\"%(branch1)s\" \"%(ancestor)s\" \"%(branch2)s\"
-	#i2merge = xxdiff --title1 current --title2 patched \
-	#	--show-merged-pane -m -E -O -X -M \"%(output)s\" \
-	#	\"%(branch1)s\" \"%(branch2)s\"
-	#i3merge = emacs --eval '(ediff-merge-files-with-ancestor \
-	#	\"%(branch1)s\" \"%(branch2)s\" \"%(ancestor)s\" nil \
-	#	\"%(output)s\")'
-	#i2merge = emacs --eval '(ediff-merge-files \
-	#	\"%(branch1)s\" \"%(branch2)s\" nil \"%(output)s\")'
-
-	# Automatically invoke the interactive merger in case of conflicts
+	# Automatically invoke the interactive merger (git mergetool) in case
+	# of conflicts
 	#autoimerge = no
 
-	# Leave the original files in the working tree in case of a
-	# merge conflict
-	#keeporig = yes
-
 	# Optimize (repack) the object store after every pull
 	#keepoptimized = yes
 
diff --git a/stgit/commands/resolved.py b/stgit/commands/resolved.py
index 2ce7ec3..eba778d 100644
--- a/stgit/commands/resolved.py
+++ b/stgit/commands/resolved.py
@@ -22,7 +22,6 @@ from stgit.commands.common import *
 from stgit.utils import *
 from stgit import argparse, stack, git, basedir
 from stgit.config import config, file_extensions
-from stgit.gitmergeonefile import interactive_merge
 
 help = 'Mark a file conflict as solved'
 kind = 'wc'
@@ -78,8 +77,6 @@ def func(parser, options, args):
 
     # resolved
     if options.interactive:
-        for filename in files:
-            interactive_merge(filename)
-            git.resolved([filename])
+        git.mergetool(files)
     else:
         git.resolved(files, options.reset)
diff --git a/stgit/config.py b/stgit/config.py
index 05ef624..efce097 100644
--- a/stgit/config.py
+++ b/stgit/config.py
@@ -35,7 +35,6 @@ class GitConfig:
         'stgit.fetchcmd':	'git fetch',
         'stgit.pull-policy':	'pull',
         'stgit.autoimerge':	'no',
-        'stgit.keeporig':	'yes',
         'stgit.keepoptimized':	'no',
         'stgit.extensions':	'.ancestor .current .patched',
         'stgit.shortnr':	 '5'
diff --git a/stgit/git.py b/stgit/git.py
index 4d01fc2..50e3621 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os, re, gitmergeonefile
+import sys, os, re
 from shutil import copyfile
 
 from stgit.exception import *
@@ -632,19 +632,25 @@ def merge_recursive(base, head1, head2):
     output = p.output_lines()
     if p.exitcode:
         # There were conflicts
-        conflicts = [l.strip() for l in output if l.startswith('CONFLICT')]
+        if config.get('stgit.autoimerge') == 'yes':
+            mergetool()
+        else:
+            conflicts = [l for l in output if l.startswith('CONFLICT')]
+            out.info(*conflicts)
+            raise GitException, "%d conflict(s)" % len(conflicts)
+
+def mergetool(files = ()):
+    """Invoke 'git mergetool' to resolve any outstanding conflicts. If 'not
+    files', all the files in an unmerged state will be processed."""
+    err = os.system('git mergetool %s' % ' '.join(files))
+    # check for unmerged entries (prepend 'CONFLICT ' for consistency with
+    # merge_recursive())
+    conflicts = ['CONFLICT ' + f for f in get_conflicts()]
+    if conflicts:
         out.info(*conflicts)
-
-        # try the interactive merge or stage checkout (if enabled)
-        for filename in get_conflicts():
-            if (gitmergeonefile.merge(filename)):
-                # interactive merge succeeded
-                resolved([filename])
-
-        # any conflicts left unsolved?
-        cn = len(get_conflicts())
-        if cn:
-            raise GitException, "%d conflict(s)" % cn
+        raise GitException, "%d conflict(s)" % len(conflicts)
+    elif err:
+        raise GitException('"git mergetool" failed, exit code: %d' % err)
 
 def diff(files = None, rev1 = 'HEAD', rev2 = None, diff_flags = [],
          binary = True):
@@ -754,7 +760,6 @@ def resolved(filenames, reset = None):
              '--stdin', '-z').input_nulterm(filenames).no_output()
     GRun('update-index', '--add', '--').xargs(filenames)
     for filename in filenames:
-        gitmergeonefile.clean_up(filename)
         # update the access and modificatied times
         os.utime(filename, None)
 
diff --git a/stgit/gitmergeonefile.py b/stgit/gitmergeonefile.py
deleted file mode 100644
index 1fe226e..0000000
--- a/stgit/gitmergeonefile.py
+++ /dev/null
@@ -1,150 +0,0 @@
-"""Performs a 3-way merge for GIT files
-"""
-
-__copyright__ = """
-Copyright (C) 2006, Catalin Marinas <catalin.marinas@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-"""
-
-import sys, os
-from stgit.exception import *
-from stgit import basedir
-from stgit.config import config, file_extensions, ConfigOption
-from stgit.utils import append_string
-from stgit.out import *
-from stgit.run import *
-
-class GitMergeException(StgException):
-    pass
-
-
-#
-# Options
-#
-autoimerge = ConfigOption('stgit', 'autoimerge')
-keeporig = ConfigOption('stgit', 'keeporig')
-
-#
-# Utility functions
-#
-def __str2none(x):
-    if x == '':
-        return None
-    else:
-        return x
-
-class MRun(Run):
-    exc = GitMergeException # use a custom exception class on errors
-
-def __checkout_stages(filename):
-    """Check-out the merge stages in the index for the give file
-    """
-    extensions = file_extensions()
-    line = MRun('git', 'checkout-index', '--stage=all', '--', filename
-                ).output_one_line()
-    stages, path = line.split('\t')
-    stages = dict(zip(['ancestor', 'current', 'patched'],
-                      stages.split(' ')))
-
-    for stage, fn in stages.iteritems():
-        if stages[stage] == '.':
-            stages[stage] = None
-        else:
-            newname = filename + extensions[stage]
-            if os.path.exists(newname):
-                # remove the stage if it is already checked out
-                os.remove(newname)
-            os.rename(stages[stage], newname)
-            stages[stage] = newname
-
-    return stages
-
-def __remove_stages(filename):
-    """Remove the merge stages from the working directory
-    """
-    extensions = file_extensions()
-    for ext in extensions.itervalues():
-        fn = filename + ext
-        if os.path.isfile(fn):
-            os.remove(fn)
-
-def interactive_merge(filename):
-    """Run the interactive merger on the given file. Stages will be
-    removed according to stgit.keeporig. If successful and stages
-    kept, they will be removed via git.resolved().
-    """
-    stages = __checkout_stages(filename)
-
-    try:
-        # Check whether we have all the files for the merge.
-        if not (stages['current'] and stages['patched']):
-            raise GitMergeException('Cannot run the interactive merge')
-
-        if stages['ancestor']:
-            three_way = True
-            files_dict = {'branch1': stages['current'],
-                          'ancestor': stages['ancestor'],
-                          'branch2': stages['patched'],
-                          'output': filename}
-            imerger = config.get('stgit.i3merge')
-        else:
-            three_way = False
-            files_dict = {'branch1': stages['current'],
-                          'branch2': stages['patched'],
-                          'output': filename}
-            imerger = config.get('stgit.i2merge')
-
-        if not imerger:
-            raise GitMergeException, 'No interactive merge command configured'
-
-        mtime = os.path.getmtime(filename)
-
-        out.start('Trying the interactive %s merge'
-                  % (three_way and 'three-way' or 'two-way'))
-        err = os.system(imerger % files_dict)
-        out.done()
-        if err != 0:
-            raise GitMergeException, 'The interactive merge failed'
-        if not os.path.isfile(filename):
-            raise GitMergeException, 'The "%s" file is missing' % filename
-        if mtime == os.path.getmtime(filename):
-            raise GitMergeException, 'The "%s" file was not modified' % filename
-    finally:
-        # keep the merge stages?
-        if str(keeporig) != 'yes':
-            __remove_stages(filename)
-
-def clean_up(filename):
-    """Remove merge conflict stages if they were generated.
-    """
-    if str(keeporig) == 'yes':
-        __remove_stages(filename)
-
-def merge(filename):
-    """Merge one file if interactive is allowed or check out the stages
-    if keeporig is set.
-    """
-    if str(autoimerge) == 'yes':
-        try:
-            interactive_merge(filename)
-        except GitMergeException, ex:
-            out.error(str(ex))
-            return False
-        return True
-
-    if str(keeporig) == 'yes':
-        __checkout_stages(filename)
-
-    return False
diff --git a/t/t0002-status.sh b/t/t0002-status.sh
index ac92aa8..d95a83b 100755
--- a/t/t0002-status.sh
+++ b/t/t0002-status.sh
@@ -107,9 +107,6 @@ test_expect_success 'Make a conflicting patch' '
 '
 
 cat > expected.txt <<EOF
-? foo/bar.ancestor
-? foo/bar.current
-? foo/bar.patched
 A fie
 C foo/bar
 EOF

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure
  2009-03-12 12:08 [StGit PATCH 0/5] Various StGit patches Catalin Marinas
  2009-03-12 12:08 ` [StGit PATCH 1/5] Check for local changes with "goto" Catalin Marinas
  2009-03-12 12:09 ` [StGit PATCH 2/5] Add mergetool support to the classic StGit infrastructure Catalin Marinas
@ 2009-03-12 12:09 ` Catalin Marinas
  2009-03-13  2:17   ` Karl Hasselström
  2009-03-12 12:09 ` [StGit PATCH 4/5] Convert "sink" " Catalin Marinas
  2009-03-12 12:09 ` [StGit PATCH 5/5] Convert "float" to the lib infrastructure Catalin Marinas
  4 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-12 12:09 UTC (permalink / raw)
  To: git, Karl Hasselström

This patch adds the IndexAndWorktree.mergetool() function responsible
for calling 'git mergetool' to interactively solve conflicts. The
function may also be called from IndexAndWorktree.merge() if the
standard 'git merge-recursive' fails and 'interactive == True'. The
'allow_interactive' parameter is passed to Transaction.push_patch() from
the functions allowing interactive merging.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
 stgit/commands/edit.py   |    2 +-
 stgit/commands/goto.py   |    2 +-
 stgit/lib/git.py         |   21 ++++++++++++++++++---
 stgit/lib/transaction.py |    7 +++++--
 4 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/stgit/commands/edit.py b/stgit/commands/edit.py
index ed785aa..42eb792 100644
--- a/stgit/commands/edit.py
+++ b/stgit/commands/edit.py
@@ -128,7 +128,7 @@ def func(parser, options, args):
     trans.patches[patchname] = stack.repository.commit(cd)
     try:
         for pn in popped:
-            trans.push_patch(pn, iw)
+            trans.push_patch(pn, iw, allow_interactive = True)
     except transaction.TransactionHalted:
         pass
     try:
diff --git a/stgit/commands/goto.py b/stgit/commands/goto.py
index 0f67314..56c09da 100644
--- a/stgit/commands/goto.py
+++ b/stgit/commands/goto.py
@@ -48,7 +48,7 @@ def func(parser, options, args):
     elif patch in trans.unapplied:
         try:
             for pn in trans.unapplied[:trans.unapplied.index(patch)+1]:
-                trans.push_patch(pn, iw)
+                trans.push_patch(pn, iw, allow_interactive = True)
         except transaction.TransactionHalted:
             pass
     elif patch in trans.hidden:
diff --git a/stgit/lib/git.py b/stgit/lib/git.py
index 07079b8..d83b475 100644
--- a/stgit/lib/git.py
+++ b/stgit/lib/git.py
@@ -824,7 +824,7 @@ class IndexAndWorktree(RunWithEnvCwd):
                      ).discard_output()
         except run.RunException:
             raise CheckoutException('Index/workdir dirty')
-    def merge(self, base, ours, theirs):
+    def merge(self, base, ours, theirs, interactive = False):
         assert isinstance(base, Tree)
         assert isinstance(ours, Tree)
         assert isinstance(theirs, Tree)
@@ -838,10 +838,25 @@ class IndexAndWorktree(RunWithEnvCwd):
             output = r.output_lines()
             if r.exitcode:
                 # There were conflicts
-                conflicts = [l for l in output if l.startswith('CONFLICT')]
-                raise MergeConflictException(conflicts)
+                if interactive:
+                    self.mergetool()
+                else:
+                    conflicts = [l for l in output if l.startswith('CONFLICT')]
+                    raise MergeConflictException(conflicts)
         except run.RunException, e:
             raise MergeException('Index/worktree dirty')
+    def mergetool(self, files = ()):
+        """Invoke 'git mergetool' on the current IndexAndWorktree to resolve
+        any outstanding conflicts. If 'not files', all the files in an
+        unmerged state will be processed."""
+        err = os.system('git mergetool %s' % ' '.join(files))
+        # check for unmerged entries (prepend 'CONFLICT ' for consistency with
+        # merge())
+        conflicts = ['CONFLICT ' + f for f in self.index.conflicts()]
+        if conflicts:
+            raise MergeConflictException(conflicts)
+        elif err:
+            raise MergeException('"git mergetool" failed, exit code: %d' % err)
     def changed_files(self, tree, pathlimits = []):
         """Return the set of files in the worktree that have changed with
         respect to C{tree}. The listing is optionally restricted to
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 5a81f9d..a918a66 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -8,6 +8,7 @@ from stgit import exception, utils
 from stgit.utils import any, all
 from stgit.out import *
 from stgit.lib import git, log
+from stgit.config import config
 
 class TransactionException(exception.StgException):
     """Exception raised when something goes wrong with a
@@ -296,7 +297,7 @@ class StackTransaction(object):
                     out.info('Deleted %s%s' % (pn, s))
         return popped
 
-    def push_patch(self, pn, iw = None):
+    def push_patch(self, pn, iw = None, allow_interactive = False):
         """Attempt to push the named patch. If this results in conflicts,
         halts the transaction. If index+worktree are given, spill any
         conflicts to them."""
@@ -319,7 +320,9 @@ class StackTransaction(object):
             except git.CheckoutException:
                 self.__halt('Index/worktree dirty')
             try:
-                iw.merge(base, ours, theirs)
+                interactive = allow_interactive and \
+                        config.get('stgit.autoimerge') == 'yes'
+                iw.merge(base, ours, theirs, interactive = interactive)
                 tree = iw.index.write_tree()
                 self.__current_tree = tree
                 s = ' (modified)'

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [StGit PATCH 4/5] Convert "sink" to the new infrastructure
  2009-03-12 12:08 [StGit PATCH 0/5] Various StGit patches Catalin Marinas
                   ` (2 preceding siblings ...)
  2009-03-12 12:09 ` [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure Catalin Marinas
@ 2009-03-12 12:09 ` Catalin Marinas
  2009-03-13  2:27   ` Karl Hasselström
  2009-03-12 12:09 ` [StGit PATCH 5/5] Convert "float" to the lib infrastructure Catalin Marinas
  4 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-12 12:09 UTC (permalink / raw)
  To: git, Karl Hasselström

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
 stgit/commands/sink.py |   86 +++++++++++++++++++++---------------------------
 t/t1501-sink.sh        |    2 +
 2 files changed, 39 insertions(+), 49 deletions(-)

diff --git a/stgit/commands/sink.py b/stgit/commands/sink.py
index d4561ed..8b17fd1 100644
--- a/stgit/commands/sink.py
+++ b/stgit/commands/sink.py
@@ -16,11 +16,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os
 from stgit.argparse import opt
-from stgit.commands.common import *
-from stgit.utils import *
-from stgit import argparse, stack, git
+from stgit.commands import common
+from stgit.lib import transaction
+from stgit import argparse
 
 help = 'Send patches deeper down the stack'
 kind = 'stack'
@@ -51,57 +50,48 @@ options = [
     opt('-t', '--to', metavar = 'TARGET', args = [argparse.applied_patches],
         short = 'Sink patches below the TARGET patch', long = """
         Specify a target patch to place the patches below, instead of
-        sinking them to the bottom of the stack.""")]
+        sinking them to the bottom of the stack.""")
+    ] + argparse.keep_option()
 
-directory = DirectoryGotoToplevel(log = True)
+directory = common.DirectoryHasRepositoryLib()
 
 def func(parser, options, args):
     """Sink patches down the stack.
     """
+    stack = directory.repository.current_stack
 
-    check_local_changes()
-    check_conflicts()
-    check_head_top_equal(crt_series)
+    if options.to and not options.to in stack.patchorder.applied:
+        raise common.CmdException('Cannot sink below %s since it is not applied'
+                                  % options.to)
 
-    oldapplied = crt_series.get_applied()
-    unapplied = crt_series.get_unapplied()
-    all = oldapplied + unapplied
+    if len(args) > 0:
+        patches = common.parse_patches(args, stack.patchorder.all)
+    else:
+        # current patch
+        patches = list(stack.patchorder.applied[-1:])
 
-    if options.to and not options.to in oldapplied:
-        raise CmdException('Cannot sink below %s, since it is not applied'
-                           % options.to)
+    if not patches:
+        raise common.CmdException('No patches to sink')
+    if options.to and options.to in patches:
+        raise common.CmdException('Cannot have a sinked patch as target')
 
-    if len(args) > 0:
-        patches = parse_patches(args, all)
+    applied = [p for p in stack.patchorder.applied if p not in patches]
+    if options.to:
+        insert_idx = applied.index(options.to)
     else:
-        current = crt_series.get_current()
-        if not current:
-            raise CmdException('No patch applied')
-        patches = [current]
-
-    before_patches = after_patches = []
-
-    # pop necessary patches
-    if oldapplied:
-        if options.to:
-            pop_idx = oldapplied.index(options.to)
-        else:
-            pop_idx = 0
-        after_patches = [p for p in oldapplied[pop_idx:] if p not in patches]
-
-        # find the deepest patch to pop
-        sink_applied = [p for p in oldapplied if p in patches]
-        if sink_applied:
-            sinked_idx = oldapplied.index(sink_applied[0])
-            if sinked_idx < pop_idx:
-                # this is the case where sink brings patches forward
-                before_patches = [p for p in oldapplied[sinked_idx:pop_idx]
-                                  if p not in patches]
-                pop_idx = sinked_idx
-
-        crt_series.pop_patch(oldapplied[pop_idx])
-
-    push_patches(crt_series, before_patches)
-    push_patches(crt_series, patches)
-    if not options.nopush:
-        push_patches(crt_series, after_patches)
+        insert_idx = 0
+    applied = applied[:insert_idx] + patches + applied[insert_idx:]
+
+    unapplied = [p for p in stack.patchorder.unapplied if p not in patches]
+    hidden = list(stack.patchorder.hidden)
+
+    iw = stack.repository.default_iw
+    clean_iw = not options.keep and iw or None
+    trans = transaction.StackTransaction(stack, 'sink',
+                                         check_clean_iw = clean_iw)
+
+    try:
+        trans.reorder_patches(applied, unapplied, hidden, iw)
+    except transaction.TransactionHalted:
+        pass
+    return trans.run(iw)
diff --git a/t/t1501-sink.sh b/t/t1501-sink.sh
index 516aa44..a0769dd 100755
--- a/t/t1501-sink.sh
+++ b/t/t1501-sink.sh
@@ -58,7 +58,7 @@ test_expect_success 'sink specified patch below a target' '
 '
 
 test_expect_success 'sink with conflict' '
-    conflict_old stg sink --to=p2 p22 &&
+    conflict stg sink --to=p2 p22 &&
     test "$(echo $(stg series --applied --noprefix))" = "p1 p22" &&
     test "$(echo $(stg status -c))" = "f2"
 '

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [StGit PATCH 5/5] Convert "float" to the lib infrastructure
  2009-03-12 12:08 [StGit PATCH 0/5] Various StGit patches Catalin Marinas
                   ` (3 preceding siblings ...)
  2009-03-12 12:09 ` [StGit PATCH 4/5] Convert "sink" " Catalin Marinas
@ 2009-03-12 12:09 ` Catalin Marinas
  2009-03-13  2:41   ` Karl Hasselström
  4 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-12 12:09 UTC (permalink / raw)
  To: git, Karl Hasselström

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
 stgit/commands/float.py |   75 ++++++++++++++++++-----------------------------
 1 files changed, 29 insertions(+), 46 deletions(-)

diff --git a/stgit/commands/float.py b/stgit/commands/float.py
index 7c3dcdf..f94de88 100644
--- a/stgit/commands/float.py
+++ b/stgit/commands/float.py
@@ -16,11 +16,11 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os
+import sys
 from stgit.argparse import opt
-from stgit.commands.common import *
-from stgit.utils import *
-from stgit import argparse, stack, git
+from stgit.commands import common
+from stgit.lib import transaction
+from stgit import argparse
 
 help = 'Push patches to the top, even if applied'
 kind = 'stack'
@@ -36,25 +36,20 @@ args = [argparse.patch_range(argparse.applied_patches,
                              argparse.unapplied_patches)]
 options = [
     opt('-s', '--series', action = 'store_true',
-        short = 'Rearrange according to a series file')]
+        short = 'Rearrange according to a series file')
+    ] + argparse.keep_option()
 
-directory = DirectoryGotoToplevel(log = True)
+directory = common.DirectoryHasRepositoryLib()
 
 def func(parser, options, args):
-    """Pops and pushed to make the named patch the topmost patch
+    """Reorder patches to make the named patch the topmost one.
     """
     args_nr = len(args)
     if (options.series and args_nr > 1) \
            or (not options.series and args_nr == 0):
         parser.error('incorrect number of arguments')
 
-    check_local_changes()
-    check_conflicts()
-    check_head_top_equal(crt_series)
-
-    unapplied = crt_series.get_unapplied()
-    applied = crt_series.get_applied()
-    all = unapplied + applied
+    stack = directory.repository.current_stack
 
     if options.series:
         if args_nr:
@@ -68,35 +63,23 @@ def func(parser, options, args):
             if patch:
                 patches.append(patch)
     else:
-        patches = parse_patches(args, all)
-
-    # working with "topush" patches in reverse order might be a bit
-    # more efficient for large series but the main reason is for the
-    # "topop != topush" comparison to work
-    patches.reverse()
-
-    topush = []
-    topop = []
-
-    for p in patches:
-        while p in applied:
-            top = applied.pop()
-            if not top in patches:
-                topush.append(top)
-            topop.append(top)
-    topush = patches + topush
-
-    # remove common patches to avoid unnecessary pop/push
-    while topush and topop:
-        if topush[-1] != topop[-1]:
-            break
-        topush.pop()
-        topop.pop()
-
-    # check whether the operation is really needed
-    if topop != topush:
-        if topop:
-            pop_patches(crt_series, topop)
-        if topush:
-            topush.reverse()
-            push_patches(crt_series, topush)
+        patches = common.parse_patches(args, stack.patchorder.all)
+
+    if not patches:
+        raise common.CmdException('No patches to float')
+
+    applied = [p for p in stack.patchorder.applied if p not in patches] + \
+            patches
+    unapplied = [p for p in stack.patchorder.unapplied if p not in patches]
+    hidden = list(stack.patchorder.hidden)
+
+    iw = stack.repository.default_iw
+    clean_iw = not options.keep and iw or None
+    trans = transaction.StackTransaction(stack, 'sink',
+                                         check_clean_iw = clean_iw)
+
+    try:
+        trans.reorder_patches(applied, unapplied, hidden, iw)
+    except transaction.TransactionHalted:
+        pass
+    return trans.run(iw)

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 1/5] Check for local changes with "goto"
  2009-03-12 12:08 ` [StGit PATCH 1/5] Check for local changes with "goto" Catalin Marinas
@ 2009-03-13  1:57   ` Karl Hasselström
  2009-03-16 14:56     ` Catalin Marinas
  0 siblings, 1 reply; 19+ messages in thread
From: Karl Hasselström @ 2009-03-13  1:57 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-12 12:08:56 +0000, Catalin Marinas wrote:

> This is done by default, unless the --keep option is passed, for
> consistency with the "pop" command. The index is checked in the
> Transaction.run() function so that other commands could benefit from
> this feature (off by default).
>
> This behaviour can be overridden by setting the stgit.autokeep option.

Two small nits; otherwise,

  Acked-by: Karl Hasselström <kha@treskal.com>

> -    trans = transaction.StackTransaction(stack, 'goto')
> +    clean_iw = not options.keep and iw or None

Add some parentheses here, please! I know that "and" binds tighter
than "or", but I have to think for too long to remember which is
which, and I'll bet I'm not alone ...

> +    def __assert_index_worktree_clean(self, iw):
> +        if not iw.worktree_clean() or \
> +           not iw.index.is_clean(self.stack.head):
> +            self.__halt('Repository not clean. Use "refresh" or '
> +                        '"status --reset"')

"Repository" is misleading here. Maybe something like

   ix_c = iw.index.is_clean(self.stack.head)
   wt_c = iw.worktree_clean()
   if not ix_c or not wt_c:
       self.__halt('%s not clean. Use "refresh" or "status --reset"'
                   % { (False, True): 'Index', (True, False): 'Worktree',
                       (False, False): 'Index and worktree' }[(ix_c, wt_c)])

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 2/5] Add mergetool support to the classic StGit infrastructure
  2009-03-12 12:09 ` [StGit PATCH 2/5] Add mergetool support to the classic StGit infrastructure Catalin Marinas
@ 2009-03-13  2:02   ` Karl Hasselström
  0 siblings, 0 replies; 19+ messages in thread
From: Karl Hasselström @ 2009-03-13  2:02 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-12 12:09:02 +0000, Catalin Marinas wrote:

> Since Git already has a tool for interactively solving conflicts
> which is highly customisable, there is no need to duplicate this
> feature via the i3merge and i2merge configuration options. The
> user-visible change is that now mergetool is invoked rather than the
> previously customised interactive merging tool.

I agree wholeheartedly with the idea. Just one issue:

> +def mergetool(files = ()):
> +    """Invoke 'git mergetool' to resolve any outstanding conflicts. If 'not
> +    files', all the files in an unmerged state will be processed."""
> +    err = os.system('git mergetool %s' % ' '.join(files))
> +    # check for unmerged entries (prepend 'CONFLICT ' for consistency with
> +    # merge_recursive())
> +    conflicts = ['CONFLICT ' + f for f in get_conflicts()]
> +    if conflicts:

Mmm, os.system()? That'll break things as soon as we have a file name
with a space in it. I'm pretty sure there's something in stgit.run
that you could use.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure
  2009-03-12 12:09 ` [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure Catalin Marinas
@ 2009-03-13  2:17   ` Karl Hasselström
  2009-03-16 15:03     ` Catalin Marinas
  0 siblings, 1 reply; 19+ messages in thread
From: Karl Hasselström @ 2009-03-13  2:17 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-12 12:09:07 +0000, Catalin Marinas wrote:

> This patch adds the IndexAndWorktree.mergetool() function responsible
> for calling 'git mergetool' to interactively solve conflicts. The
> function may also be called from IndexAndWorktree.merge() if the
> standard 'git merge-recursive' fails and 'interactive == True'. The
> 'allow_interactive' parameter is passed to Transaction.push_patch() from
> the functions allowing interactive merging.

Nicely done with the "interactive" and "allow_interactive" arguments;
the policy and the implementation end up at the right levels.

>                  # There were conflicts
> -                conflicts = [l for l in output if l.startswith('CONFLICT')]
> -                raise MergeConflictException(conflicts)
> +                if interactive:
> +                    self.mergetool()
> +                else:
> +                    conflicts = [l for l in output if l.startswith('CONFLICT')]
> +                    raise MergeConflictException(conflicts)

Does the merge tool always resolve all conflicts? If it doesn't, the
two lines in the "else" branch should probably be run unconditionally.

>          except run.RunException, e:
>              raise MergeException('Index/worktree dirty')
> +    def mergetool(self, files = ()):
> +        """Invoke 'git mergetool' on the current IndexAndWorktree to resolve
> +        any outstanding conflicts. If 'not files', all the files in an
> +        unmerged state will be processed."""
> +        err = os.system('git mergetool %s' % ' '.join(files))

Look at how the surrounding code calls git. os.system() will do nasty
things with filenames that require quoting, such as for example
"; rm -rf ~/".

> +        # check for unmerged entries (prepend 'CONFLICT ' for consistency with
> +        # merge())
> +        conflicts = ['CONFLICT ' + f for f in self.index.conflicts()]
> +        if conflicts:
> +            raise MergeConflictException(conflicts)
> +        elif err:
> +            raise MergeException('"git mergetool" failed, exit code: %d' % err)

Ah, you take care of conflicts here too. Hmm. I guess that's fine too,
though there is some code duplication. Maybe a helper function that
takes output as a parameter, and raises MergeConflictException if
necessary?

> +                interactive = allow_interactive and \
> +                        config.get('stgit.autoimerge') == 'yes'

Small style nit: backslash line continuations are ugly. :-)

If you put parentheses around the expression, you can break the line
without a backslash.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 4/5] Convert "sink" to the new infrastructure
  2009-03-12 12:09 ` [StGit PATCH 4/5] Convert "sink" " Catalin Marinas
@ 2009-03-13  2:27   ` Karl Hasselström
  0 siblings, 0 replies; 19+ messages in thread
From: Karl Hasselström @ 2009-03-13  2:27 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

Nicely done.

  Acked-by: Karl Hasselström <kha@treskal.com>

On 2009-03-12 12:09:13 +0000, Catalin Marinas wrote:

> +    applied = applied[:insert_idx] + patches + applied[insert_idx:]
> +
> +    unapplied = [p for p in stack.patchorder.unapplied if p not in patches]
> +    hidden = list(stack.patchorder.hidden)
> +
> +    iw = stack.repository.default_iw
> +    clean_iw = not options.keep and iw or None
> +    trans = transaction.StackTransaction(stack, 'sink',
> +                                         check_clean_iw = clean_iw)
> +
> +    try:
> +        trans.reorder_patches(applied, unapplied, hidden, iw)

Hmm. We should maybe have a default value for hidden: the current list
of patches. Not changing the hidden patches is a common operation.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 5/5] Convert "float" to the lib infrastructure
  2009-03-12 12:09 ` [StGit PATCH 5/5] Convert "float" to the lib infrastructure Catalin Marinas
@ 2009-03-13  2:41   ` Karl Hasselström
  2009-03-16 16:36     ` Catalin Marinas
  0 siblings, 1 reply; 19+ messages in thread
From: Karl Hasselström @ 2009-03-13  2:41 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

Nice job here too.

On 2009-03-12 12:09:18 +0000, Catalin Marinas wrote:

>  options = [
>      opt('-s', '--series', action = 'store_true',
> -        short = 'Rearrange according to a series file')]
> +        short = 'Rearrange according to a series file')
> +    ] + argparse.keep_option()

This flag should take the filename as a parameter, both because it's
the right thing to do and because it'll make the tab completion work
right (as is, it'll complete on patch names after the -s flag).

Something like

  opt('-s', '--series', type = 'string')

ought to do it.

> +    applied = [p for p in stack.patchorder.applied if p not in patches] + \
> +            patches
> +    unapplied = [p for p in stack.patchorder.unapplied if p not in patches]

It may be just me, but I find "not p in patches" more readable than "p
not in patches". Oh, and the backslash.

Feel free to ignore, of course. :-)

> +    hidden = list(stack.patchorder.hidden)
> +
> +    iw = stack.repository.default_iw
> +    clean_iw = not options.keep and iw or None
> +    trans = transaction.StackTransaction(stack, 'sink',
> +                                         check_clean_iw = clean_iw)
> +
> +    try:
> +        trans.reorder_patches(applied, unapplied, hidden, iw)

That default value for hidden would've come in handy here too!

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 1/5] Check for local changes with "goto"
  2009-03-13  1:57   ` Karl Hasselström
@ 2009-03-16 14:56     ` Catalin Marinas
  2009-03-17  7:06       ` Karl Hasselström
  0 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-16 14:56 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: git

2009/3/13 Karl Hasselström <kha@treskal.com>:
> On 2009-03-12 12:08:56 +0000, Catalin Marinas wrote:
>> +    def __assert_index_worktree_clean(self, iw):
>> +        if not iw.worktree_clean() or \
>> +           not iw.index.is_clean(self.stack.head):
>> +            self.__halt('Repository not clean. Use "refresh" or '
>> +                        '"status --reset"')
>
> "Repository" is misleading here. Maybe something like
>
>   ix_c = iw.index.is_clean(self.stack.head)
>   wt_c = iw.worktree_clean()
>   if not ix_c or not wt_c:
>       self.__halt('%s not clean. Use "refresh" or "status --reset"'
>                   % { (False, True): 'Index', (True, False): 'Worktree',
>                       (False, False): 'Index and worktree' }[(ix_c, wt_c)])

I added two separate if's as I don't find the above readable :-)

if not iw.worktree_clean():
    self.__halt('Worktree not clean. Use "refresh" or "status --reset"')
if not iw.index.is_clean(self.stack.head):
    self.__halt('Index not clean. Use "refresh" or "status --reset"')
def __checkout(self, tree, iw, allow_bad_head):

-- 
Catalin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 3/5] Add automatic git-mergetool invocation to the  new infrastructure
  2009-03-13  2:17   ` Karl Hasselström
@ 2009-03-16 15:03     ` Catalin Marinas
  2009-03-17  7:12       ` Karl Hasselström
  0 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-16 15:03 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: git

2009/3/13 Karl Hasselström <kha@treskal.com>:
> On 2009-03-12 12:09:07 +0000, Catalin Marinas wrote:
>>                  # There were conflicts
>> -                conflicts = [l for l in output if l.startswith('CONFLICT')]
>> -                raise MergeConflictException(conflicts)
>> +                if interactive:
>> +                    self.mergetool()
>> +                else:
>> +                    conflicts = [l for l in output if l.startswith('CONFLICT')]
>> +                    raise MergeConflictException(conflicts)
>
> Does the merge tool always resolve all conflicts? If it doesn't, the
> two lines in the "else" branch should probably be run unconditionally.
[...]
>> +        # check for unmerged entries (prepend 'CONFLICT ' for consistency with
>> +        # merge())
>> +        conflicts = ['CONFLICT ' + f for f in self.index.conflicts()]
>> +        if conflicts:
>> +            raise MergeConflictException(conflicts)
>> +        elif err:
>> +            raise MergeException('"git mergetool" failed, exit code: %d' % err)
>
> Ah, you take care of conflicts here too. Hmm. I guess that's fine too,
> though there is some code duplication. Maybe a helper function that
> takes output as a parameter, and raises MergeConflictException if
> necessary?

The non-interactive path assumes that there are conflicts if "git
merge-recursive" returned an error and it simply splits the output if
this command. The mergetool path has to run "git ls-files --unmerged"
to check if there were any left conflicts. I wouldn't call "git
ls-files" in the first case as we already have the information.

-- 
Catalin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 5/5] Convert "float" to the lib infrastructure
  2009-03-13  2:41   ` Karl Hasselström
@ 2009-03-16 16:36     ` Catalin Marinas
  2009-03-17  7:16       ` Karl Hasselström
  0 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-16 16:36 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: git

2009/3/13 Karl Hasselström <kha@treskal.com>:
> On 2009-03-12 12:09:18 +0000, Catalin Marinas wrote:
>>  options = [
>>      opt('-s', '--series', action = 'store_true',
>> -        short = 'Rearrange according to a series file')]
>> +        short = 'Rearrange according to a series file')
>> +    ] + argparse.keep_option()
>
> This flag should take the filename as a parameter, both because it's
> the right thing to do and because it'll make the tab completion work
> right (as is, it'll complete on patch names after the -s flag).
>
> Something like
>
>  opt('-s', '--series', type = 'string')
>
> ought to do it.

This command was accepting series via the stdin as well (maybe for
easier use in other scripts or from stgit.el). Anyway, it doesn't seem
to make any difference with the bash completion. It still tries to
complete patches but when this fails bash lists files if the prefix
matches some.

-- 
Catalin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 1/5] Check for local changes with "goto"
  2009-03-16 14:56     ` Catalin Marinas
@ 2009-03-17  7:06       ` Karl Hasselström
  2009-03-17 10:51         ` Catalin Marinas
  0 siblings, 1 reply; 19+ messages in thread
From: Karl Hasselström @ 2009-03-17  7:06 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-16 14:56:11 +0000, Catalin Marinas wrote:

> 2009/3/13 Karl Hasselström <kha@treskal.com>:
>
> > "Repository" is misleading here. Maybe something like
> >
> >   ix_c = iw.index.is_clean(self.stack.head)
> >   wt_c = iw.worktree_clean()
> >   if not ix_c or not wt_c:
> >       self.__halt('%s not clean. Use "refresh" or "status --reset"'
> >                   % { (False, True): 'Index', (True, False): 'Worktree',
> >                       (False, False): 'Index and worktree' }[(ix_c, wt_c)])
>
> I added two separate if's as I don't find the above readable :-)
>
> if not iw.worktree_clean():
>     self.__halt('Worktree not clean. Use "refresh" or "status --reset"')
> if not iw.index.is_clean(self.stack.head):
>     self.__halt('Index not clean. Use "refresh" or "status --reset"')

It's actually quite nice once you get used to the idea of ephemeral
dictionaries just for selection inside an expression ... :-)

Your version doesn't generate the "Your index and worktree are both
dirty" warning, but I guess that's OK.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure
  2009-03-16 15:03     ` Catalin Marinas
@ 2009-03-17  7:12       ` Karl Hasselström
  0 siblings, 0 replies; 19+ messages in thread
From: Karl Hasselström @ 2009-03-17  7:12 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-16 15:03:09 +0000, Catalin Marinas wrote:

> 2009/3/13 Karl Hasselström <kha@treskal.com>:
>
> > On 2009-03-12 12:09:07 +0000, Catalin Marinas wrote:
> >
> > >                  # There were conflicts
> > > -                conflicts = [l for l in output if l.startswith('CONFLICT')]
> > > -                raise MergeConflictException(conflicts)
> > > +                if interactive:
> > > +                    self.mergetool()
> > > +                else:
> > > +                    conflicts = [l for l in output if l.startswith('CONFLICT')]
> > > +                    raise MergeConflictException(conflicts)
> >
> > Does the merge tool always resolve all conflicts? If it doesn't,
> > the two lines in the "else" branch should probably be run
> > unconditionally.
> [...]
> > > +        # check for unmerged entries (prepend 'CONFLICT ' for consistency with
> > > +        # merge())
> > > +        conflicts = ['CONFLICT ' + f for f in self.index.conflicts()]
> > > +        if conflicts:
> > > +            raise MergeConflictException(conflicts)
> > > +        elif err:
> > > +            raise MergeException('"git mergetool" failed, exit code: %d' % err)
> >
> > Ah, you take care of conflicts here too. Hmm. I guess that's fine
> > too, though there is some code duplication. Maybe a helper
> > function that takes output as a parameter, and raises
> > MergeConflictException if necessary?
>
> The non-interactive path assumes that there are conflicts if "git
> merge-recursive" returned an error and it simply splits the output
> if this command. The mergetool path has to run "git ls-files
> --unmerged" to check if there were any left conflicts. I wouldn't
> call "git ls-files" in the first case as we already have the
> information.

I was thinking of a function you'd call with either the output of the
merge operation or ls-files depending on the code path. But maybe it's
not worth it.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 5/5] Convert "float" to the lib infrastructure
  2009-03-16 16:36     ` Catalin Marinas
@ 2009-03-17  7:16       ` Karl Hasselström
  0 siblings, 0 replies; 19+ messages in thread
From: Karl Hasselström @ 2009-03-17  7:16 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-16 16:36:43 +0000, Catalin Marinas wrote:

> 2009/3/13 Karl Hasselström <kha@treskal.com>:
>
> > On 2009-03-12 12:09:18 +0000, Catalin Marinas wrote:
> >
> > >  options = [
> > >      opt('-s', '--series', action = 'store_true',
> > > -        short = 'Rearrange according to a series file')]
> > > +        short = 'Rearrange according to a series file')
> > > +    ] + argparse.keep_option()
> >
> > This flag should take the filename as a parameter, both because
> > it's the right thing to do and because it'll make the tab
> > completion work right (as is, it'll complete on patch names after
> > the -s flag).
> >
> > Something like
> >
> >  opt('-s', '--series', type = 'string')
> >
> > ought to do it.
>
> This command was accepting series via the stdin as well (maybe for
> easier use in other scripts or from stgit.el).

Ah. Hmm, I'd prefer if it used "-" for that, for consistency. And
because I don't know how to make flags with optional parameters. :-/

> Anyway, it doesn't seem to make any difference with the bash
> completion. It still tries to complete patches but when this fails
> bash lists files if the prefix matches some.

Hmm, that's not right. But I can have a look at it if you like.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 1/5] Check for local changes with "goto"
  2009-03-17  7:06       ` Karl Hasselström
@ 2009-03-17 10:51         ` Catalin Marinas
  2009-03-17 13:36           ` Karl Hasselström
  0 siblings, 1 reply; 19+ messages in thread
From: Catalin Marinas @ 2009-03-17 10:51 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: git

2009/3/17 Karl Hasselström <kha@treskal.com>:
> On 2009-03-16 14:56:11 +0000, Catalin Marinas wrote:
>> if not iw.worktree_clean():
>>     self.__halt('Worktree not clean. Use "refresh" or "status --reset"')
>> if not iw.index.is_clean(self.stack.head):
>>     self.__halt('Index not clean. Use "refresh" or "status --reset"')
[...]
> Your version doesn't generate the "Your index and worktree are both
> dirty" warning, but I guess that's OK.

The iw.worktree_clean() only checks whether the worktree is clean
relative to the index (I just tried "git update-index --refresh" after
"git add <modified file>" and it returns 0).

-- 
Catalin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [StGit PATCH 1/5] Check for local changes with "goto"
  2009-03-17 10:51         ` Catalin Marinas
@ 2009-03-17 13:36           ` Karl Hasselström
  0 siblings, 0 replies; 19+ messages in thread
From: Karl Hasselström @ 2009-03-17 13:36 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git

On 2009-03-17 10:51:08 +0000, Catalin Marinas wrote:

> 2009/3/17 Karl Hasselström <kha@treskal.com>:
>
> > On 2009-03-16 14:56:11 +0000, Catalin Marinas wrote:
> >
> > > if not iw.worktree_clean():
> > >     self.__halt('Worktree not clean. Use "refresh" or "status --reset"')
> > > if not iw.index.is_clean(self.stack.head):
> > >     self.__halt('Index not clean. Use "refresh" or "status --reset"')
> [...]
> > Your version doesn't generate the "Your index and worktree are
> > both dirty" warning, but I guess that's OK.
>
> The iw.worktree_clean() only checks whether the worktree is clean
> relative to the index (I just tried "git update-index --refresh"
> after "git add <modified file>" and it returns 0).

Yes, I know. The point I was trying to make was that your code doesn't
make a difference between

  (iw.worktree_clean(), iw.index.is_clean(self.stack.head)) == (False, True)

and

  (iw.worktree_clean(), iw.index.is_clean(self.stack.head)) == (False, False)

But as I said, it's not really important.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2009-03-17 13:38 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-12 12:08 [StGit PATCH 0/5] Various StGit patches Catalin Marinas
2009-03-12 12:08 ` [StGit PATCH 1/5] Check for local changes with "goto" Catalin Marinas
2009-03-13  1:57   ` Karl Hasselström
2009-03-16 14:56     ` Catalin Marinas
2009-03-17  7:06       ` Karl Hasselström
2009-03-17 10:51         ` Catalin Marinas
2009-03-17 13:36           ` Karl Hasselström
2009-03-12 12:09 ` [StGit PATCH 2/5] Add mergetool support to the classic StGit infrastructure Catalin Marinas
2009-03-13  2:02   ` Karl Hasselström
2009-03-12 12:09 ` [StGit PATCH 3/5] Add automatic git-mergetool invocation to the new infrastructure Catalin Marinas
2009-03-13  2:17   ` Karl Hasselström
2009-03-16 15:03     ` Catalin Marinas
2009-03-17  7:12       ` Karl Hasselström
2009-03-12 12:09 ` [StGit PATCH 4/5] Convert "sink" " Catalin Marinas
2009-03-13  2:27   ` Karl Hasselström
2009-03-12 12:09 ` [StGit PATCH 5/5] Convert "float" to the lib infrastructure Catalin Marinas
2009-03-13  2:41   ` Karl Hasselström
2009-03-16 16:36     ` Catalin Marinas
2009-03-17  7:16       ` Karl Hasselström

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.