From: Pablo Date: Sat, 04 Apr 2026 16:08:25 GMT Subject: Re: [RFC] Show empty root commits when using --simplify-by-decoration Message-ID: In-Reply-To: El sáb, 4 abr 2026 a las 17:18, Fernando Ramos () escribió: Hi Fernando, I think I can bring some clarity to your second issue. > > Regarding "--simplify-by-decoration", I found a somewhat unexpected behavior. > > Let's say we have a repository with two branches ("master" and "branch") and > this history structure: > > a * b * > | | > 2 *------------------' > | > 1 * > | > start * > > If I now run this... > > $ git log --graph --all --oneline --simplify-by-decoration > > ...I get this (which is expected and ok): > > * 0f3892d (branch) b > | * 0c37d8c (master) a > |/ > * d783631 Start > > HOWEVER, if the root commit ("start") is an empty commit, then the same command > will print this instead: > > * 7abc10a (branch) b > * 14d51e1 (master) a > > ...which is confusing for two reasons: > > 1. The graph is not showing a common origin. > 2. Because "root" commits use an "*", it looks like "a" is the parent of "b", > when the reality is that the graph is showing two independen origins. > > Issue (1) seems to be caused by the fact that empty root commits are marked as > TREESAME and thus discarded when showing the graph. This can be fixed with > patch #1 at the end of this email. Note, however, that this patch partially > breaks what Taylor did on 1343c893138 (I say "partially" because it only happens > when using "--simplify-by-decoration"). I have CC'ed Taylor in case he has any > comments about it. > > Issue (2) can be "fixed" by using a diferent character (for example "I") for > root commits (ie. those without parents), which can be done with patch #2 at the > end of this email. This has actually been discussed before and it was ruled out some years ago. https://lore.kernel.org/git/xmqqwnwajbuj.fsf@gitster.c.googlers.com/ You would need more symbols for different roots, --boundary, --left-right and what if a commit that is not a root has its parents excluded, would you change the symbol even tho it is not a root? You might find interesting a patch I'm working on that tackles that confusing look when two "parentless" commits are stacked. https://lore.kernel.org/git/20260404092425.550346-1-pabloosabaterr@gmail.com/ This answer from junio might be helpful as well: https://lore.kernel.org/git/xmqqbjfzn6ku.fsf@gitster.g/ > > With those two patches applied, this is what the output looks like in both cases > (with the root commit being empty or not): > > * 7abc10a (branch) b > | * 14d51e1 (master) a > |/ > I c0db521 Start > > Let me know what you think and whether you want me to send a proper patch that > includes (1) or (2) or (1)+(2). > > Thanks! > > PS: Path #3 at the end of this emails includes a dummy script to quickly > recreate the two scenarios described above. > > > > -------------------------------------------------------------------------------- > Patch #1 > -------------------------------------------------------------------------------- > > diff --git a/revision.c b/revision.c > index c9b8bfd09f..0e7bf2ed3c 100644 > --- a/revision.c > +++ b/revision.c > @@ -978,15 +978,17 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) > return; > > if (!commit->parents) { > - /* > - * Pretend as if we are comparing ourselves to the > - * (non-existent) first parent of this commit object. Even > - * though no such parent exists, its changed-path Bloom filter > - * (if one exists) is relative to the empty tree, using Bloom > - * filters is allowed here. > - */ > - if (rev_same_tree_as_empty(revs, commit, 0)) > - commit->object.flags |= TREESAME; > + if (!revs->simplify_by_decoration) { > + /* > + * Pretend as if we are comparing ourselves to the > + * (non-existent) first parent of this commit object. Even > + * though no such parent exists, its changed-path Bloom filter > + * (if one exists) is relative to the empty tree, using Bloom > + * filters is allowed here. > + */ > + if (rev_same_tree_as_empty(revs, commit, 0)) > + commit->object.flags |= TREESAME; > + } > return; > } > > > -------------------------------------------------------------------------------- > Patch #2 > -------------------------------------------------------------------------------- > > diff --git a/revision.c b/revision.c > index 31808e3df0..c9b8bfd09f 100644 > --- a/revision.c > +++ b/revision.c > @@ -4565,7 +4565,7 @@ const char *get_revision_mark(const struct rev_info *revs, const struct commit * > else > return ">"; > } else if (revs->graph) > - return "*"; > + return commit->parents ? "*" : "I"; This only focuses on real roots, what about commits with excluded parents. for example: O---A X---Y If you'd run 'git log --graph O..A Y', it shows A, Y, X but because it only look for roots it ends up looking like: * A <- not a root but O is excluded so it seems like one * Y I X This would make A and Y look related, also the "I" makes it very confusing because the vertical edges are very similar "|". > else if (revs->cherry_mark) > return "+"; > return ""; > > > -------------------------------------------------------------------------------- > Patch #3 > -------------------------------------------------------------------------------- > > diff --git a/build_example.sh b/build_example.sh > new file mode 100755 > index 0000000000..60f63c5344 > --- /dev/null > +++ b/build_example.sh > @@ -0,0 +1,61 @@ > +#!/bin/bash > + > +################################################################################ > +# Example #1 > +################################################################################ > +# > +# This will create this a repo with this history structure: > +# > +# a * (master) b * (branch) > +# | | > +# 2 * -----------------' > +# | > +# 1 * > +# | > +# start * > + > +rm -rf EXAMPLE1 || true; mkdir -p EXAMPLE1; cd EXAMPLE1 > + > +touch start.txt; git init; git add start.txt; git commit -m 'Start' > +touch 1.txt; git add 1.txt; git commit -m '1' > +touch 2.txt; git add 2.txt; git commit -m '2' > +touch a.txt; git add a.txt; git commit -m 'a' > +git checkout -b branch HEAD^ > +touch b.txt; git add b.txt; git commit -m 'b' > + > +git log --graph --all --oneline --simplify-by-decoration > +# The previous command will print this, which is what we expected: > +# > +# * 0f3892d (HEAD -> branch) b > +# | * 0c37d8c (master) a > +# |/ > +# * d783631 Start > + > +cd .. > + > + > + > +################################################################################ > +# Example #2 > +################################################################################ > +# > +# This will create this a repo with the same structure as before, but this time > +# the root commit ("start") is an empty one. > + > +rm -rf EXAMPLE2 || true; mkdir -p EXAMPLE2; cd EXAMPLE2 > + > +git init; git commit --allow-empty -m 'Start' > +touch 1.txt; git add 1.txt; git commit -m '1' > +touch 2.txt; git add 2.txt; git commit -m '2' > +touch a.txt; git add a.txt; git commit -m 'a' > +git checkout -b branch HEAD^ > +touch b.txt; git add b.txt; git commit -m 'b' > + > +git log --graph --all --oneline --simplify-by-decoration > +# The previous command will print this, which is unexpected: > +# > +# * 7abc10a (HEAD -> branch) b > +# * 14d51e1 (master) a > + > +cd .. > + > > One more thing, even if it's an RFC it would be much easier for reviewers if the patches were sent as git format-patch (one each email) with a cover letter, discussing your RFC, so anyone can use git am and b4 to apply the patches. Hope this helps, Pablo