update-ref and tag: add --create-reflog arg
Allow the creation of a ref (e.g. stash) with a reflog already in place. For most refs (e.g. those under refs/heads), this happens automatically, but for others, we need this option. Currently, git does this by pre-creating the reflog, but alternate ref backends might store reflogs somewhere other than .git/logs. Code that now directly manipulates .git/logs should instead use git plumbing commands. I also added --create-reflog to git tag, just for completeness. In a moment, we will use this argument to make git stash work with alternate ref backends. Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
parent
0f2a71d992
commit
144c76fa39
|
@ -13,7 +13,7 @@ SYNOPSIS
|
||||||
<tagname> [<commit> | <object>]
|
<tagname> [<commit> | <object>]
|
||||||
'git tag' -d <tagname>...
|
'git tag' -d <tagname>...
|
||||||
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
|
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
|
||||||
[--column[=<options>] | --no-column] [<pattern>...]
|
[--column[=<options>] | --no-column] [--create-reflog] [<pattern>...]
|
||||||
[<pattern>...]
|
[<pattern>...]
|
||||||
'git tag' -v <tagname>...
|
'git tag' -v <tagname>...
|
||||||
|
|
||||||
|
@ -143,6 +143,9 @@ This option is only applicable when listing tags without annotation lines.
|
||||||
all, 'whitespace' removes just leading/trailing whitespace lines and
|
all, 'whitespace' removes just leading/trailing whitespace lines and
|
||||||
'strip' removes both whitespace and commentary.
|
'strip' removes both whitespace and commentary.
|
||||||
|
|
||||||
|
--create-reflog::
|
||||||
|
Create a reflog for the tag.
|
||||||
|
|
||||||
<tagname>::
|
<tagname>::
|
||||||
The name of the tag to create, delete, or describe.
|
The name of the tag to create, delete, or describe.
|
||||||
The new tag name must pass all checks defined by
|
The new tag name must pass all checks defined by
|
||||||
|
|
|
@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
|
'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -67,6 +67,9 @@ performs all modifications together. Specify commands of the form:
|
||||||
verify SP <ref> [SP <oldvalue>] LF
|
verify SP <ref> [SP <oldvalue>] LF
|
||||||
option SP <opt> LF
|
option SP <opt> LF
|
||||||
|
|
||||||
|
With `--create-reflog`, update-ref will create a reflog for each ref
|
||||||
|
even if one would not ordinarily be created.
|
||||||
|
|
||||||
Quote fields containing whitespace as if they were strings in C source
|
Quote fields containing whitespace as if they were strings in C source
|
||||||
code; i.e., surrounded by double-quotes and with backslash escapes.
|
code; i.e., surrounded by double-quotes and with backslash escapes.
|
||||||
Use 40 "0" characters or the empty string to specify a zero value. To
|
Use 40 "0" characters or the empty string to specify a zero value. To
|
||||||
|
|
|
@ -579,6 +579,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||||
struct create_tag_options opt;
|
struct create_tag_options opt;
|
||||||
char *cleanup_arg = NULL;
|
char *cleanup_arg = NULL;
|
||||||
int annotate = 0, force = 0, lines = -1;
|
int annotate = 0, force = 0, lines = -1;
|
||||||
|
int create_reflog = 0;
|
||||||
int cmdmode = 0;
|
int cmdmode = 0;
|
||||||
const char *msgfile = NULL, *keyid = NULL;
|
const char *msgfile = NULL, *keyid = NULL;
|
||||||
struct msg_arg msg = { 0, STRBUF_INIT };
|
struct msg_arg msg = { 0, STRBUF_INIT };
|
||||||
|
@ -605,6 +606,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||||
OPT_STRING('u', "local-user", &keyid, N_("key-id"),
|
OPT_STRING('u', "local-user", &keyid, N_("key-id"),
|
||||||
N_("use another key to sign the tag")),
|
N_("use another key to sign the tag")),
|
||||||
OPT__FORCE(&force, N_("replace the tag if exists")),
|
OPT__FORCE(&force, N_("replace the tag if exists")),
|
||||||
|
OPT_BOOL(0, "create-reflog", &create_reflog, N_("create_reflog")),
|
||||||
|
|
||||||
OPT_GROUP(N_("Tag listing options")),
|
OPT_GROUP(N_("Tag listing options")),
|
||||||
OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
|
OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
|
||||||
|
@ -733,7 +735,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, ref.buf, object, prev,
|
ref_transaction_update(transaction, ref.buf, object, prev,
|
||||||
0, NULL, &err) ||
|
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
|
||||||
|
NULL, &err) ||
|
||||||
ref_transaction_commit(transaction, &err))
|
ref_transaction_commit(transaction, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
|
|
|
@ -14,6 +14,7 @@ static const char * const git_update_ref_usage[] = {
|
||||||
|
|
||||||
static char line_termination = '\n';
|
static char line_termination = '\n';
|
||||||
static int update_flags;
|
static int update_flags;
|
||||||
|
static unsigned create_reflog_flag;
|
||||||
static const char *msg;
|
static const char *msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -200,7 +201,8 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
|
||||||
|
|
||||||
if (ref_transaction_update(transaction, refname,
|
if (ref_transaction_update(transaction, refname,
|
||||||
new_sha1, have_old ? old_sha1 : NULL,
|
new_sha1, have_old ? old_sha1 : NULL,
|
||||||
update_flags, msg, &err))
|
update_flags | create_reflog_flag,
|
||||||
|
msg, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
|
@ -231,7 +233,8 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
|
||||||
die("create %s: extra input: %s", refname, next);
|
die("create %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
if (ref_transaction_create(transaction, refname, new_sha1,
|
if (ref_transaction_create(transaction, refname, new_sha1,
|
||||||
update_flags, msg, &err))
|
update_flags | create_reflog_flag,
|
||||||
|
msg, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
|
@ -354,6 +357,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
unsigned char sha1[20], oldsha1[20];
|
unsigned char sha1[20], oldsha1[20];
|
||||||
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
|
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
int create_reflog = 0;
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
|
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
|
||||||
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
|
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
|
||||||
|
@ -361,6 +365,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
N_("update <refname> not the one it points to")),
|
N_("update <refname> not the one it points to")),
|
||||||
OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
|
OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
|
||||||
OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
|
OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
|
||||||
|
OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create_reflog")),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -370,6 +375,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
if (msg && !*msg)
|
if (msg && !*msg)
|
||||||
die("Refusing to perform update with empty message.");
|
die("Refusing to perform update with empty message.");
|
||||||
|
|
||||||
|
create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
|
||||||
|
|
||||||
if (read_stdin) {
|
if (read_stdin) {
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
struct ref_transaction *transaction;
|
struct ref_transaction *transaction;
|
||||||
|
@ -418,5 +425,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
|
return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
|
||||||
else
|
else
|
||||||
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
|
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
|
||||||
flags, UPDATE_REFS_DIE_ON_ERR);
|
flags | create_reflog_flag,
|
||||||
|
UPDATE_REFS_DIE_ON_ERR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ test_expect_success setup '
|
||||||
m=refs/heads/master
|
m=refs/heads/master
|
||||||
n_dir=refs/heads/gu
|
n_dir=refs/heads/gu
|
||||||
n=$n_dir/fixes
|
n=$n_dir/fixes
|
||||||
|
outside=foo
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
"create $m" \
|
"create $m" \
|
||||||
|
@ -74,6 +75,24 @@ test_expect_success "delete $m (by HEAD)" '
|
||||||
'
|
'
|
||||||
rm -f .git/$m
|
rm -f .git/$m
|
||||||
|
|
||||||
|
test_expect_success 'update-ref does not create reflogs by default' '
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
|
git update-ref $outside $A &&
|
||||||
|
git rev-parse $A >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_must_fail git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref creates reflogs with --create-reflog' '
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
|
git update-ref --create-reflog $outside $A &&
|
||||||
|
git rev-parse $A >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
"create $m (by HEAD)" \
|
"create $m (by HEAD)" \
|
||||||
"git update-ref HEAD $A &&
|
"git update-ref HEAD $A &&
|
||||||
|
@ -472,6 +491,25 @@ test_expect_success 'stdin create ref works' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'stdin does not create reflogs by default' '
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
|
echo "create $outside $m" >stdin &&
|
||||||
|
git update-ref --stdin <stdin &&
|
||||||
|
git rev-parse $m >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_must_fail git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'stdin creates reflogs with --create-reflog' '
|
||||||
|
echo "create $outside $m" >stdin &&
|
||||||
|
git update-ref --create-reflog --stdin <stdin &&
|
||||||
|
git rev-parse $m >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin succeeds with quoted argument' '
|
test_expect_success 'stdin succeeds with quoted argument' '
|
||||||
git update-ref -d $a &&
|
git update-ref -d $a &&
|
||||||
echo "create $a \"$m\"" >stdin &&
|
echo "create $a \"$m\"" >stdin &&
|
||||||
|
|
|
@ -51,7 +51,19 @@ test_expect_success 'creating a tag using default HEAD should succeed' '
|
||||||
echo foo >foo &&
|
echo foo >foo &&
|
||||||
git add foo &&
|
git add foo &&
|
||||||
git commit -m Foo &&
|
git commit -m Foo &&
|
||||||
git tag mytag
|
git tag mytag &&
|
||||||
|
test_must_fail git reflog exists refs/tags/mytag
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'creating a tag with --create-reflog should create reflog' '
|
||||||
|
test_when_finished "git tag -d tag_with_reflog" &&
|
||||||
|
git tag --create-reflog tag_with_reflog &&
|
||||||
|
git reflog exists refs/tags/tag_with_reflog
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--create-reflog does not create reflog on failure' '
|
||||||
|
test_must_fail git tag --create-reflog mytag &&
|
||||||
|
test_must_fail git reflog exists refs/tags/mytag
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'listing all tags if one exists should succeed' '
|
test_expect_success 'listing all tags if one exists should succeed' '
|
||||||
|
|
Loading…
Reference in New Issue