Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Documentation/git-refs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ SYNOPSIS
[synopsis]
git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]
git refs verify [--strict] [--verbose]
git refs list [--head] [--branches] [--tag]

DESCRIPTION
-----------
Expand All @@ -25,6 +26,9 @@ migrate::

verify::
Verify reference database consistency.
list::
Displays references available in a local repository along with the associated
commit IDs.

OPTIONS
-------
Expand Down Expand Up @@ -57,6 +61,21 @@ The following options are specific to 'git refs verify':
--verbose::
When verifying the reference database consistency, be chatty.

The following options are specific to 'git refs verify':

--head::

Show the HEAD reference, even if it would normally be filtered out.

--branches::
--tags::

Limit to local branches and local tags, respectively. These options
are not mutually exclusive; when given both, references stored in
"refs/heads" and "refs/tags" are displayed. Note that `--heads`
is a deprecated synonym for `--branches` and may be removed
in the future.

KNOWN LIMITATIONS
-----------------

Expand Down
62 changes: 62 additions & 0 deletions builtin/refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
#include "refs.h"
#include "strbuf.h"
#include "worktree.h"
#include "object-name.h"

#define REFS_MIGRATE_USAGE \
N_("git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]")

#define REFS_VERIFY_USAGE \
N_("git refs verify [--strict] [--verbose]")

#define REFS_LIST_USAGE \
N_("git refs list [--head] [--branches] [--tag]")

static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
Expand Down Expand Up @@ -101,6 +105,62 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
return ret;
}

struct patterns_options {
int show_head;
int branches_only;
int tags_only;
};

static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cbdata UNUSED)
{
const char *hex;

hex = repo_find_unique_abbrev(the_repository, oid, 0);
printf("%s %s\n", hex, refname);

return 0;
}

static int cmd_refs_list(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
struct patterns_options patterns_opts = {0};
const char * const list_usage[] = {
REFS_LIST_USAGE,
NULL,
};
struct option options[] = {
OPT_BOOL(0, "head", &patterns_opts.show_head,
N_("show the HEAD reference, even if it would be filtered out")),
OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with --branches)")),
OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with --tags)")),
OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only,
N_("deprecated synonym for --branches")),
OPT_END(),
};

argc = parse_options(argc, argv, prefix, options, list_usage, 0);
if (argc)
usage(_("'git refs list' takes no arguments"));

if (patterns_opts.show_head)
refs_head_ref(get_main_ref_store(the_repository), show_ref,
&patterns_opts);
if (patterns_opts.tags_only || patterns_opts.branches_only) {
if (patterns_opts.branches_only)
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/heads/", NULL, show_ref, &patterns_opts);

if (patterns_opts.tags_only)
refs_for_each_fullref_in(get_main_ref_store(the_repository),
"refs/tags/", NULL, show_ref, &patterns_opts);
}
else refs_for_each_ref(get_main_ref_store(the_repository), show_ref, &patterns_opts);

return 0;
}

int cmd_refs(int argc,
const char **argv,
const char *prefix,
Expand All @@ -109,12 +169,14 @@ int cmd_refs(int argc,
const char * const refs_usage[] = {
REFS_MIGRATE_USAGE,
REFS_VERIFY_USAGE,
REFS_LIST_USAGE,
NULL,
};
parse_opt_subcommand_fn *fn = NULL;
struct option opts[] = {
OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
OPT_SUBCOMMAND("list", &fn, cmd_refs_list),
OPT_END(),
};

Expand Down
1 change: 1 addition & 0 deletions t/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ integration_tests = [
't1450-fsck.sh',
't1451-fsck-buffer.sh',
't1460-refs-migrate.sh',
't1461-refs-list.sh',
't1500-rev-parse.sh',
't1501-work-tree.sh',
't1502-rev-parse-parseopt.sh',
Expand Down
52 changes: 52 additions & 0 deletions t/t1461-refs-list.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/sh

test_description='refs list'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME

. ./test-lib.sh

test_expect_success setup '
test_commit --annotate A &&
git checkout -b side &&
test_commit --annotate B &&
git checkout main &&
test_commit C &&
git branch B A^0
'
test_expect_success 'refs list --branches, --tags, --head' '
for branch in B main side
do
echo $(git rev-parse refs/heads/$branch) refs/heads/$branch || return 1
done >expect.branches &&
git refs list --branches >actual &&
test_cmp expect.branches actual &&

for tag in A B C
do
echo $(git rev-parse refs/tags/$tag) refs/tags/$tag || return 1
done >expect.tags &&
git refs list --tags >actual &&
test_cmp expect.tags actual &&

cat expect.branches expect.tags >expect &&
git refs list --branches --tags >actual &&
test_cmp expect actual &&

{
echo $(git rev-parse HEAD) HEAD &&
cat expect.branches expect.tags
} >expect &&
git refs list --branches --tags --head >actual &&
test_cmp expect actual
'

test_expect_success 'refs list --heads is deprecated and hidden' '
test_expect_code 129 git refs list -h >short-help &&
test_grep ! -e --heads short-help &&
git refs list --heads >actual 2>warning &&
test_grep ! deprecated warning &&
test_cmp expect.branches actual
'

test_done
Loading