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

[PATCH] log: let --follow follow renames in merge commits

From
Miklos Vajna <vmiklos@collabora.com>
Date
May 12, 2026, 07:21 UTC
Message-ID
<agLU58gbG1y7KLz-@collabora.com>

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.

This is inconsistent, since doing a 'git blame prefix/test.c' does find the original commits. This works because find_rename() in blame.c is invoked for each parent, and there diff_tree_oid() is used, which uses try_to_follow_renames(). This means that in case a rename happens as part of a merge commit, git blame can follow that rename.

Fix the problem in a similar way for the 'git log --follow' case: in case log_tree_diff() finds a merge commit and it would return early, then do some extra work in the follow_renames case first. Check each parent, use diff_tree_oid() and if found_follow is set, then work with that parent instead of returning.

This means that users examining the history of a repo with subtree merges can see all commits to a file with a single 'git log --follow' invocation, instead of one invocation for the outer repo and one for the history before the subtree merge.

Signed-off-by: Miklos Vajna <vmiklos@collabora.com>
---
Hi Junio,

I sent this out a week ago at <https://lore.kernel.org/git/afmfSa-p-9vuDL3E@collabora.com/T/#u>, I didn't get any reply to it -- so I'm somewhat optimistic that the patch itself is a good idea, seeing no negative comments.

So this is a resend, this time to you, CC'ing the list, rather than the other way around.

Could you please review this?
Thanks,
Miklos
 log-tree.c                          | 20 ++++++++++++++++-
 t/meson.build                       |  1 +
 t/t4218-log-follow-subtree-merge.sh | 34 +++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100755 t/t4218-log-follow-subtree-merge.sh
diff --git a/log-tree.c b/log-tree.c
index 7e048701d0..bce09c7dac 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1142,8 +1142,26 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 				/* Show parent info for multiple diffs */
 				log->parent = parents->item;
 			}
-		} else
+		} else {
+			if (opt->diffopt.flags.follow_renames) {
+				/*
+				 * Detect a rename across one of the parents.
+				 * Check each parent till we find a follow.
+				 */
+				struct commit_list *p;
+				for (p = parents; p; p = p->next) {
+					parse_commit_or_die(p->item);
+					diff_tree_oid(get_commit_tree_oid(p->item),
+						      oid, "", &opt->diffopt);
+					diff_queue_clear(&diff_queued_diff);
+					if (opt->diffopt.found_follow) {
+						opt->diffopt.found_follow = 0;
+						break;
+					}
+				}
+			}
 			return 0;
+		}
 	}
 
 	showed_log = 0;
diff --git a/t/meson.build b/t/meson.build
index 7528e5cda5..b4ae8d76d8 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -574,6 +574,7 @@ integration_tests = [
   't4215-log-skewed-merges.sh',
   't4216-log-bloom.sh',
   't4217-log-limit.sh',
+  't4218-log-follow-subtree-merge.sh',
   't4252-am-options.sh',
   't4253-am-keep-cr-dos.sh',
   't4254-am-corrupt.sh',
diff --git a/t/t4218-log-follow-subtree-merge.sh b/t/t4218-log-follow-subtree-merge.sh
new file mode 100755
index 0000000000..7ca607cbb8
--- /dev/null
+++ b/t/t4218-log-follow-subtree-merge.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+test_description='Test --follow follows renames across subtree merges'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'setup subtree-merged repository' '
+	git init inner &&
+	echo inner >inner/inner.txt &&
+	git -C inner add inner.txt &&
+	git -C inner commit -m "inner init" &&
+
+	git init outer &&
+	echo outer >outer/outer.txt &&
+	git -C outer add outer.txt &&
+	git -C outer commit -m "outer init" &&
+
+	git -C outer fetch ../inner master &&
+	git -C outer merge -s ours --no-commit --allow-unrelated-histories \
+		FETCH_HEAD &&
+	git -C outer read-tree --prefix=inner/ -u FETCH_HEAD &&
+	git -C outer commit -m "Merge inner repo into inner/ subdirectory"
+'
+
+test_expect_success '--follow finds the pre-merge commit through a subtree merge' '
+	git -C outer log --follow --pretty=tformat:%s inner/inner.txt >actual &&
+	echo "inner init" >expect &&
+	test_cmp expect actual
+'
+
+test_done
-- 
2.51.0
Next: Miklos Vajna
Message 1 of 18 in “log: let --follow follow renames in merge commits”
  1. log: let --follow follow renames in merge commitsMiklos Vajna, May 12, 2026
  2. Miklos VajnaMay 19, 2026
  3. Junio C HamanoMay 19, 2026
  4. Junio C HamanoMay 19, 2026
  5. log: improve --follow following renames for non-linear historyMiklos Vajna, Jun 8, 2026
  6. Junio C HamanoJun 8, 2026
  7. log: improve --follow following renames for non-linear historyMiklos Vajna, Jun 11, 2026
  8. Junio C HamanoJun 11, 2026
  9. log: improve --follow following renames for non-linear historyMiklos Vajna, Jun 15, 2026
  10. log: improve --follow following renames for non-linear historyMiklos Vajna, Jun 22, 2026
  11. Junio C HamanoJun 22, 2026
  12. Miklos VajnaJun 23, 2026
  13. Junio C HamanoJun 12, 2026
  14. Miklos VajnaMay 20, 2026
  15. Jeff KingMay 22, 2026
  16. log: improve --follow following renames in merge commitsMiklos Vajna, May 23, 2026
  17. Miklos VajnaMay 30, 2026
  18. Miklos VajnaJun 4, 2026

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.