wt-status.c: handle worktree renames

Before 425a28e0a4 (diff-lib: allow ita entries treated as "not yet exist
in index" - 2016-10-24) there are never "new files" in the index, which
essentially disables rename detection because we only detect renames
when a new file appears in a diff pair.

After that commit, an i-t-a entry can appear as a new file in "git
diff-files". But the diff callback function in wt-status.c does not
handle this case and produces incorrect status output.

PS. The reader may notice that this patch adds a new xstrdup() but not
a free(). Yes we leak memory (the same for head_path). But wt_status
so far has been short lived, this leak should not matter in
practice.

Noticed-by: Alex Vandiver <alexmv@dropbox.com>
Helped-by: Igor Djordjevic <igor.d.djordjevic@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nguyễn Thái Ngọc Duy
2017-12-27 17:18:39 +07:00
committed by Junio C Hamano
parent 5134ccde64
commit 176ea74793
3 changed files with 92 additions and 13 deletions

View File

@ -361,8 +361,6 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
switch (change_type) {
case WT_STATUS_UPDATED:
status = d->index_status;
if (d->rename_source)
one_name = d->rename_source;
break;
case WT_STATUS_CHANGED:
if (d->new_submodule_commits || d->dirty_submodule) {
@ -383,6 +381,14 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
change_type);
}
/*
* Only pick up the rename it's relevant. If the rename is for
* the changed section and we're printing the updated section,
* ignore it.
*/
if (d->rename_status == status)
one_name = d->rename_source;
one = quote_path(one_name, s->prefix, &onebuf);
two = quote_path(two_name, s->prefix, &twobuf);
@ -434,7 +440,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
struct wt_status_change_data *d;
p = q->queue[i];
it = string_list_insert(&s->change, p->one->path);
it = string_list_insert(&s->change, p->two->path);
d = it->util;
if (!d) {
d = xcalloc(1, sizeof(*d));
@ -461,6 +467,14 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
/* mode_worktree is zero for a delete. */
break;
case DIFF_STATUS_COPIED:
case DIFF_STATUS_RENAMED:
if (d->rename_status)
die("BUG: multiple renames on the same target? how?");
d->rename_source = xstrdup(p->one->path);
d->rename_score = p->score * 100 / MAX_SCORE;
d->rename_status = p->status;
/* fallthru */
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
case DIFF_STATUS_UNMERGED:
@ -532,6 +546,8 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
case DIFF_STATUS_COPIED:
case DIFF_STATUS_RENAMED:
if (d->rename_status)
die("BUG: multiple renames on the same target? how?");
d->rename_source = xstrdup(p->one->path);
d->rename_score = p->score * 100 / MAX_SCORE;
d->rename_status = p->status;