342
struct diff_options *options, void *data)
343
{
344
int i;
345
+ struct string_list *changed = data;
346
347
/*
348
* Handle files below a directory first, in case they are all deleted
358
case DIFF_STATUS_DELETED:
359
printf("D ");
360
print_path(spec->path);
361
+ string_list_insert(changed, spec->path);
362
putchar('\n');
363
break;
364
365
case DIFF_STATUS_COPIED:
366
case DIFF_STATUS_RENAMED:
365
- printf("%c ", q->queue[i]->status);
366
- print_path(ospec->path);
367
- putchar(' ');
368
- print_path(spec->path);
369
- putchar('\n');
370
-
371
- if (!oidcmp(&ospec->oid, &spec->oid) &&
372
- ospec->mode == spec->mode)
373
- break;
367
+ /*
368
+ * If a change in the file corresponding to ospec->path
369
+ * has been observed, we cannot trust its contents
370
+ * because the diff is calculated based on the prior
371
+ * contents, not the current contents. So, declare a
372
+ * copy or rename only if there was no change observed.
373
+ */
374
+ if (!string_list_has_string(changed, ospec->path)) {
375
+ printf("%c ", q->queue[i]->status);
376
+ print_path(ospec->path);
377
+ putchar(' ');
378
+ print_path(spec->path);
379
+ string_list_insert(changed, spec->path);
380
+ putchar('\n');
381
+
382
+ if (!oidcmp(&ospec->oid, &spec->oid) &&
383
+ ospec->mode == spec->mode)
384
+ break;
385
+ }
386
/* fallthrough */
387
388
case DIFF_STATUS_TYPE_CHANGED:
403
get_object_mark(object));
404
}
405
print_path(spec->path);
406
+ string_list_insert(changed, spec->path);
407
putchar('\n');
408
break;
409
539
*end = out->buf + out->len;
540
}
541
529
-static void handle_commit(struct commit *commit, struct rev_info *rev)
542
+static void handle_commit(struct commit *commit, struct rev_info *rev,
543
+ struct string_list *paths_of_changed_objects)
544
{
545
int saved_output_format = rev->diffopt.output_format;
546
const char *commit_buffer;
627
if (full_tree)
628
printf("deleteall\n");
629
log_tree_diff_flush(rev);
630
+ string_list_clear(paths_of_changed_objects, 0);
631
rev->diffopt.output_format = saved_output_format;
632
633
printf("\n");
643
return strbuf_detach(&out, len);
644
}
645
631
-static void handle_tail(struct object_array *commits, struct rev_info *revs)
646
+static void handle_tail(struct object_array *commits, struct rev_info *revs,
647
+ struct string_list *paths_of_changed_objects)
648
{
649
struct commit *commit;
650
while (commits->nr) {
651
commit = (struct commit *)commits->objects[commits->nr - 1].item;
652
if (has_unshown_parent(commit))
653
return;
638
- handle_commit(commit, revs);
654
+ handle_commit(commit, revs, paths_of_changed_objects);
655
commits->nr--;
656
}
657
}
991
char *export_filename = NULL, *import_filename = NULL;
992
uint32_t lastimportid;
993
struct string_list refspecs_list = STRING_LIST_INIT_NODUP;
994
+ struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP;
995
struct option options[] = {
996
OPT_INTEGER(0, "progress", &progress,
997
N_("show progress after <n> objects")),
1064
if (prepare_revision_walk(&revs))
1065
die("revision walk setup failed");
1066
revs.diffopt.format_callback = show_filemodify;
1067
+ revs.diffopt.format_callback_data = &paths_of_changed_objects;
1068
DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
1069
while ((commit = get_revision(&revs))) {
1070
if (has_unshown_parent(commit)) {
1071
add_object_array(&commit->object, NULL, &commits);
1072
}
1073
else {
1056
- handle_commit(commit, &revs);
1057
- handle_tail(&commits, &revs);
1074
+ handle_commit(commit, &revs, &paths_of_changed_objects);
1075
+ handle_tail(&commits, &revs, &paths_of_changed_objects);
1076
}
1077
}
1078