threads / patch / 8927

patchFix "git log --parent -m" from emitting duplicated parent info

Subject: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

## tl;dr

10 messages between Jul 8, 2007 and Jul 9, 2007. Diffs are folded; open one to read it.

replies: 9people: 3as markdown or json

Marco Costalba· Jul 8, 2007, 14:37 UTC · lore

Without this patch in case of a merge, duplicated parents are omitted in first line output, but still listed in following parents information.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
---
Following the hint of someone I submit this patch.
Please take it as a wish of not reverting the patch ;-)
 log-tree.c |   25 +++++++++++++++++--------
 revision.h |    1 +
 2 files changed, 18 insertions(+), 8 deletions(-)
Show changes to 2 files +18 −8

log-tree.c, revision.h

diff --git a/log-tree.c b/log-tree.c
index 24aea6b..e5d40fe 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -6,11 +6,11 @@

  struct decoration name_decoration = { "object names" };

-static void clear_tmp_mark(struct commit_list *p)
+static void clear_flag(struct commit_list *p, unsigned int flag)
 {
 	while (p) {
  		struct commit *c = p->item;
-		c->object.flags &= ~TMP_MARK;
+		c->object.flags &= ~flag;
 		p = p->next;
 	}
 }
@@ -23,7 +23,7 @@ static void show_parents(
 	 * be used locally, but the user should clean
 	 * things up after it is done with them.
 	 */
-	clear_tmp_mark(commit->parents);
+	clear_flag(commit->parents, TMP_MARK);
 	for (p = commit->parents; p ; p = p->next) {
  		struct commit *parent = p->item;
 		if (parent->object.flags & TMP_MARK)
@@ -31,7 +31,7 @@ static void show_parents(struct
  		printf(" %s", diff_unique_abbrev(parent->object.sha1, abbrev));
 		parent->object.flags |= TMP_MARK;
 	}
-	clear_tmp_mark(commit->parents);
+	clear_flag(commit->parents, TMP_MARK);
 }

  static void show_decorations(struct commit *commit)
@@ -391,16 +391,24 @@ static int log_tree_diff(
 		/* If we show individual diffs, show the parent info */
 		log->parent = parents->item;
 	}
-
 	showed_log = 0;
+	clear_flag(parents, TMP_MARK_2);
+
 	for (;;) {
  		struct commit *parent = parents->item;

-		diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
-		log_tree_diff_flush(opt);
+		/* TMP_MARK_2 is a general purpose flag that can
+		 * be used locally nested with TMP_MARK, but the user
+		 * should clean things up after it is done with them.
+		*/
+		if (!opt->parents || !(parent->object.flags & TMP_MARK_2)) {

-		showed_log |= !opt->loginfo;
+			diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
+			log_tree_diff_flush(opt); // will use TMP_MARK

+			showed_log |= !opt->loginfo;
+			parent->object.flags |= TMP_MARK_2;
+		}
 		/* Set up the log info for the next parent, if any.. */
 		parents = parents->next;
 		if (!parents)
@@ -408,6 +416,7 @@ static int log_tree_diff(
 		log->parent = parents->item;
  		opt->loginfo = log;
 	}
+	clear_flag(parents, TMP_MARK_2);
 	return showed_log;
 }

diff --git a/revision.h b/revision.h
index f46b4d5..403507f 100644
--- a/revision.h
+++ b/revision.h
@@ -10,6 +10,7 @@
 #define CHILD_SHOWN	(1u<<6)
 #define ADDED		(1u<<7)	/* Parents already parsed and added? */
 #define SYMMETRIC_LEFT	(1u<<8)
+#define TMP_MARK_2	(1u<<9) /* for isolated cases; clean after use */

  struct rev_info;
  struct log_info;
-- 
1.5.3.rc0.65.g39a4d-dirty
Junio C Hamano· Jul 8, 2007, 18:32 UTC · re: Marco Costalba · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

"Marco Costalba" <mcostalba@gmail.com> writes:
Show 10 quoted lines
> Without this patch in case of a merge, duplicated parents are
> omitted in first line output, but still listed in following
> parents information.
>
> Signed-off-by: Marco Costalba <mcostalba@gmail.com>
> ---
>
> Following the hint of someone I submit this patch.
>
> Please take it as a wish of not reverting the patch ;-)

Sorry, I am puzzled... which patch are you talking about possibly getting reverted?

In any case, the caller asked "log" to:
 1. simplify the history, by giving pathspec,
 2. show the list of parents,
 3. show the diff with each of the parents.

