mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-19 16:55:31 -05:00
Merge branch 'ps/refs-writing-subcommands' into jch
The "git refs" toolbox has been extended with new "create", "delete", "update", and "rename" subcommands to create, delete, update, and rename references, respectively. * ps/refs-writing-subcommands: builtin/refs: add "rename" subcommand builtin/refs: add "create" subcommand builtin/refs: add "update" subcommand builtin/refs: add "delete" subcommand builtin/refs: drop `the_repository`
This commit is contained in:
@@ -20,6 +20,10 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl]
|
||||
[ --stdin | (<pattern>...)]
|
||||
git refs exists <ref>
|
||||
git refs optimize [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
|
||||
git refs create [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value>
|
||||
git refs delete [--message=<reason>] [--no-deref] <ref> [<old-value>]
|
||||
git refs update [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value> [<old-value>]
|
||||
git refs rename [--message=<reason>] <old-ref> <new-ref>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -51,6 +55,28 @@ optimize::
|
||||
usage. This subcommand is an alias for linkgit:git-pack-refs[1] and
|
||||
offers identical functionality.
|
||||
|
||||
create::
|
||||
Create the given reference, which must not already exist, pointing at
|
||||
`<new-value>`.
|
||||
|
||||
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>`.
|
||||
|
||||
update::
|
||||
Update the given reference to point at `<new-value>`. If `<old-value>`
|
||||
is given, the reference is only updated after verifying that it
|
||||
currently contains `<old-value>`. As a special case, an all-zeroes
|
||||
`<new-value>` deletes the branch, whereas an all-zeroes `<old-value>`
|
||||
ensures that the branch does not yet exist.
|
||||
|
||||
rename::
|
||||
Rename the reference `<oldref>` to `<newref>`. The old reference must
|
||||
exist and the new reference must not yet exist, and both must have a
|
||||
well-formed name (see linkgit:git-check-ref-format[1]).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
@@ -90,6 +116,20 @@ The following options are specific to 'git refs optimize':
|
||||
|
||||
include::pack-refs-options.adoc[]
|
||||
|
||||
The following options are specific to commands which write references:
|
||||
|
||||
`--create-reflog`::
|
||||
Create a reflog for the reference even if one would not ordinarily be
|
||||
created.
|
||||
|
||||
`--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
|
||||
-----------------
|
||||
|
||||
|
||||
222
builtin/refs.c
222
builtin/refs.c
@@ -1,4 +1,3 @@
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
#include "builtin.h"
|
||||
#include "config.h"
|
||||
#include "fsck.h"
|
||||
@@ -22,8 +21,20 @@
|
||||
#define REFS_OPTIMIZE_USAGE \
|
||||
N_("git refs optimize " PACK_REFS_OPTS)
|
||||
|
||||
#define REFS_CREATE_USAGE \
|
||||
N_("git refs create [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value>")
|
||||
|
||||
#define REFS_DELETE_USAGE \
|
||||
N_("git refs delete [--message=<reason>] [--no-deref] <ref> [<old-value>]")
|
||||
|
||||
#define REFS_UPDATE_USAGE \
|
||||
N_("git refs update [--message=<reason>] [--no-deref] [--create-reflog] <ref> <new-value> [<old-value>]")
|
||||
|
||||
#define REFS_RENAME_USAGE \
|
||||
N_("git refs rename [--message=<reason>] <old-ref> <new-ref>")
|
||||
|
||||
static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo UNUSED)
|
||||
struct repository *repo)
|
||||
{
|
||||
const char * const migrate_usage[] = {
|
||||
REFS_MIGRATE_USAGE,
|
||||
@@ -59,13 +70,13 @@ static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (the_repository->ref_storage_format == format) {
|
||||
if (repo->ref_storage_format == format) {
|
||||
err = error(_("repository already uses '%s' format"),
|
||||
ref_storage_format_to_name(format));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (repo_migrate_ref_storage_format(the_repository, format, flags, &errbuf) < 0) {
|
||||
if (repo_migrate_ref_storage_format(repo, format, flags, &errbuf) < 0) {
|
||||
err = error("%s", errbuf.buf);
|
||||
goto out;
|
||||
}
|
||||
@@ -99,8 +110,8 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
|
||||
if (argc)
|
||||
usage(_("'git refs verify' takes no arguments"));
|
||||
|
||||
repo_config(the_repository, git_fsck_config, &fsck_refs_options);
|
||||
prepare_repo_settings(the_repository);
|
||||
repo_config(repo, git_fsck_config, &fsck_refs_options);
|
||||
prepare_repo_settings(repo);
|
||||
|
||||
worktrees = get_worktrees_without_reading_head();
|
||||
for (size_t i = 0; worktrees[i]; i++)
|
||||
@@ -124,7 +135,7 @@ static int cmd_refs_list(int argc, const char **argv, const char *prefix,
|
||||
}
|
||||
|
||||
static int cmd_refs_exists(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo UNUSED)
|
||||
struct repository *repo)
|
||||
{
|
||||
struct strbuf unused_referent = STRBUF_INIT;
|
||||
struct object_id unused_oid;
|
||||
@@ -145,7 +156,7 @@ static int cmd_refs_exists(int argc, const char **argv, const char *prefix,
|
||||
die(_("'git refs exists' requires a reference"));
|
||||
|
||||
ref = *argv++;
|
||||
if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
|
||||
if (refs_read_raw_ref(get_main_ref_store(repo), ref,
|
||||
&unused_oid, &unused_referent, &unused_type,
|
||||
&failure_errno)) {
|
||||
if (failure_errno == ENOENT || failure_errno == EISDIR) {
|
||||
@@ -176,6 +187,193 @@ static int cmd_refs_optimize(int argc, const char **argv, const char *prefix,
|
||||
return pack_refs_core(argc, argv, prefix, repo, refs_optimize_usage);
|
||||
}
|
||||
|
||||
static int cmd_refs_create(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
{
|
||||
static char const * const refs_create_usage[] = {
|
||||
REFS_CREATE_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_BIT(0, "create-reflog", &flags, N_("create a reflog"),
|
||||
REF_FORCE_CREATE_REFLOG),
|
||||
OPT_END(),
|
||||
};
|
||||
struct object_id newoid;
|
||||
const char *refname;
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, prefix, opts, refs_create_usage, 0);
|
||||
if (argc != 2)
|
||||
usage(_("create requires reference name and an object ID"));
|
||||
|
||||
if (message && !*message)
|
||||
die(_("refusing to perform update with empty message"));
|
||||
|
||||
repo_config(repo, git_default_config, NULL);
|
||||
|
||||
refname = argv[0];
|
||||
if (repo_get_oid_with_flags(repo, argv[1], &newoid, GET_OID_SKIP_AMBIGUITY_CHECK))
|
||||
die(_("invalid object ID: '%s'"), argv[1]);
|
||||
if (is_null_oid(&newoid))
|
||||
die(_("cannot create reference with null old object ID"));
|
||||
|
||||
ret = refs_update_ref(get_main_ref_store(repo), message, refname,
|
||||
&newoid, null_oid(repo->hash_algo), flags,
|
||||
UPDATE_REFS_MSG_ON_ERR);
|
||||
|
||||
if (ret < 0)
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int cmd_refs_update(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
{
|
||||
static char const * const refs_update_usage[] = {
|
||||
REFS_UPDATE_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_BIT(0, "create-reflog", &flags, N_("create a reflog"),
|
||||
REF_FORCE_CREATE_REFLOG),
|
||||
OPT_END(),
|
||||
};
|
||||
struct object_id newoid, oldoid;
|
||||
const char *refname;
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, prefix, opts, refs_update_usage, 0);
|
||||
if (argc < 2 || argc > 3)
|
||||
usage(_("update requires reference name, new value and an optional old value"));
|
||||
|
||||
if (message && !*message)
|
||||
die(_("refusing to perform update with empty message"));
|
||||
|
||||
repo_config(repo, git_default_config, NULL);
|
||||
|
||||
refname = argv[0];
|
||||
if (repo_get_oid_with_flags(repo, argv[1], &newoid,
|
||||
GET_OID_SKIP_AMBIGUITY_CHECK))
|
||||
die(_("invalid new object ID: '%s'"), argv[1]);
|
||||
if (argc == 3 &&
|
||||
repo_get_oid_with_flags(repo, argv[2], &oldoid,
|
||||
GET_OID_SKIP_AMBIGUITY_CHECK))
|
||||
die(_("invalid old object ID: '%s'"), argv[2]);
|
||||
|
||||
ret = refs_update_ref(get_main_ref_store(repo), message, refname,
|
||||
&newoid, argc == 3 ? &oldoid : NULL, flags,
|
||||
UPDATE_REFS_MSG_ON_ERR);
|
||||
|
||||
if (ret < 0)
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmd_refs_rename(int argc, const char **argv, const char *prefix,
|
||||
struct repository *repo)
|
||||
{
|
||||
static char const * const refs_rename_usage[] = {
|
||||
REFS_RENAME_USAGE,
|
||||
NULL
|
||||
};
|
||||
const char *message = NULL;
|
||||
struct option opts[] = {
|
||||
OPT_STRING(0, "message", &message, N_("reason"),
|
||||
N_("reason of the update")),
|
||||
OPT_END(),
|
||||
};
|
||||
const char *oldref, *newref;
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, prefix, opts, refs_rename_usage, 0);
|
||||
if (argc != 2)
|
||||
usage(_("rename requires old and new reference name"));
|
||||
if (message && !*message)
|
||||
die(_("refusing to perform update with empty message"));
|
||||
|
||||
repo_config(repo, git_default_config, NULL);
|
||||
|
||||
oldref = argv[0];
|
||||
newref = argv[1];
|
||||
|
||||
if (check_refname_format(oldref, 0))
|
||||
die(_("invalid ref format: '%s'"), oldref);
|
||||
if (check_refname_format(newref, 0))
|
||||
die(_("invalid ref format: '%s'"), newref);
|
||||
|
||||
if (!refs_ref_exists(get_main_ref_store(repo), oldref))
|
||||
die(_("reference does not exist: '%s'"), oldref);
|
||||
if (refs_ref_exists(get_main_ref_store(repo), newref))
|
||||
die(_("reference already exists: '%s'"), newref);
|
||||
|
||||
ret = refs_rename_ref(get_main_ref_store(repo), oldref, newref, message);
|
||||
|
||||
if (ret < 0)
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_refs(int argc,
|
||||
const char **argv,
|
||||
const char *prefix,
|
||||
@@ -187,6 +385,10 @@ int cmd_refs(int argc,
|
||||
"git refs list " COMMON_USAGE_FOR_EACH_REF,
|
||||
REFS_EXISTS_USAGE,
|
||||
REFS_OPTIMIZE_USAGE,
|
||||
REFS_CREATE_USAGE,
|
||||
REFS_DELETE_USAGE,
|
||||
REFS_UPDATE_USAGE,
|
||||
REFS_RENAME_USAGE,
|
||||
NULL,
|
||||
};
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
@@ -196,6 +398,10 @@ int cmd_refs(int argc,
|
||||
OPT_SUBCOMMAND("list", &fn, cmd_refs_list),
|
||||
OPT_SUBCOMMAND("exists", &fn, cmd_refs_exists),
|
||||
OPT_SUBCOMMAND("optimize", &fn, cmd_refs_optimize),
|
||||
OPT_SUBCOMMAND("create", &fn, cmd_refs_create),
|
||||
OPT_SUBCOMMAND("delete", &fn, cmd_refs_delete),
|
||||
OPT_SUBCOMMAND("update", &fn, cmd_refs_update),
|
||||
OPT_SUBCOMMAND("rename", &fn, cmd_refs_rename),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
|
||||
@@ -223,6 +223,10 @@ integration_tests = [
|
||||
't1461-refs-list.sh',
|
||||
't1462-refs-exists.sh',
|
||||
't1463-refs-optimize.sh',
|
||||
't1464-refs-delete.sh',
|
||||
't1465-refs-update.sh',
|
||||
't1466-refs-create.sh',
|
||||
't1467-refs-rename.sh',
|
||||
't1500-rev-parse.sh',
|
||||
't1501-work-tree.sh',
|
||||
't1502-rev-parse-parseopt.sh',
|
||||
|
||||
130
t/t1464-refs-delete.sh
Executable file
130
t/t1464-refs-delete.sh
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/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
|
||||
268
t/t1465-refs-update.sh
Executable file
268
t/t1465-refs-update.sh
Executable file
@@ -0,0 +1,268 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git refs update'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
setup_repo () {
|
||||
git init "$1" &&
|
||||
test_commit -C "$1" A &&
|
||||
test_commit -C "$1" B
|
||||
}
|
||||
|
||||
test_ref_matches () {
|
||||
git rev-parse "$1" >expect &&
|
||||
echo "$2" >actual &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
|
||||
test_expect_success 'update creates a new reference' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_ref_matches refs/heads/foo "$A"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update an existing reference without oldvalue' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git refs update refs/heads/foo $B &&
|
||||
test_ref_matches refs/heads/foo $B
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update with matching oldvalue' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git refs update refs/heads/foo $B $A &&
|
||||
test_ref_matches refs/heads/foo $B
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update 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 refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs update refs/heads/foo $B $B 2>err &&
|
||||
test_grep " but expected " err &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update can create a new branch with oldvalue' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A $ZERO_OID 2>err &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update can create a new branch without oldvalue' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A 2>err &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update refuses to create preexisting branch' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs update refs/heads/foo $B $ZERO_OID 2>err &&
|
||||
test_grep "reference already exists" err &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update can delete a branch with oldvalue' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A 2>err &&
|
||||
git refs update refs/heads/foo $ZERO_OID $A 2>err &&
|
||||
test_must_fail git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update can delete a branch without oldvalue' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A 2>err &&
|
||||
git refs update refs/heads/foo $ZERO_OID 2>err &&
|
||||
test_must_fail git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update refuses to delete a branch with mismatching value' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A 2>err &&
|
||||
test_must_fail git refs update refs/heads/foo $ZERO_OID $B 2>err &&
|
||||
test_grep " but expected " err &&
|
||||
git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update refuses to create preexisting branch' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs update refs/heads/foo $B $ZERO_OID 2>err &&
|
||||
test_grep "reference already exists" err &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'update with invalid new value fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_must_fail git refs update refs/heads/foo invalid-oid 2>err &&
|
||||
test_grep "invalid new object ID" err &&
|
||||
test_must_fail git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update with invalid old value fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs update refs/heads/foo $B invalid-oid 2>err &&
|
||||
test_grep "invalid old object ID" err &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update --no-deref rewrites the symref itself' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git symbolic-ref refs/heads/symref refs/heads/foo &&
|
||||
git refs update --no-deref refs/heads/symref $B &&
|
||||
test_must_fail git symbolic-ref refs/heads/symref &&
|
||||
test_ref_matches refs/heads/symref $B &&
|
||||
test_ref_matches refs/heads/foo $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update does not create a reflog by default' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/foo $A &&
|
||||
test_must_fail git reflog exists refs/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update creates a reflog with --create-reflog' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update --create-reflog refs/foo $A &&
|
||||
git reflog exists refs/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update with message records reason in reflog' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git refs update --message=update-reason refs/heads/foo $B &&
|
||||
git reflog show refs/heads/foo >actual &&
|
||||
test_grep "update-reason$" actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update with empty message fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs update --message= refs/heads/foo $B 2>err &&
|
||||
test_grep "empty message" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'update with too few arguments fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
test_must_fail git -C repo refs update refs/heads/foo 2>err &&
|
||||
test_grep "requires reference name, new value" err
|
||||
'
|
||||
|
||||
test_expect_success 'update with too many arguments fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
test_must_fail git refs update refs/heads/foo $A $B extra 2>err &&
|
||||
test_grep "requires reference name, new value" err
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
151
t/t1466-refs-create.sh
Executable file
151
t/t1466-refs-create.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git refs create'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
setup_repo () {
|
||||
git init "$1" &&
|
||||
test_commit -C "$1" A &&
|
||||
test_commit -C "$1" B
|
||||
}
|
||||
|
||||
test_ref_matches () {
|
||||
git rev-parse "$1" >expect &&
|
||||
echo "$2" >actual &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
|
||||
test_expect_success 'create a new reference' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs create refs/heads/foo $A &&
|
||||
test_ref_matches refs/heads/foo "$A"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create fails when the reference already exists' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs create refs/heads/foo $A &&
|
||||
test_must_fail git refs create refs/heads/foo $B 2>err &&
|
||||
test_grep "reference already exists" err &&
|
||||
test_ref_matches refs/heads/foo "$A"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create with null new value fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_must_fail git refs create refs/heads/foo $ZERO_OID 2>err &&
|
||||
test_grep "null old object ID" err &&
|
||||
test_must_fail git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create with invalid new value fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_must_fail git refs create refs/heads/foo invalid-oid 2>err &&
|
||||
test_grep "invalid object ID" err &&
|
||||
test_must_fail git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create does not create a reflog by default' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs create refs/foo $A &&
|
||||
test_must_fail git reflog exists refs/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create creates a reflog with --create-reflog' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs create --create-reflog refs/foo $A &&
|
||||
git reflog exists refs/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create with message records reason in reflog' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs create --message="create reason" refs/heads/foo $A &&
|
||||
git reflog show refs/heads/foo >actual &&
|
||||
test_grep "create reason$" actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create with symref target creates target reference' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git symbolic-ref refs/heads/symref refs/heads/target &&
|
||||
git refs create refs/heads/symref $A &&
|
||||
git reflog exists refs/heads/target
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create with symref target and --no-deref refuses to create reference' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git symbolic-ref refs/heads/symref refs/heads/target &&
|
||||
test_must_fail git refs create --no-deref refs/heads/symref $A 2>err &&
|
||||
test_grep "dangling symref already exists" err &&
|
||||
test_must_fail git reflog exists refs/heads/target
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create with empty message fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
test_must_fail git refs create --message= refs/heads/foo $A 2>err &&
|
||||
test_grep "empty message" err &&
|
||||
test_must_fail git refs exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'create without arguments fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
test_must_fail git -C repo refs create 2>err &&
|
||||
test_grep "requires reference name" err
|
||||
'
|
||||
|
||||
test_expect_success 'create with too many arguments fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
test_must_fail git -C repo refs create refs/heads/foo a b 2>err &&
|
||||
test_grep "requires reference name" err
|
||||
'
|
||||
|
||||
test_done
|
||||
131
t/t1467-refs-rename.sh
Executable file
131
t/t1467-refs-rename.sh
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git refs rename'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
setup_repo () {
|
||||
git init "$1" &&
|
||||
test_commit -C "$1" A &&
|
||||
test_commit -C "$1" B
|
||||
}
|
||||
|
||||
test_ref_matches () {
|
||||
git rev-parse "$1" >expect &&
|
||||
echo "$2" >actual &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
|
||||
test_expect_success 'rename an existing reference' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git refs rename refs/heads/foo refs/heads/bar &&
|
||||
test_must_fail git refs exists refs/heads/foo &&
|
||||
test_ref_matches refs/heads/bar $A
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename moves the reflog along with the reference' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update --message="rename me" refs/heads/foo $A &&
|
||||
git refs rename refs/heads/foo refs/heads/bar &&
|
||||
git reflog show refs/heads/bar >reflog &&
|
||||
test_grep "rename me" reflog &&
|
||||
test_must_fail git reflog exists refs/heads/foo
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename with message records reason in reflog' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git refs rename --message="rename reason" refs/heads/foo refs/heads/bar &&
|
||||
git reflog show refs/heads/bar >actual &&
|
||||
test_grep "rename reason" actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename a nonexistent reference fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_must_fail git refs rename refs/heads/foo refs/heads/bar 2>err &&
|
||||
test_grep "reference does not exist" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename to an existing reference fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
B=$(git rev-parse B) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
git refs update refs/heads/bar $B &&
|
||||
test_must_fail git refs rename refs/heads/foo refs/heads/bar 2>err &&
|
||||
test_grep "reference already exists" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename with empty message fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs rename --message= refs/heads/foo refs/heads/bar 2>err &&
|
||||
test_grep "empty message" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename with invalid old reference name fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_must_fail git refs rename "refs/heads/foo..bar" refs/heads/bar 2>err &&
|
||||
test_grep "invalid ref format" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename with invalid new reference name fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
(
|
||||
cd repo &&
|
||||
A=$(git rev-parse A) &&
|
||||
git refs update refs/heads/foo $A &&
|
||||
test_must_fail git refs rename refs/heads/foo "refs/heads/bar..baz" 2>err &&
|
||||
test_grep "invalid ref format" err
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'rename with too few arguments fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
test_must_fail git -C repo refs rename refs/heads/foo 2>err &&
|
||||
test_grep "requires old and new reference name" err
|
||||
'
|
||||
|
||||
test_expect_success 'rename with too many arguments fails' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
setup_repo repo &&
|
||||
test_must_fail git -C repo refs rename refs/heads/foo refs/heads/bar refs/heads/baz 2>err &&
|
||||
test_grep "requires old and new reference name" err
|
||||
'
|
||||
|
||||
test_done
|
||||
Reference in New Issue
Block a user