Skip to content

Commit e6c06e8

Browse files
To1negitster
authored andcommitted
last-modified: fix bug when some paths remain unhandled
The recently introduced new subcommand git-last-modified(1) runs into an error in some scenarios. It then would exit with the message: BUG: paths remaining beyond boundary in last-modified This seems to happens for example when criss-cross merges are involved. In that scenario, the function diff_tree_combined() gets called. The function diff_tree_combined() copies the `struct diff_options` from the input `struct rev_info` to override some flags. One flag is `recursive`, which is always set to 1. This has been the case since the inception of this function in af3feef (diff-tree -c: show a merge commit a bit more sensibly., 2006-01-24). This behavior is incompatible with git-last-modified(1), when called non-recursive (which is the default). The last-modified machinery uses a hashmap for all the paths it wants to get the last-modified commit for. Through log_tree_commit() the callback mark_path() is called. The diff machinery uses diff_tree_combined() internally, and due to it's recursive behavior the callback receives entries inside subtrees, but not the subtree entries themselves. So a directory is never expelled from the hashmap, and the BUG() statement gets hit. Because there are many callers calling into diff_tree_combined(), both directly and indirectly, we cannot simply change it's behavior. Instead, add a flag `no_recursive_diff_tree_combined` which supresses the behavior of diff_tree_combined() to override `recursive` and set this flag in builtin/last-modified.c. Signed-off-by: Toon Claes <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 215033b commit e6c06e8

File tree

4 files changed

+26
-1
lines changed

4 files changed

+26
-1
lines changed

builtin/last-modified.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ static int last_modified_init(struct last_modified *lm, struct repository *r,
265265
lm->rev.boundary = 1;
266266
lm->rev.no_commit_id = 1;
267267
lm->rev.diff = 1;
268+
lm->rev.diffopt.flags.no_recursive_diff_tree_combined = 1;
268269
lm->rev.diffopt.flags.recursive = lm->recursive;
269270
lm->rev.diffopt.flags.tree_in_recursive = lm->show_trees;
270271

combine-diff.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1515,8 +1515,9 @@ void diff_tree_combined(const struct object_id *oid,
15151515

15161516
diffopts = *opt;
15171517
copy_pathspec(&diffopts.pathspec, &opt->pathspec);
1518-
diffopts.flags.recursive = 1;
15191518
diffopts.flags.allow_external = 0;
1519+
if (!opt->flags.no_recursive_diff_tree_combined)
1520+
diffopts.flags.recursive = 1;
15201521

15211522
/* find set of paths that everybody touches
15221523
*

diff.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ struct diff_flags {
126126
unsigned recursive;
127127
unsigned tree_in_recursive;
128128

129+
/*
130+
* Historically diff_tree_combined() overrides recursive to 1. To
131+
* suppress this behavior, set the flag below.
132+
* It has no effect if recursive is already set to 1.
133+
*/
134+
unsigned no_recursive_diff_tree_combined;
135+
129136
/* Affects the way how a file that is seemingly binary is treated. */
130137
unsigned binary;
131138
unsigned text;

t/t8020-last-modified.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ test_expect_success 'only last-modified files in the current tree' '
128128
EOF
129129
'
130130

131+
test_expect_success 'last-modified with subdir and criss-cross merge' '
132+
git checkout -b branch-k1 1 &&
133+
mkdir -p a k &&
134+
test_commit k1 a/file2 &&
135+
git checkout -b branch-k2 &&
136+
test_commit k2 k/file2 &&
137+
git checkout branch-k1 &&
138+
test_merge km2 branch-k2 &&
139+
test_merge km3 3 &&
140+
check_last_modified <<-\EOF
141+
km3 a
142+
k2 k
143+
1 file
144+
EOF
145+
'
146+
131147
test_expect_success 'cross merge boundaries in blaming' '
132148
git checkout HEAD^0 &&
133149
git rm -rf . &&

0 commit comments

Comments
 (0)