If we omit dupilicated parents in the simplified view from 2., we should be consistent in the output from 3.; I think what your patch does makes sense.

I'll look at it again later.
Junio C Hamano· Jul 9, 2007, 00:37 UTC · re: Marco Costalba · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

This is whitespace damaged in a funny way (some lines do not have leading whitespace while some do).

log_tree_diff() hence log_tree_commit() is caled by codepaths other than "git log -p", and I am not convinced that this patch would not break them. Worrysome.

I wonder why we did not actually remove the duplicate parents from "commit->parents" list after history simplification when we originally did 88494239, instead of filtering only on the output path. Anybody remember the reason?

Johannes Schindelin· Jul 9, 2007, 01:15 UTC · re: Junio C Hamano · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

Hi,
On Sun, 8 Jul 2007, Junio C Hamano wrote:
> I wonder why we did not actually remove the duplicate parents
> >from "commit->parents" list after history simplification when we
> originally did 88494239, instead of filtering only on the output
> path.  Anybody remember the reason?
I do not have that commit here.

Ciao, Dscho

Junio C Hamano· Jul 9, 2007, 01:28 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

Sorry, not 88494239 but this one.
commit 884944239f2ab673cedfaa5e7999d31fd6a46331
Author: Junio C Hamano <junkio@cox.net>
Date:   Sun Jan 29 15:24:42 2006 -0800
    rev-list: omit duplicated parents.
    
    Showing the same parent more than once for a commit does not
    make much sense downstream, so stop it.
    
    This can happen with an incorrectly made merge commit that
    merges the same parent twice, but can happen in an otherwise
    sane development history while squishing the history by taking
    into account only commits that touch specified paths.
    
    For example,
    
    	$ git rev-list --max-count=1 --parents addafaf -- rev-list.c
    
    would have to show this commit ancestry graph:
    
                      .---o---.
                     /         \
                    .---*---o---.
                   /    93b74bc  \
       ---*---o---o-----o---o-----o addafaf
          d8f6b34  \             /
                    .---o---o---.
                     \         /
                      .---*---.
                          3815f42
    
    where 5 independent development tracks, only two of which have
    changes in the specified paths since they forked.  The last
    change for the other three development tracks was done by the
    same commit before they forked, and we were showing that three
    times.
    
    Signed-off-by: Junio C Hamano <junkio@cox.net>
Junio C Hamano· Jul 9, 2007, 01:20 UTC · re: Junio C Hamano · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

Junio C Hamano <gitster@pobox.com> writes:
Show 11 quoted lines
> This is whitespace damaged in a funny way (some lines do not
> have leading whitespace while some do).
>
> log_tree_diff() hence log_tree_commit() is caled by codepaths
> other than "git log -p", and I am not convinced that this patch
> would not break them.  Worrysome.
>
> I wonder why we did not actually remove the duplicate parents
> from "commit->parents" list after history simplification when we
> originally did 88494423, instead of filtering only on the output
> path.  Anybody remember the reason?

In any case, I think this patch would let us revert 88494239 and the "matching" patch for git-log I sent out earlier, and also makes your patch unnecessary.

Seems to pass the test suite, and your original example of checking addafaf with path limiter of "diff.h".

I am a bit worried about the possible fallout, though. There might be some callers that expect to find the same number of parents in commit->parents list and what is recorded in the commit object itself, although I do not think of any, and I tend to think it is broken if there is one.

-- >8 -- [PATCH] remove duplicated parents after history simplification

When we simplify history due to path limits, the parents list for a rewritten commit can end up having duplicates. Instead of filtering them out in the output codepath like earlier commit 88494423 did, remove them much earlier, when the parent rewriting actually happens.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 revision.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)
Show changes to revision.c +21 −1
diff --git a/revision.c b/revision.c
index 5184716..b8a7571 100644
--- a/revision.c
+++ b/revision.c
@@ -1308,6 +1308,26 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
 	}
 }
 
+static int remove_duplicate_parents(struct commit *commit)
+{
+	struct commit_list *p;
+	struct commit_list **pp = &commit->parents;
+
+	/* Examine existing parents while marking ones we have seen... */
+	for (p = commit->parents; p; p = p->next) {
+		struct commit *parent = p->item;
+		if (parent->object.flags & TMP_MARK)
+			continue;
+		parent->object.flags |= TMP_MARK;
+		*pp = p;
+		pp = &p->next;
+	}
+	/* ... and clear the temporary mark */
+	for (p = commit->parents; p; p = p->next)
+		p->item->object.flags &= ~TMP_MARK;
+	return 0;
+}
+
 static int rewrite_parents(struct rev_info *revs, struct commit *commit)
 {
 	struct commit_list **pp = &commit->parents;
@@ -1324,7 +1344,7 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
 		}
 		pp = &parent->next;
 	}
