Skip to content

Commit 9f38e1e

Browse files
torvaldsgitster
authored andcommitted
Fix up "git log --follow" a bit..
This fixes "git log --follow" to hopefully not leak memory any more, and also cleans it up a bit to look more like some of the other functions that use "diff_queued_diff" (by *not* using it directly as a global in the code, but by instead just taking a pointer to the diff queue and using that). As to "diff_queued_diff", I think it would be better off not as a global at all, but as being just an entry in the "struct diff_options" structure, but that's a separate issue, and there may be some subtle reason for why it's currently a global. Anyway, no real changes. Instead of having a magical first entry in the diff-queue, we now end up just keeping the diff-queue clean, and keeping our "preferred" file pairing in an internal "choice" variable. That makes it easy to switch the choice around when we find a better one. Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 750f7b6 commit 9f38e1e

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

tree-diff.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,15 @@ static inline int diff_might_be_rename(void)
305305
static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
306306
{
307307
struct diff_options diff_opts;
308-
const char *paths[2];
308+
struct diff_queue_struct *q = &diff_queued_diff;
309+
struct diff_filepair *choice;
310+
const char *paths[1];
309311
int i;
310312

313+
/* Remove the file creation entry from the diff queue, and remember it */
314+
choice = q->queue[0];
315+
q->nr = 0;
316+
311317
diff_setup(&diff_opts);
312318
diff_opts.recursive = 1;
313319
diff_opts.detect_rename = DIFF_DETECT_RENAME;
@@ -320,28 +326,41 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
320326
diff_tree(t1, t2, base, &diff_opts);
321327
diffcore_std(&diff_opts);
322328

323-
/* NOTE! Ignore the first diff! That was the old one! */
324-
for (i = 1; i < diff_queued_diff.nr; i++) {
325-
struct diff_filepair *p = diff_queued_diff.queue[i];
329+
/* Go through the new set of filepairing, and see if we find a more interesting one */
330+
for (i = 0; i < q->nr; i++) {
331+
struct diff_filepair *p = q->queue[i];
326332

327333
/*
328334
* Found a source? Not only do we use that for the new
329-
* diff_queued_diff, we also use that as the path in
335+
* diff_queued_diff, we will also use that as the path in
330336
* the future!
331337
*/
332338
if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) {
333-
diff_queued_diff.queue[0] = p;
339+
/* Switch the file-pairs around */
340+
q->queue[i] = choice;
341+
choice = p;
342+
343+
/* Update the path we use from now on.. */
334344
opt->paths[0] = xstrdup(p->one->path);
335345
diff_tree_setup_paths(opt->paths, opt);
336346
break;
337347
}
338348
}
339349

340350
/*
341-
* Then, ignore any but the first entry! It might be the old one,
342-
* or it might be the rename/copy we found
351+
* Then, discard all the non-relevane file pairs...
352+
*/
353+
for (i = 0; i < q->nr; i++) {
354+
struct diff_filepair *p = q->queue[i];
355+
diff_free_filepair(p);
356+
}
357+
358+
/*
359+
* .. and re-instate the one we want (which might be either the
360+
* original one, or the rename/copy we found)
343361
*/
344-
diff_queued_diff.nr = 1;
362+
q->queue[0] = choice;
363+
q->nr = 1;
345364
}
346365

347366
int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)

0 commit comments

Comments
 (0)