From: Catalin Marinas <catalin.marinas@arm.com>
To: git@vger.kernel.org, "Karl Hasselström" <kha@treskal.com>
Subject: [StGit PATCH] Add the --merged option to goto
Date: Fri, 20 Mar 2009 16:15:45 +0000 [thread overview]
Message-ID: <20090320161233.28989.82497.stgit@pc1117.cambridge.arm.com> (raw)
This patch adds support for checking which patches were already merged
upstream. This checking is done by trying to reverse-apply the patches
in the index before pushing them onto the stack. The trivial merge cases
in Index.merge() are ignored when performing this operation otherwise
the results could be wrong (e.g. a patch adding a hunk and a subsequent
patch canceling the previous change would both be considered merged).
Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
This is in preparation for the updating of the push command where we
have this functionality (I think we had it for goto as well but was lost
with the update to stgit.lib). Test cases with --merged are already done
for the push command, so I haven't added any for goto (but I'll push
this patch only after push is updated).
stgit/argparse.py | 4 ++++
stgit/commands/goto.py | 12 +++++++++---
stgit/lib/git.py | 15 ++++++++-------
stgit/lib/transaction.py | 42 +++++++++++++++++++++++++++++++++++-------
4 files changed, 56 insertions(+), 17 deletions(-)
diff --git a/stgit/argparse.py b/stgit/argparse.py
index 85ee6e3..765579c 100644
--- a/stgit/argparse.py
+++ b/stgit/argparse.py
@@ -225,6 +225,10 @@ def keep_option():
short = 'Keep the local changes',
default = config.get('stgit.autokeep') == 'yes')]
+def merged_option():
+ return [opt('-m', '--merged', action = 'store_true',
+ short = 'Check for patches merged upstream')]
+
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 66f49df..839b75c 100644
--- a/stgit/commands/goto.py
+++ b/stgit/commands/goto.py
@@ -28,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 = argparse.keep_option()
+options = argparse.keep_option() + argparse.merged_option()
directory = common.DirectoryHasRepositoryLib()
@@ -47,8 +47,14 @@ def func(parser, options, args):
assert not trans.pop_patches(lambda pn: pn in to_pop)
elif patch in trans.unapplied:
try:
- for pn in trans.unapplied[:trans.unapplied.index(patch)+1]:
- trans.push_patch(pn, iw, allow_interactive = True)
+ to_push = trans.unapplied[:trans.unapplied.index(patch)+1]
+ if options.merged:
+ merged = set(trans.check_merged(to_push))
+ else:
+ merged = set()
+ for pn in to_push:
+ trans.push_patch(pn, iw, allow_interactive = True,
+ already_merged = pn in merged)
except transaction.TransactionHalted:
pass
elif patch in trans.hidden:
diff --git a/stgit/lib/git.py b/stgit/lib/git.py
index e0a3c96..875e352 100644
--- a/stgit/lib/git.py
+++ b/stgit/lib/git.py
@@ -732,7 +732,7 @@ class Index(RunWithEnv):
# to use --binary.
self.apply(self.__repository.diff_tree(tree1, tree2, ['--full-index']),
quiet)
- def merge(self, base, ours, theirs, current = None):
+ def merge(self, base, ours, theirs, current = None, check_trivial = True):
"""Use the index (and only the index) to do a 3-way merge of the
L{Tree}s C{base}, C{ours} and C{theirs}. The merge will either
succeed (in which case the first half of the return value is
@@ -752,12 +752,13 @@ class Index(RunWithEnv):
assert current == None or isinstance(current, Tree)
# Take care of the really trivial cases.
- if base == ours:
- return (theirs, current)
- if base == theirs:
- return (ours, current)
- if ours == theirs:
- return (ours, current)
+ if check_trivial:
+ if base == ours:
+ return (theirs, current)
+ if base == theirs:
+ return (ours, current)
+ if ours == theirs:
+ return (ours, current)
if current == theirs:
# Swap the trees. It doesn't matter since merging is
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index b146648..8cd5e50 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -297,7 +297,8 @@ class StackTransaction(object):
out.info('Deleted %s%s' % (pn, s))
return popped
- def push_patch(self, pn, iw = None, allow_interactive = False):
+ def push_patch(self, pn, iw = None, allow_interactive = False,
+ already_merged = 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."""
@@ -305,11 +306,14 @@ class StackTransaction(object):
cd = orig_cd.set_committer(None)
oldparent = cd.parent
cd = cd.set_parent(self.top)
- base = oldparent.data.tree
- ours = cd.parent.data.tree
- theirs = cd.tree
- tree, self.temp_index_tree = self.temp_index.merge(
- base, ours, theirs, self.temp_index_tree)
+ if already_merged:
+ tree = cd.tree
+ else:
+ base = oldparent.data.tree
+ ours = cd.parent.data.tree
+ theirs = cd.tree
+ tree, self.temp_index_tree = self.temp_index.merge(
+ base, ours, theirs, self.temp_index_tree)
s = ''
merge_conflict = False
if not tree:
@@ -341,7 +345,9 @@ class StackTransaction(object):
else:
comm = None
s = ' (unmodified)'
- if not merge_conflict and cd.is_nochange():
+ if already_merged:
+ s = ' (merged)'
+ elif not merge_conflict and cd.is_nochange():
s = ' (empty)'
out.info('Pushed %s%s' % (pn, s))
def update():
@@ -379,3 +385,25 @@ class StackTransaction(object):
assert set(self.unapplied + self.hidden) == set(unapplied + hidden)
self.unapplied = unapplied
self.hidden = hidden
+
+ def check_merged(self, patches):
+ """Return a subset of patches already merged."""
+ merged = []
+ temp_index = self.__stack.repository.temp_index()
+ temp_index_tree = None
+ ours = self.stack.head.data.tree
+
+ for pn in reversed(patches):
+ # check whether patch changes can be reversed in the current tree
+ cd = self.patches[pn].data
+ base = cd.tree
+ theirs = cd.parent.data.tree
+ tree, temp_index_tree = \
+ temp_index.merge(base, ours, theirs, temp_index_tree,
+ check_trivial = False)
+ if tree:
+ merged.append(pn)
+ ours = tree
+
+ temp_index.delete()
+ return merged
next reply other threads:[~2009-03-20 16:17 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-20 16:15 Catalin Marinas [this message]
2009-03-23 8:45 ` [StGit PATCH] Add the --merged option to goto Karl Hasselström
2009-03-23 16:33 ` Catalin Marinas
2009-03-24 13:16 ` Karl Hasselström
2009-03-24 15:40 ` Catalin Marinas
2009-03-25 9:05 ` Karl Hasselström
2009-03-25 10:24 ` Catalin Marinas
2009-03-26 11:15 ` Karl Hasselström
2009-03-30 16:01 ` Catalin Marinas
2009-03-31 7:27 ` 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=20090320161233.28989.82497.stgit@pc1117.cambridge.arm.com \
--to=catalin.marinas@arm.com \
--cc=catalin.marinas@gmail.com \
--cc=git@vger.kernel.org \
--cc=kha@treskal.com \
/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).