-	return 0;
+	return remove_duplicate_parents(commit);
 }
 
 static int commit_match(struct commit *commit, struct rev_info *opt)
Junio C Hamano· Jul 9, 2007, 01:38 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> I only found this:
>
> http://thread.gmane.org/gmane.comp.version-control.git/29222

Thanks. As it happens, the patch I just sent out is a moral equivalent of your patch in that thread ;-)

We still may need to think about being careful upon --full-history though.

Second try, this time not doing the simplification when --full-history is given.

-- >8 -- [PATCH] remove duplicated parents after history simplification

When we simplify history due to path limits, the parents list for a rewritten commit can end up having duplicates. Instead of filtering them out in the output codepath like earlier commit 88494423 did, remove them much earlier, when the parent information actually gets rewritten.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 revision.c |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)
Show changes to revision.c +21 −0
diff --git a/revision.c b/revision.c
index 5184716..740e6a8 100644
--- a/revision.c
+++ b/revision.c
@@ -1308,6 +1308,25 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
 	}
 }
 
+static void remove_duplicate_parents(struct commit *commit)
+{
+	struct commit_list *p;
+	struct commit_list **pp = &commit->parents;
+
+	/* Examine existing parents while marking ones we have seen... */
+	for (p = commit->parents; p; p = p->next) {
+		struct commit *parent = p->item;
+		if (parent->object.flags & TMP_MARK)
+			continue;
+		parent->object.flags |= TMP_MARK;
+		*pp = p;
+		pp = &p->next;
+	}
+	/* ... and clear the temporary mark */
+	for (p = commit->parents; p; p = p->next)
+		p->item->object.flags &= ~TMP_MARK;
+}
+
 static int rewrite_parents(struct rev_info *revs, struct commit *commit)
 {
 	struct commit_list **pp = &commit->parents;
@@ -1324,6 +1343,8 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
 		}
 		pp = &parent->next;
 	}
+	if (revs->simplify_history)
+		remove_duplicate_parents(commit);
 	return 0;
 }
 
Marco Costalba· Jul 9, 2007, 05:46 UTC · re: Junio C Hamano · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

On 7/9/07, Junio C Hamano <gitster@pobox.com> wrote:
Show 5 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> Second try, this time not doing the simplification when --full-history
> is given.
>

Probably I'm wrong but I would think the first original version with post-filtering is more correct.

Indeed we can use and _do_ use --full-history not only for printing all revisions but to _walk_ the tree in a certain way, different from default.

IMHO --parents + --full-history is absolutely legal because the first flag indicate how to walk the tree and the second flag indicate what to show to the user.

I agree the original patch is much uglier then your last version but I would say is more correct.

Thanks Marco

Junio C Hamano· Jul 9, 2007, 06:19 UTC · re: Marco Costalba · lore

Re: [PATCH] Fix "git log --parent -m" from emitting duplicated parent info

"Marco Costalba" <mcostalba@gmail.com> writes:
> Indeed we can use and _do_ use --full-history not only for printing
> all revisions but to _walk_ the tree in a certain way, different from
> default.

Yes, --full-history essentially tells the machnery to walk all side branches even when a merge takes all the specified paths from one parent's version. You will end up walking all five branches from the first pentapus "addafaf" in git.git history, even if history simplification with pathspec would have narrowed it down to three paths if you did not give that option.

> IMHO --parents + --full-history is absolutely legal because the first
> flag indicate how to walk the tree and the second flag indicate what
> to show to the user.

I think we are in agreement. You are telling the machinery to walk all five branches with --full-history. But you are not telling the machinery to keep the intermediate commits (i.e. you do not give --sparse), so these five branches can be simplified to lead to the same parent. I think I was confused by dense vs simplify_history when I wrote that message in the thread Johannes pointed out:

	http://thread.gmane.org/gmane.comp.version-control.git/29222

Making the duplicate parent removal depend on "dense" makes sense, but the rewrite_parent() codepath is used only when dense anyway.

Thanks for a timely objection and sanity checking.

← back to recent threads