From 176ea747930908669200520ae14f9dbc61cf0d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Wed, 27 Dec 2017 17:18:39 +0700 Subject: wt-status.c: handle worktree renames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Helped-by: Igor Djordjevic Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- wt-status.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'wt-status.c') diff --git a/wt-status.c b/wt-status.c index 02fda45f05..4858888e9f 100644 --- a/wt-status.c +++ b/wt-status.c @@ -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; -- cgit v1.2.3