On 27/02/06, Catalin Marinas <catalin.marinas@xxxxxxxxx> wrote: > An idea (untested, I don't even know whether it's feasible) would be to > check which patches were merged by reverse-applying them starting with > the last. In this situation, all the merged patches should just revert > their changes. You only need to do a git-diff between the bottom and the > top of the patch and git-apply the output (maybe without even modifying > the tree). If this operation succeeds, the patch was integrated and you > don't even need to push it. I tried some simple tests with the idea above. I attached a patch if you'd like to try (I won't push it to the main StGIT repository yet. For safety reasons, it only skips the merged patches when pushing them. A future version could simply delete the merged patches. -- Catalin
Add a merged upstream test for pull and push From: Catalin Marinas <catalin.marinas@xxxxxxxxx> This patch adds the --merged option to both pull and push commands. With this option, these commands will first try to check which patches were merged upstream by reverse-applying them in reverse order. This should solve the situation where several patches modify the same line in a file. Signed-off-by: Catalin Marinas <catalin.marinas@xxxxxxxxx> --- stgit/commands/pull.py | 20 +++++++++++++++++++- stgit/commands/push.py | 17 ++++++++++++++++- stgit/git.py | 12 +++++++++--- stgit/stack.py | 20 ++++++++++++++++++++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/stgit/commands/pull.py b/stgit/commands/pull.py index 843b579..5d75530 100644 --- a/stgit/commands/pull.py +++ b/stgit/commands/pull.py @@ -39,6 +39,9 @@ format.""" options = [make_option('-n', '--nopush', help = 'do not push the patches back after pulling', + action = 'store_true'), + make_option('-m', '--merged', + help = 'check for patches merged upstream (slower)', action = 'store_true')] def func(parser, options, args): @@ -77,12 +80,27 @@ def func(parser, options, args): # push the patches back if options.nopush: applied = [] + + # check for patches merged upstream + if options.merged: + merged = crt_series.merged_patches(patches) + else: + merged = [] + for p in applied: + if p in merged: + print 'Patch "%s" merged upstream' % p + continue + print 'Pushing patch "%s"...' % p, sys.stdout.flush() - crt_series.push_patch(p) + + modified = crt_series.push_patch(p) + if crt_series.empty_patch(p): print 'done (empty patch)' + elif modified: + print 'done (modified)' else: print 'done' diff --git a/stgit/commands/push.py b/stgit/commands/push.py index 9924a78..72b2663 100644 --- a/stgit/commands/push.py +++ b/stgit/commands/push.py @@ -49,6 +49,9 @@ options = [make_option('-a', '--all', make_option('--reverse', help = 'push the patches in reverse order', action = 'store_true'), + make_option('-m', '--merged', + help = 'check for patches merged upstream (slower)', + action = 'store_true'), make_option('--undo', help = 'undo the last push operation', action = 'store_true')] @@ -134,9 +137,21 @@ def func(parser, options, args): elif forwarded == 1: print 'Fast-forwarded patch "%s"' % patches[0] - for p in patches[forwarded:]: + patches = patches[forwarded:] + + # check for patches merged upstream + if options.merged: + merged = crt_series.merged_patches(patches) + else: + merged = [] + + for p in patches: is_patch_appliable(p) + if p in merged: + print 'Patch "%s" merged upstream' % p + continue + print 'Pushing patch "%s"...' % p, sys.stdout.flush() diff --git a/stgit/git.py b/stgit/git.py index 016bc3a..66b8612 100644 --- a/stgit/git.py +++ b/stgit/git.py @@ -462,14 +462,20 @@ def commit(message, files = None, parent return commit_id -def apply_diff(rev1, rev2): +def apply_diff(rev1, rev2, check_index = True): """Apply the diff between rev1 and rev2 onto the current index. This function doesn't need to raise an exception since it is only used for fast-pushing a patch. If this operation fails, the pushing would fall back to the three-way merge. """ - return os.system('git-diff-tree -p %s %s | git-apply --index 2> /dev/null' - % (rev1, rev2)) == 0 + if check_index: + index_opt = '--index' + else: + index_opt = '' + cmd = 'git-diff-tree -p %s %s | git-apply %s 2> /dev/null' \ + % (rev1, rev2, index_opt) + + return os.system(cmd) == 0 def merge(base, head1, head2): """Perform a 3-way merge between base, head1 and head2 into the diff --git a/stgit/stack.py b/stgit/stack.py index e1c55f0..9d5f043 100644 --- a/stgit/stack.py +++ b/stgit/stack.py @@ -780,6 +780,26 @@ class Series: return forwarded + def merged_patches(self, names): + """Test which patches were merged upstream by reverse-applying + them in reverse order. The function returns the list of + patches detected to have been applied. The state of the tree + is restored to the original one + """ + patches = [Patch(name, self.__patch_dir, self.__refs_dir) + for name in names] + patches.reverse() + + merged = [] + for p in patches: + if git.apply_diff(p.get_top(), p.get_bottom(), False): + merged.append(p.get_name()) + merged.reverse() + + git.reset() + + return merged + def push_patch(self, name): """Pushes a patch on the stack """