Subject: [PATCH] Documentation: 'cherry' does not cope well with merges from upstream

From: Jonathan Nieder <[email-masked]>
Date: Thu, 1 Jul 2010 16:09:19 -0500

Although ‘git cherry’ is advertised simply to list commits from
<topic> that have not been merged into <upstream>, internally it
works by checking for patches in <upstream>..<topic> that do not
match a patch in <topic>..<upstream>.  This is fast because there
are not many patches to check, and it makes sense semantically
since even if a new patch patches an old patch from <upstream>,
it cannot be said to have been merged upstream unless it was
applied there at some point after the <topic> and <upstream>
branches diverged.

But.  If the <topic> branch later merges from <upstream>, it
throws a spanner in the works and for such a history ‘git cherry’
is not very useful at all.

Example:

 o---o---F---X'---G---U [upstream]
          \        \
           X----Y---M---T [topic]

Suppose the author of the ‘topic’ branch starts from upstream
commit F and makes a few changes.  One is applied upstream, and
additionally there is some other useful upstream change, so he
performs a merge to include the upstream updates into topic.
The expected output from ‘cherry’ is:

 + T
 + Y
 - X

Consider the author of a different branch, also called ‘topic’, but
this one starts from commit G.  Some infrastructure from an existing 
branch is needed, so first she merges that.  Then she adds her own
commit.  The expected output from ‘cherry’ is:

 + T
 + Y
 + X

since none of the new commits have been applied upstream since
the fork point.

‘cherry’ cannot distinguish between these two cases, in part because
it does not distinguish between parents in a merge commit.

Add a BUGS section to explain the problem.

Reported-by: Frédéric Brière <[email-masked]>
Reported-by: Andrew Pimlott <[email-masked]>
Signed-off-by: Jonathan Nieder <[email-masked]>
---
Hi Andrew,

Andrew Pimlott wrote:

> The documentation for git-cherry says it marks changes in the current
> checkout that have an "equivalent" change in the upstream branch.  It
> even says it's useful when feeding patches upstream by email instead of
> git, which is what I'm doing (with CVS instead of email).  But it
> doesn't seem to work for me.
[...]
>     ~/a% git commit -m 3
>     [master bb13e6c] 3
>      1 files changed, 1 insertions(+), 0 deletions(-)
>     ~/a% cd ../b
>     ~/b% git pull
[...]
>     ~/b% git cherry
>     + 551e90ac390a2a27152661b9cbe73845d237e008

I have not carefully read your example, but maybe this patch might help
explain it.  A correct solution for some cases might include a
‘git cherry --full’ option that scans the full upstream history for
equivalents to patches.

Thoughts?  Improvements?

 Documentation/git-cherry.txt |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt
index fed115a..83e3bdc 100644
--- a/Documentation/git-cherry.txt
+++ b/Documentation/git-cherry.txt
@@ -59,6 +59,21 @@ OPTIONS
 <limit>::
 	Do not report commits up to (and including) limit.
 
+BUGS
+----
+'git cherry' does not cope well with merges from upstream on the
+working branch.  Any commits after the original fork point and
+before the latest merge from upstream will be reported as not found
+in <upstream>.
+
+                       ____*____*____*_____*__> <upstream>
+                      /                     \
+   original fork point                       \
+                      \__+__+__+__+__+__+__+__*_> <head>
+
+While these commits are part of upstream..head, their upstream
+counterparts are not in head..upstream.
+
 SEE ALSO
 --------
 linkgit:git-patch-id[1]
-- 
1.7.1.1