From: Catalin Marinas <catalin.marinas@gmail.com>
To: "Karl Hasselström" <kha@treskal.com>
Cc: git@vger.kernel.org
Subject: Re: [StGit PATCH] Add the --merged option to goto
Date: Tue, 24 Mar 2009 15:40:10 +0000 [thread overview]
Message-ID: <b0943d9e0903240840m3f22b702qd48293caad4187e3@mail.gmail.com> (raw)
In-Reply-To: <20090324131640.GB4040@diana.vm.bytemark.co.uk>
2009/3/24 Karl Hasselström <kha@treskal.com>:
> On 2009-03-23 16:33:04 +0000, Catalin Marinas wrote:
>> Now I understand it better :-). Reading my explanation above, it
>> seems that only the T1..T2 case matters and it can be taken care of
>> in the check_merged() function. Checking whether the tree returned
>> by merge() is different than "ours" should be enough for all the
>> above cases.
>
> Hmm. If the tip of the branch is T1, and we reverse-apply the patch
> T1..T2, we get the merge (base T2, ours T1, theirs T1) ... yeah, I see
> what you mean. The problem isn't that we give T1 as the result of this
> merge -- that's actually the right thing to do -- the problem is that
> you don't actually want a merge. What you want is patch application.
> Maybe the apply_treediff method would do?
Yes, see below for an updated patch.
>> I had the impression that an Index object would hold some state and
>> didn't want to break it. It seems OK to use as long as I don't touch
>> self.temp_index_tree. See below for an updated patch:
>
> Yes, an Index object owns a git index file.
>
> And no, not quite. temp_index_tree is set to the tree we know is
> stored in temp_index right now (or None if we don't know). The idea is
> that we'll often want to read a tree into the index that's already
> there, and by keeping track of this we'll get better performance.
> (This works very well in practice.) Apologies if there aren't comments
> explaining this ... the merge method has some docs on the subject.
I figured this out eventually. Anyway, with apply_treedif() there is
no need for the temp_index_tree. In the updated patch below, I don't
even call write_tree() as it isn't needed (to my understanding).
Whatever is in the index after the check_merged() function doesn't
correspond to any tree so it would need to be re-read.
BTW, I implemented push and pop and it now passes all the "push
--merged" tests. I had to correct the "already_merged" case in
Transaction.push_patch() to generate an empty patch.
Add the --merged option to goto
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.
Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
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/transaction.py b/stgit/lib/transaction.py
index b146648..e2d9b78 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,15 @@ 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:
+ # the resulting patch is empty
+ tree = cd.parent.data.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 +346,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 +386,23 @@ 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 = []
+ self.temp_index.read_tree(self.stack.head.data.tree)
+ # The self.temp_index is modified by apply_treediff() so force
+ # read_tree() the next time merge() is used.
+ self.temp_index_tree = None
+ for pn in reversed(patches):
+ # check whether patch changes can be reversed in the current index
+ cd = self.patches[pn].data
+ if cd.is_nochange():
+ continue
+ try:
+ self.temp_index.apply_treediff(cd.tree, cd.parent.data.tree,
+ quiet = True)
+ merged.append(pn)
+ except git.MergeException:
+ pass
+ return merged
Thanks.
--
Catalin
next prev parent reply other threads:[~2009-03-24 15:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-20 16:15 [StGit PATCH] Add the --merged option to goto Catalin Marinas
2009-03-23 8:45 ` 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 [this message]
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=b0943d9e0903240840m3f22b702qd48293caad4187e3@mail.gmail.com \
--to=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).