git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Karl Hasselström" <kha@treskal.com>
To: Catalin Marinas <catalin.marinas@gmail.com>
Cc: git@vger.kernel.org
Subject: [StGit PATCH 01/10] Prevent most commands from running when there are conflicts
Date: Mon, 21 Apr 2008 00:10:27 +0200	[thread overview]
Message-ID: <20080420221027.5837.19012.stgit@yoghurt> (raw)
In-Reply-To: <20080420215625.5837.82896.stgit@yoghurt>

When there are conflicts, we want most commands to fail, since the
conflicts conceptually belong to the topmost patch. git read-tree
already checks this for us when we check out a new tree, but there are
operations where the top tree stays the same, e.g. stg new.

This patch inserts a conflict check when the tree to check out is the
same. By default, conflicts will prevent the checkout from succeeding,
but commands can choose to override this if the same patch stays on
top (for some definition of "same").

This change only affects the new-infrastructure commands; the others
always refuse to run when there are local changes of any kind.

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

---

 stgit/commands/clean.py    |    3 ++-
 stgit/commands/coalesce.py |    3 ++-
 stgit/commands/commit.py   |    7 ++++++-
 stgit/commands/delete.py   |   10 +++++++++-
 stgit/commands/edit.py     |    3 ++-
 stgit/commands/uncommit.py |    3 ++-
 stgit/lib/transaction.py   |   27 ++++++++++++++++++++++-----
 7 files changed, 45 insertions(+), 11 deletions(-)


diff --git a/stgit/commands/clean.py b/stgit/commands/clean.py
index 889c1dc..ed6fc6e 100644
--- a/stgit/commands/clean.py
+++ b/stgit/commands/clean.py
@@ -37,7 +37,8 @@ options = [make_option('-a', '--applied',
 
 
 def _clean(stack, clean_applied, clean_unapplied):
-    trans = transaction.StackTransaction(stack, 'stg clean')
+    trans = transaction.StackTransaction(stack, 'stg clean',
+                                         allow_conflicts = True)
     def del_patch(pn):
         if pn in stack.patchorder.applied:
             if pn == stack.patchorder.applied[-1]:
diff --git a/stgit/commands/coalesce.py b/stgit/commands/coalesce.py
index 291a537..bf40427 100644
--- a/stgit/commands/coalesce.py
+++ b/stgit/commands/coalesce.py
@@ -79,7 +79,8 @@ def _coalesce(stack, iw, name, msg, save_template, patches):
         trans.patches[name] = stack.repository.commit(new_commit_data)
         trans.unapplied.insert(0, name)
 
-    trans = transaction.StackTransaction(stack, 'stg coalesce')
+    trans = transaction.StackTransaction(stack, 'stg coalesce',
+                                         allow_conflicts = True)
     push_new_patch = bool(set(patches) & set(trans.applied))
     try:
         new_commit_data = _coalesce_patches(trans, patches, msg, save_template)
diff --git a/stgit/commands/commit.py b/stgit/commands/commit.py
index bff94ce..ee95836 100644
--- a/stgit/commands/commit.py
+++ b/stgit/commands/commit.py
@@ -69,7 +69,12 @@ def func(parser, options, args):
         raise common.CmdException('No patches to commit')
 
     iw = stack.repository.default_iw
-    trans = transaction.StackTransaction(stack, 'stg commit')
+    def allow_conflicts(trans):
+        # As long as the topmost patch stays where it is, it's OK to
+        # run "stg commit" with conflicts in the index.
+        return len(trans.applied) >= 1
+    trans = transaction.StackTransaction(stack, 'stg commit',
+                                         allow_conflicts = allow_conflicts)
     try:
         common_prefix = 0
         for i in xrange(min(len(stack.patchorder.applied), len(patches))):
diff --git a/stgit/commands/delete.py b/stgit/commands/delete.py
index 106fbd2..14bf442 100644
--- a/stgit/commands/delete.py
+++ b/stgit/commands/delete.py
@@ -46,7 +46,15 @@ def func(parser, options, args):
                        + list(stack.patchorder.unapplied))))
     else:
         parser.error('No patches specified')
-    trans = transaction.StackTransaction(stack, 'stg delete')
+    def allow_conflicts(trans):
+        # Allow conflicts if the topmost patch stays the same.
+        if stack.patchorder.applied:
+            return (trans.applied
+                    and trans.applied[-1] == stack.patchorder.applied[-1])
+        else:
+            return not trans.applied
+    trans = transaction.StackTransaction(stack, 'stg delete',
+                                         allow_conflicts = allow_conflicts)
     try:
         to_push = trans.delete_patches(lambda pn: pn in patches)
         for pn in to_push:
