Re: [PATCH] log: improve --follow following renames for non-linear history
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Jun 8, 2026, 15:10 UTC
- Message-ID
- <xmqqpl21vzj2.fsf@gitster.g>
- In-Reply-To
- <aiZipugmA7z8oBcd@collabora.com>
Miklos Vajna <vmiklos@collabora.com> writes:
Show 10 quoted lines
> Have a repo with a subtree merge, do a 'git log --follow prefix/test.c', > the output only contains history in the outer repo, not commits that > were merged via a subtree merge. > > What happened is that 'git log --follow' used to store the followed path > only in opt->diffopt.pathspec, so in case the commit history is > non-linear, and multiple parents had renames to the followed path, then > the end result wasn't really defined: the first commit that happened to > be visited in one of the parents updated opt->diffopt.pathspec, and from > that point, only that updated path was visited.
When describing a problematic symptom you are trying to improve, you should talk about the current state of the system in the present tense. "used to store" makes it sound like in ancient times back when Linus wrote the first version of this feature it was so, but a few years ago that changed, but that is not what you want to say, is it?
The above may sound picky, but using the consistent style of description makes it easier to follow the thought process, especially when you need to read many commits to understand what is going on.
Show 6 quoted lines
> Fix the problem by introducing a commit -> path map > (follow_pathspec_slab) that stores that will be path to follow when > visiting that parent. At the top of log_tree_commit(), if the slab has > an entry for this commit, we replace opt->diffopt.pathspec with it, so > the correct path is followed, even if an unrelated sub-tree changed the > path to be followed to something else.
Can a "map" cut it?
If a history forked at commit A, with two children commit B and commit C, and you started traversing the history from a much later descendant M that merges these two lines of history (i.e., M^1 contains B, M^2 contains C, and A==B^1==C^1), while traversing down from M to B you may find that you need to follow path1 and similarly somewhere between M down to C the path you are following may be path2. And the traversal meets at A. The slab records path1 for B and path2 for C. Wouldn't you need to be able to store both path1 and path2 for commit A? What path do you need to pay attention to when traversing past A to its ancestors?