How do I produce every possible git-status?

巧了我就是萌 提交于 2019-12-04 10:50:44

For what it's worth, based on the source, there's no way to get "copied in index" to occur today:

wt-status.c:            status = d->index_status;
wt-status.c:            if (!d->index_status)
wt-status.c:                    d->index_status = p->status;
wt-status.c:                    d->index_status = DIFF_STATUS_UNMERGED;
wt-status.c:                    d->index_status = DIFF_STATUS_ADDED;
wt-status.c:            if (!d->index_status ||
wt-status.c:                d->index_status == DIFF_STATUS_UNMERGED)
wt-status.c:    if (d->index_status)
wt-status.c:            color_fprintf(s->fp, color(WT_STATUS_UPDATED, s), "%c", 
wt-status.h:    int index_status;

(where index_status is the letter printed for the first column). So the direct assignments can set it to U and A, and the copy-assignment from p->status can set it to whatever p->status is set to. That is ultimately controlled via this bit of code:

static void wt_status_collect_changes_index(struct wt_status *s)
{
        struct rev_info rev;
        struct setup_revision_opt opt;

        init_revisions(&rev, NULL);
        memset(&opt, 0, sizeof(opt));
        opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;
        setup_revisions(0, NULL, &rev, &opt);

        if (s->ignore_submodule_arg) {
                DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
                handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
        }

        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = wt_status_collect_updated_cb;
        rev.diffopt.format_callback_data = s;
        rev.diffopt.detect_rename = 1;
        rev.diffopt.rename_limit = 200;
        rev.diffopt.break_opt = 0;
        copy_pathspec(&rev.prune_data, &s->pathspec);
        run_diff_index(&rev, 1);
}

The diff options here are those shown above: detect_rename is set to DIFF_DETECT_RENAME (1 -- this should use the #define, really), with a limit of 200. If detect_rename had been set to DIFF_DETECT_COPY (2), you could get state C.

I tested this by modifying wt-status.c (see below), then fussing about with another file:

$ git status --short
 M wt-status.c
$ git mv zlib.c zzy.c; cp zzy.c zzz.c; git add zzz.c; git status --short
 M wt-status.c
R  zlib.c -> zzy.c
A  zzz.c
$ ./git-status --short
 M wt-status.c
C  zlib.c -> zzy.c
R  zlib.c -> zzz.c

note that the equivalent of --find-copies-harder is still not set, so you have to have at least one rename already to get the copied status:

$ git mv zzy.c zlib.c; ./git-status --short
 M wt-status.c
A  zzz.c

To get that I had to also add another DIFF_OPT_SET:

$ git diff
diff --git a/wt-status.c b/wt-status.c
index 4e55810..06310e3 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -494,7 +494,8 @@ static void wt_status_collect_changes_index(struct wt_status
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = wt_status_collect_updated_cb;
        rev.diffopt.format_callback_data = s;
-       rev.diffopt.detect_rename = 1;
+       rev.diffopt.detect_rename = DIFF_DETECT_COPY;
+       DIFF_OPT_SET(&rev.diffopt, FIND_COPIES_HARDER);
        rev.diffopt.rename_limit = 200;
        rev.diffopt.break_opt = 0;
        copy_pathspec(&rev.prune_data, &s->pathspec);
$ ./git-status --short
 M wt-status.c
C  zlib.c -> zzz.c

I'll stop at this point though, that's enough playing for now :-)

Chris

By posting this question to the git mailing list, I got an answer for four of the seven codes, with the investigation done by @torek there is now a complete answer to this question, though I don't quite know how to reflect that in stackoverflow.

You can read the git mailing list discussion for details, but the short answer is, with the information provided by @torek, none of the status combinations which I cannot reproduce are reachable by normal users of the git command line tools.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!