diff --git a/stgit/commands/edit.py b/stgit/commands/edit.py
index eff9117..c354730 100644
--- a/stgit/commands/edit.py
+++ b/stgit/commands/edit.py
@@ -173,7 +173,8 @@ def func(parser, options, args):
     # The patch applied, so now we have to rewrite the StGit patch
     # (and any patches on top of it).
     iw = stack.repository.default_iw
-    trans = transaction.StackTransaction(stack, 'stg edit')
+    trans = transaction.StackTransaction(stack, 'stg edit',
+                                         allow_conflicts = True)
     if patchname in trans.applied:
         popped = trans.applied[trans.applied.index(patchname)+1:]
         assert not trans.pop_patches(lambda pn: pn in popped)
diff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py
index 272c5db..b6765bc 100644
--- a/stgit/commands/uncommit.py
+++ b/stgit/commands/uncommit.py
@@ -131,7 +131,8 @@ def func(parser, options, args):
             taken_names.add(pn)
         patchnames.reverse()
 
-    trans = transaction.StackTransaction(stack, 'stg uncommit')
+    trans = transaction.StackTransaction(stack, 'stg uncommit',
+                                         allow_conflicts = True)
     for commit, pn in zip(commits, patchnames):
         trans.patches[pn] = commit
     trans.applied = list(reversed(patchnames)) + trans.applied
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index 1ece01e..874f81b 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -34,7 +34,7 @@ class _TransPatchMap(dict):
             return self.__stack.patches.get(pn).commit
 
 class StackTransaction(object):
-    def __init__(self, stack, msg):
+    def __init__(self, stack, msg, allow_conflicts = False):
         self.__stack = stack
         self.__msg = msg
         self.__patches = _TransPatchMap(stack)
@@ -43,6 +43,10 @@ class StackTransaction(object):
         self.__error = None
         self.__current_tree = self.__stack.head.data.tree
         self.__base = self.__stack.base
+        if isinstance(allow_conflicts, bool):
+            self.__allow_conflicts = lambda trans: allow_conflicts
+        else:
+            self.__allow_conflicts = allow_conflicts
     stack = property(lambda self: self.__stack)
     patches = property(lambda self: self.__patches)
     def __set_applied(self, val):
@@ -63,10 +67,19 @@ 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()
-        if self.__current_tree != tree:
-            assert iw != None
-            iw.checkout(self.__current_tree, tree)
-            self.__current_tree = tree
+        if self.__current_tree == tree:
+            # No tree change, but we still want to make sure that
+            # there are no unresolved conflicts. Conflicts
+            # conceptually "belong" to the topmost patch, and just
+            # carrying them along to another patch is confusing.
+            if (self.__allow_conflicts(self) or iw == None
+                or not iw.index.conflicts()):
+                return
+            out.error('Need to resolve conflicts first')
+            self.__abort()
+        assert iw != None
+        iw.checkout(self.__current_tree, tree)
+        self.__current_tree = tree
     @staticmethod
     def __abort():
         raise TransactionException(
@@ -214,4 +227,8 @@ class StackTransaction(object):
         self.applied.append(pn)
         out.info('Pushed %s%s' % (pn, s))
         if merge_conflict:
+            # We've just caused conflicts, so we must allow them in
+            # the final checkout.
+            self.__allow_conflicts = lambda trans: True
+
             self.__halt('Merge conflict')

  reply	other threads:[~2008-04-20 22:11 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-20 22:10 [StGit PATCH 00/10] Updated "stg reset" series Karl Hasselström
2008-04-20 22:10 ` Karl Hasselström [this message]
2008-04-20 22:10 ` [StGit PATCH 02/10] Add property with a list of all patch names Karl Hasselström
2008-04-20 22:10 ` [StGit PATCH 03/10] Library functions for tree and blob manipulation Karl Hasselström
2008-04-20 22:10 ` [StGit PATCH 04/10] Write to a stack log when stack is modified Karl Hasselström
2008-04-20 22:10 ` [StGit PATCH 05/10] Add utility function for reordering patches Karl Hasselström
2008-04-20 22:10 ` [StGit PATCH 06/10] New command: stg reset Karl Hasselström
2008-04-20 22:11 ` [StGit PATCH 07/10] Log conflicts separately Karl Hasselström
2008-04-20 22:11 ` [StGit PATCH 08/10] Log conflicts separately for all commands Karl Hasselström
2008-04-20 22:11 ` [StGit PATCH 09/10] Add a --hard flag to stg reset Karl Hasselström
2008-04-20 22:11 ` [StGit PATCH 10/10] Don't write a log entry if there were no changes Karl Hasselström

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080420221027.5837.19012.stgit@yoghurt \
    --to=kha@treskal.com \
    --cc=catalin.marinas@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).