Merge branch 'ab/branch-sort'
The implementation of "git branch --sort" wrt the detached HEAD display has always been hacky, which has been cleaned up. * ab/branch-sort: branch: show "HEAD detached" first under reverse sort branch: sort detached HEAD based on a flag ref-filter: move ref_sorting flags to a bitfield ref-filter: move "cmp_fn" assignment into "else if" arm ref-filter: add braces to if/else if/else chain branch tests: add to --sort tests branch: change "--local" to "--list" in comment
This commit is contained in:
commit
9e409d7e07
@ -726,7 +726,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
print_current_branch_name();
|
||||
return 0;
|
||||
} else if (list) {
|
||||
/* git branch --local also shows HEAD when it is detached */
|
||||
/* git branch --list also shows HEAD when it is detached */
|
||||
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
|
||||
filter.kind |= FILTER_REFS_DETACHED_HEAD;
|
||||
filter.name_patterns = argv;
|
||||
@ -739,7 +739,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
ref_sorting_icase_all(sorting, icase);
|
||||
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
|
||||
ref_sorting_set_sort_flags_all(
|
||||
sorting, REF_SORTING_DETACHED_HEAD_FIRST, 1);
|
||||
print_ref_list(&filter, sorting, &format);
|
||||
print_columns(&output, colopts, NULL);
|
||||
string_list_clear(&output, 0);
|
||||
|
@ -70,7 +70,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
ref_sorting_icase_all(sorting, icase);
|
||||
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
|
||||
filter.ignore_case = icase;
|
||||
|
||||
filter.name_patterns = argv;
|
||||
|
@ -485,7 +485,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
ref_sorting_icase_all(sorting, icase);
|
||||
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
|
||||
filter.ignore_case = icase;
|
||||
if (cmdmode == 'l') {
|
||||
int ret;
|
||||
|
75
ref-filter.c
75
ref-filter.c
@ -1536,36 +1536,27 @@ char *get_head_description(void)
|
||||
struct wt_status_state state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
wt_status_get_state(the_repository, &state, 1);
|
||||
|
||||
/*
|
||||
* The ( character must be hard-coded and not part of a localizable
|
||||
* string, since the description is used as a sort key and compared
|
||||
* with ref names.
|
||||
*/
|
||||
strbuf_addch(&desc, '(');
|
||||
if (state.rebase_in_progress ||
|
||||
state.rebase_interactive_in_progress) {
|
||||
if (state.branch)
|
||||
strbuf_addf(&desc, _("no branch, rebasing %s"),
|
||||
strbuf_addf(&desc, _("(no branch, rebasing %s)"),
|
||||
state.branch);
|
||||
else
|
||||
strbuf_addf(&desc, _("no branch, rebasing detached HEAD %s"),
|
||||
strbuf_addf(&desc, _("(no branch, rebasing detached HEAD %s)"),
|
||||
state.detached_from);
|
||||
} else if (state.bisect_in_progress)
|
||||
strbuf_addf(&desc, _("no branch, bisect started on %s"),
|
||||
strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
|
||||
state.branch);
|
||||
else if (state.detached_from) {
|
||||
if (state.detached_at)
|
||||
strbuf_addstr(&desc, HEAD_DETACHED_AT);
|
||||
strbuf_addf(&desc, _("(HEAD detached at %s)"),
|
||||
state.detached_from);
|
||||
else
|
||||
strbuf_addstr(&desc, HEAD_DETACHED_FROM);
|
||||
strbuf_addstr(&desc, state.detached_from);
|
||||
}
|
||||
else
|
||||
strbuf_addstr(&desc, _("no branch"));
|
||||
strbuf_addch(&desc, ')');
|
||||
strbuf_addf(&desc, _("(HEAD detached from %s)"),
|
||||
state.detached_from);
|
||||
} else
|
||||
strbuf_addstr(&desc, _("(no branch)"));
|
||||
|
||||
wt_status_state_free_buffers(&state);
|
||||
return strbuf_detach(&desc, NULL);
|
||||
}
|
||||
|
||||
@ -2350,12 +2341,24 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compare_detached_head(struct ref_array_item *a, struct ref_array_item *b)
|
||||
{
|
||||
if (!(a->kind ^ b->kind))
|
||||
BUG("ref_kind_from_refname() should only mark one ref as HEAD");
|
||||
if (a->kind & FILTER_REFS_DETACHED_HEAD)
|
||||
return -1;
|
||||
else if (b->kind & FILTER_REFS_DETACHED_HEAD)
|
||||
return 1;
|
||||
BUG("should have died in the xor check above");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
|
||||
{
|
||||
struct atom_value *va, *vb;
|
||||
int cmp;
|
||||
int cmp_detached_head = 0;
|
||||
cmp_type cmp_type = used_atom[s->atom].type;
|
||||
int (*cmp_fn)(const char *, const char *);
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
if (get_ref_atom_value(a, s->atom, &va, &err))
|
||||
@ -2363,12 +2366,18 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
|
||||
if (get_ref_atom_value(b, s->atom, &vb, &err))
|
||||
die("%s", err.buf);
|
||||
strbuf_release(&err);
|
||||
cmp_fn = s->ignore_case ? strcasecmp : strcmp;
|
||||
if (s->version)
|
||||
if (s->sort_flags & REF_SORTING_DETACHED_HEAD_FIRST &&
|
||||
((a->kind | b->kind) & FILTER_REFS_DETACHED_HEAD)) {
|
||||
cmp = compare_detached_head(a, b);
|
||||
cmp_detached_head = 1;
|
||||
} else if (s->sort_flags & REF_SORTING_VERSION) {
|
||||
cmp = versioncmp(va->s, vb->s);
|
||||
else if (cmp_type == FIELD_STR)
|
||||
} else if (cmp_type == FIELD_STR) {
|
||||
int (*cmp_fn)(const char *, const char *);
|
||||
cmp_fn = s->sort_flags & REF_SORTING_ICASE
|
||||
? strcasecmp : strcmp;
|
||||
cmp = cmp_fn(va->s, vb->s);
|
||||
else {
|
||||
} else {
|
||||
if (va->value < vb->value)
|
||||
cmp = -1;
|
||||
else if (va->value == vb->value)
|
||||
@ -2377,7 +2386,8 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
|
||||
cmp = 1;
|
||||
}
|
||||
|
||||
return (s->reverse) ? -cmp : cmp;
|
||||
return (s->sort_flags & REF_SORTING_REVERSE && !cmp_detached_head)
|
||||
? -cmp : cmp;
|
||||
}
|
||||
|
||||
static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
|
||||
@ -2392,15 +2402,20 @@ static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
|
||||
return cmp;
|
||||
}
|
||||
s = ref_sorting;
|
||||
return s && s->ignore_case ?
|
||||
return s && s->sort_flags & REF_SORTING_ICASE ?
|
||||
strcasecmp(a->refname, b->refname) :
|
||||
strcmp(a->refname, b->refname);
|
||||
}
|
||||
|
||||
void ref_sorting_icase_all(struct ref_sorting *sorting, int flag)
|
||||
void ref_sorting_set_sort_flags_all(struct ref_sorting *sorting,
|
||||
unsigned int mask, int on)
|
||||
{
|
||||
for (; sorting; sorting = sorting->next)
|
||||
sorting->ignore_case = !!flag;
|
||||
for (; sorting; sorting = sorting->next) {
|
||||
if (on)
|
||||
sorting->sort_flags |= mask;
|
||||
else
|
||||
sorting->sort_flags &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
|
||||
@ -2537,12 +2552,12 @@ void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
|
||||
*sorting_tail = s;
|
||||
|
||||
if (*arg == '-') {
|
||||
s->reverse = 1;
|
||||
s->sort_flags |= REF_SORTING_REVERSE;
|
||||
arg++;
|
||||
}
|
||||
if (skip_prefix(arg, "version:", &arg) ||
|
||||
skip_prefix(arg, "v:", &arg))
|
||||
s->version = 1;
|
||||
s->sort_flags |= REF_SORTING_VERSION;
|
||||
s->atom = parse_sorting_atom(arg);
|
||||
}
|
||||
|
||||
|
13
ref-filter.h
13
ref-filter.h
@ -28,9 +28,12 @@ struct atom_value;
|
||||
struct ref_sorting {
|
||||
struct ref_sorting *next;
|
||||
int atom; /* index into used_atom array (internal) */
|
||||
unsigned reverse : 1,
|
||||
ignore_case : 1,
|
||||
version : 1;
|
||||
enum {
|
||||
REF_SORTING_REVERSE = 1<<0,
|
||||
REF_SORTING_ICASE = 1<<1,
|
||||
REF_SORTING_VERSION = 1<<2,
|
||||
REF_SORTING_DETACHED_HEAD_FIRST = 1<<3,
|
||||
} sort_flags;
|
||||
};
|
||||
|
||||
struct ref_array_item {
|
||||
@ -109,8 +112,8 @@ void ref_array_clear(struct ref_array *array);
|
||||
int verify_ref_format(struct ref_format *format);
|
||||
/* Sort the given ref_array as per the ref_sorting provided */
|
||||
void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
|
||||
/* Set the ignore_case flag for all elements of a sorting list */
|
||||
void ref_sorting_icase_all(struct ref_sorting *sorting, int flag);
|
||||
/* Set REF_SORTING_* sort_flags for all elements of a sorting list */
|
||||
void ref_sorting_set_sort_flags_all(struct ref_sorting *sorting, unsigned int mask, int on);
|
||||
/* Based on the given format and quote_style, fill the strbuf */
|
||||
int format_ref_array_item(struct ref_array_item *info,
|
||||
const struct ref_format *format,
|
||||
|
@ -210,7 +210,7 @@ EOF
|
||||
test_i18ncmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git branch `--sort` option' '
|
||||
test_expect_success 'git branch `--sort=[-]objectsize` option' '
|
||||
cat >expect <<-\EOF &&
|
||||
* (HEAD detached from fromtag)
|
||||
branch-two
|
||||
@ -218,6 +218,55 @@ test_expect_success 'git branch `--sort` option' '
|
||||
main
|
||||
EOF
|
||||
git branch --sort=objectsize >actual &&
|
||||
test_i18ncmp expect actual &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
* (HEAD detached from fromtag)
|
||||
branch-one
|
||||
main
|
||||
branch-two
|
||||
EOF
|
||||
git branch --sort=-objectsize >actual &&
|
||||
test_i18ncmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git branch `--sort=[-]type` option' '
|
||||
cat >expect <<-\EOF &&
|
||||
* (HEAD detached from fromtag)
|
||||
branch-one
|
||||
branch-two
|
||||
main
|
||||
EOF
|
||||
git branch --sort=type >actual &&
|
||||
test_i18ncmp expect actual &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
* (HEAD detached from fromtag)
|
||||
branch-one
|
||||
branch-two
|
||||
main
|
||||
EOF
|
||||
git branch --sort=-type >actual &&
|
||||
test_i18ncmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git branch `--sort=[-]version:refname` option' '
|
||||
cat >expect <<-\EOF &&
|
||||
* (HEAD detached from fromtag)
|
||||
branch-one
|
||||
branch-two
|
||||
main
|
||||
EOF
|
||||
git branch --sort=version:refname >actual &&
|
||||
test_i18ncmp expect actual &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
* (HEAD detached from fromtag)
|
||||
main
|
||||
branch-two
|
||||
branch-one
|
||||
EOF
|
||||
git branch --sort=-version:refname >actual &&
|
||||
test_i18ncmp expect actual
|
||||
'
|
||||
|
||||
|
@ -1742,9 +1742,9 @@ static void wt_longstatus_print(struct wt_status *s)
|
||||
} else if (s->state.detached_from) {
|
||||
branch_name = s->state.detached_from;
|
||||
if (s->state.detached_at)
|
||||
on_what = HEAD_DETACHED_AT;
|
||||
on_what = _("HEAD detached at ");
|
||||
else
|
||||
on_what = HEAD_DETACHED_FROM;
|
||||
on_what = _("HEAD detached from ");
|
||||
} else {
|
||||
branch_name = "";
|
||||
on_what = _("Not currently on any branch.");
|
||||
|
@ -77,8 +77,6 @@ enum wt_status_format {
|
||||
STATUS_FORMAT_UNSPECIFIED
|
||||
};
|
||||
|
||||
#define HEAD_DETACHED_AT _("HEAD detached at ")
|
||||
#define HEAD_DETACHED_FROM _("HEAD detached from ")
|
||||
#define SPARSE_CHECKOUT_DISABLED -1
|
||||
|
||||
struct wt_status_state {
|
||||
|
Loading…
Reference in New Issue
Block a user