git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: bug?: stgit creates (unneccessary?) conflicts when pulling

From
CMCatalin Marinas <catalin.marinas@gmail.com>
Date
Feb 28, 2006, 15:00 UTC
Message-ID
<b0943d9e0602280700p132c6da2v@mail.gmail.com>
In-Reply-To
<44037A5C.6080409@gmail.com>
On 27/02/06, Catalin Marinas <catalin.marinas@gmail.com> wrote:
Show 7 quoted lines
> 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@gmail.com>

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@gmail.com>
---
 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
         """
Previous: Catalin MarinasNext: Catalin Marinas
Message 4 of 22 in “bug?: stgit creates (unneccessary?) conflicts when pulling”
  1. Karl HasselströmFeb 27, 2006
  2. Sam VilainFeb 27, 2006
  3. Catalin MarinasFeb 27, 2006
  4. Catalin MarinasFeb 28, 2006
  5. Catalin MarinasFeb 28, 2006
  6. Catalin MarinasFeb 28, 2006
  7. Chuck LeverMar 1, 2006
  8. Catalin MarinasMar 1, 2006
  9. Karl HasselströmMar 3, 2006
  10. Catalin MarinasMar 3, 2006
  11. Karl HasselströmMar 3, 2006
  12. Catalin MarinasMar 3, 2006
  13. Shawn PearceFeb 27, 2006
  14. Catalin MarinasMar 1, 2006
  15. Shawn PearceMar 1, 2006
  16. Catalin MarinasMar 1, 2006
  17. Shawn PearceMar 1, 2006
  18. Catalin MarinasMar 9, 2006
  19. Junio C HamanoMar 9, 2006
  20. Catalin MarinasMar 10, 2006
  21. Junio C HamanoMar 11, 2006
  22. Shawn PearceMar 10, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.