[ --stdin | (<pattern>...)]
git refs exists <ref>
git refs optimize [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
+git refs delete [--message=<reason>] [--no-deref] <ref> [<old-value>]
DESCRIPTION
-----------
usage. This subcommand is an alias for linkgit:git-pack-refs[1] and
offers identical functionality.
+delete::
+ Delete the given reference. This subcommand mirrors `git update-ref -d`
+ (see linkgit:git-update-ref[1]). When `<old-value>` is given, the
+ reference is only deleted after verifying that it currently contains
+ `<old-value>`.
+
OPTIONS
-------
include::pack-refs-options.adoc[]
+The following options are specific to commands which write references:
+
+`--message=<reason>`::
+ Use the given <reason> string for the reflog entry associated with the
+ update. An empty message is rejected.
+
+`--no-deref`::
+ Operate on <ref> itself rather than the reference it points to via a
+ symbolic ref.
+
KNOWN LIMITATIONS
-----------------
#define REFS_OPTIMIZE_USAGE \
N_("git refs optimize " PACK_REFS_OPTS)
+#define REFS_DELETE_USAGE \
+ N_("git refs delete [--message=<reason>] [--no-deref] <ref> [<old-value>]")
+
static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
struct repository *repo)
{
return pack_refs_core(argc, argv, prefix, repo, refs_optimize_usage);
}
+static int cmd_refs_delete(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ static char const * const refs_delete_usage[] = {
+ REFS_DELETE_USAGE,
+ NULL
+ };
+ const char *message = NULL;
+ unsigned flags = 0;
+ struct option opts[] = {
+ OPT_STRING(0, "message", &message, N_("reason"),
+ N_("reason of the update")),
+ OPT_BIT(0 ,"no-deref", &flags,
+ N_("update <refname> not the one it points to"),
+ REF_NO_DEREF),
+ OPT_END(),
+ };
+ struct object_id oldoid;
+ const char *refname;
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, opts, refs_delete_usage, 0);
+ if (argc < 1 || argc > 2)
+ usage(_("delete requires reference name and an optional old object ID"));
+
+ if (message && !*message)
+ die(_("refusing to perform update with empty message"));
+
+ repo_config(repo, git_default_config, NULL);
+
+ refname = argv[0];
+ if (argc == 2) {
+ if (repo_get_oid_with_flags(repo, argv[1], &oldoid, GET_OID_SKIP_AMBIGUITY_CHECK))
+ die(_("invalid old object ID: '%s'"), argv[1]);
+ if (is_null_oid(&oldoid))
+ die(_("cannot delete reference with null old object ID"));
+ }
+
+ ret = refs_delete_ref(get_main_ref_store(repo), message, refname,
+ argc == 2 ? &oldoid : NULL, flags);
+
+ if (ret < 0)
+ ret = 1;
+ return ret;
+}
+
int cmd_refs(int argc,
const char **argv,
const char *prefix,
"git refs list " COMMON_USAGE_FOR_EACH_REF,
REFS_EXISTS_USAGE,
REFS_OPTIMIZE_USAGE,
+ REFS_DELETE_USAGE,
NULL,
};
parse_opt_subcommand_fn *fn = NULL;
OPT_SUBCOMMAND("list", &fn, cmd_refs_list),
OPT_SUBCOMMAND("exists", &fn, cmd_refs_exists),
OPT_SUBCOMMAND("optimize", &fn, cmd_refs_optimize),
+ OPT_SUBCOMMAND("delete", &fn, cmd_refs_delete),
OPT_END(),
};
't1461-refs-list.sh',
't1462-refs-exists.sh',
't1463-refs-optimize.sh',
+ 't1464-refs-delete.sh',
't1500-rev-parse.sh',
't1501-work-tree.sh',
't1502-rev-parse-parseopt.sh',
--- /dev/null
+#!/bin/sh
+
+test_description='git refs delete'
+
+. ./test-lib.sh
+
+setup_repo () {
+ git init "$1" &&
+ test_commit -C "$1" A &&
+ test_commit -C "$1" B
+}
+
+test_expect_success 'delete without oldvalue verification' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ A=$(git -C repo rev-parse A) &&
+ git -C repo update-ref refs/heads/foo $A &&
+ git -C repo refs delete refs/heads/foo &&
+ test_must_fail git -C repo show-ref --verify -q refs/heads/foo
+'
+
+test_expect_success 'delete with matching oldvalue' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ git update-ref refs/heads/foo $A &&
+ git refs delete refs/heads/foo $A &&
+ test_must_fail git refs exists refs/heads/foo
+ )
+'
+
+test_expect_success 'delete with stale oldvalue fails' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ B=$(git rev-parse B) &&
+ git update-ref refs/heads/foo $A &&
+ test_must_fail git refs delete refs/heads/foo $B 2>err &&
+ test_grep " but expected " err &&
+ git refs exists refs/heads/foo
+ )
+'
+
+test_expect_success 'delete with null oldvalue fails' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ git update-ref refs/heads/foo $A &&
+ test_must_fail git refs delete refs/heads/foo $ZERO_OID 2>err &&
+ test_grep "null old object ID" err &&
+ git refs exists refs/heads/foo
+ )
+'
+
+test_expect_success 'delete with invalid oldvalue fails' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ git update-ref refs/heads/foo $A &&
+ test_must_fail git refs delete refs/heads/foo invalid-oid 2>err &&
+ test_grep "invalid old object ID" err &&
+ git refs exists refs/heads/foo
+ )
+'
+
+test_expect_success 'delete symref with --no-deref leaves target intact' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ git update-ref refs/heads/foo $A &&
+ git symbolic-ref refs/heads/symref refs/heads/foo &&
+ git refs delete --no-deref refs/heads/symref &&
+ test_must_fail git refs exists refs/heads/symref &&
+ git refs exists refs/heads/foo
+ )
+'
+
+test_expect_success 'delete with message records reason in reflog' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ git update-ref refs/heads/foo $A &&
+ git symbolic-ref HEAD refs/heads/foo &&
+ git refs delete --message=delete-reason refs/heads/foo &&
+ test_must_fail git refs exists refs/heads/foo &&
+ test-tool ref-store main for-each-reflog-ent HEAD >actual &&
+ test_grep "delete-reason$" actual
+ )
+'
+
+test_expect_success 'delete with empty message fails' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ (
+ cd repo &&
+ A=$(git rev-parse A) &&
+ git update-ref refs/heads/foo $A &&
+ test_must_fail git refs delete --message= refs/heads/foo 2>err &&
+ test_grep "empty message" err &&
+ git refs exists refs/heads/foo
+ )
+'
+
+test_expect_success 'delete without arguments fails' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ test_must_fail git -C repo refs delete 2>err &&
+ test_grep "requires reference name" err
+'
+
+test_expect_success 'delete with too many arguments fails' '
+ test_when_finished "rm -rf repo" &&
+ setup_repo repo &&
+ test_must_fail git refs delete one two three 2>err &&
+ test_grep "requires reference name" err
+'
+
+test_done