Skip to content

Commit 144c76f

Browse files
dturner-twgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0f2a71d commit 144c76f

File tree

6 files changed

+74
-7
lines changed

6 files changed

+74
-7
lines changed

Documentation/git-tag.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ SYNOPSIS
1313
<tagname> [<commit> | <object>]
1414
'git tag' -d <tagname>...
1515
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
16-
[--column[=<options>] | --no-column] [<pattern>...]
16+
[--column[=<options>] | --no-column] [--create-reflog] [<pattern>...]
1717
[<pattern>...]
1818
'git tag' -v <tagname>...
1919

@@ -143,6 +143,9 @@ This option is only applicable when listing tags without annotation lines.
143143
all, 'whitespace' removes just leading/trailing whitespace lines and
144144
'strip' removes both whitespace and commentary.
145145

146+
--create-reflog::
147+
Create a reflog for the tag.
148+
146149
<tagname>::
147150
The name of the tag to create, delete, or describe.
148151
The new tag name must pass all checks defined by

Documentation/git-update-ref.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
11+
'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
1212

1313
DESCRIPTION
1414
-----------
@@ -67,6 +67,9 @@ performs all modifications together. Specify commands of the form:
6767
verify SP <ref> [SP <oldvalue>] LF
6868
option SP <opt> LF
6969

70+
With `--create-reflog`, update-ref will create a reflog for each ref
71+
even if one would not ordinarily be created.
72+
7073
Quote fields containing whitespace as if they were strings in C source
7174
code; i.e., surrounded by double-quotes and with backslash escapes.
7275
Use 40 "0" characters or the empty string to specify a zero value. To

builtin/tag.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
579579
struct create_tag_options opt;
580580
char *cleanup_arg = NULL;
581581
int annotate = 0, force = 0, lines = -1;
582+
int create_reflog = 0;
582583
int cmdmode = 0;
583584
const char *msgfile = NULL, *keyid = NULL;
584585
struct msg_arg msg = { 0, STRBUF_INIT };
@@ -605,6 +606,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
605606
OPT_STRING('u', "local-user", &keyid, N_("key-id"),
606607
N_("use another key to sign the tag")),
607608
OPT__FORCE(&force, N_("replace the tag if exists")),
609+
OPT_BOOL(0, "create-reflog", &create_reflog, N_("create_reflog")),
608610

609611
OPT_GROUP(N_("Tag listing options")),
610612
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)
733735
transaction = ref_transaction_begin(&err);
734736
if (!transaction ||
735737
ref_transaction_update(transaction, ref.buf, object, prev,
736-
0, NULL, &err) ||
738+
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
739+
NULL, &err) ||
737740
ref_transaction_commit(transaction, &err))
738741
die("%s", err.buf);
739742
ref_transaction_free(transaction);

builtin/update-ref.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ static const char * const git_update_ref_usage[] = {
1414

1515
static char line_termination = '\n';
1616
static int update_flags;
17+
static unsigned create_reflog_flag;
1718
static const char *msg;
1819

1920
/*
@@ -200,7 +201,8 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
200201

201202
if (ref_transaction_update(transaction, refname,
202203
new_sha1, have_old ? old_sha1 : NULL,
203-
update_flags, msg, &err))
204+
update_flags | create_reflog_flag,
205+
msg, &err))
204206
die("%s", err.buf);
205207

206208
update_flags = 0;
@@ -231,7 +233,8 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
231233
die("create %s: extra input: %s", refname, next);
232234

233235
if (ref_transaction_create(transaction, refname, new_sha1,
234-
update_flags, msg, &err))
236+
update_flags | create_reflog_flag,
237+
msg, &err))
235238
die("%s", err.buf);
236239

237240
update_flags = 0;
@@ -354,13 +357,15 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
354357
unsigned char sha1[20], oldsha1[20];
355358
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
356359
unsigned int flags = 0;
360+
int create_reflog = 0;
357361
struct option options[] = {
358362
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
359363
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
360364
OPT_BOOL( 0 , "no-deref", &no_deref,
361365
N_("update <refname> not the one it points to")),
362366
OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
363367
OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
368+
OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create_reflog")),
364369
OPT_END(),
365370
};
366371

@@ -370,6 +375,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
370375
if (msg && !*msg)
371376
die("Refusing to perform update with empty message.");
372377

378+
create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
379+
373380
if (read_stdin) {
374381
struct strbuf err = STRBUF_INIT;
375382
struct ref_transaction *transaction;
@@ -418,5 +425,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
418425
return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
419426
else
420427
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
421-
flags, UPDATE_REFS_DIE_ON_ERR);
428+
flags | create_reflog_flag,
429+
UPDATE_REFS_DIE_ON_ERR);
422430
}

t/t1400-update-ref.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ test_expect_success setup '
2323
m=refs/heads/master
2424
n_dir=refs/heads/gu
2525
n=$n_dir/fixes
26+
outside=foo
2627

2728
test_expect_success \
2829
"create $m" \
@@ -74,6 +75,24 @@ test_expect_success "delete $m (by HEAD)" '
7475
'
7576
rm -f .git/$m
7677

78+
test_expect_success 'update-ref does not create reflogs by default' '
79+
test_when_finished "git update-ref -d $outside" &&
80+
git update-ref $outside $A &&
81+
git rev-parse $A >expect &&
82+
git rev-parse $outside >actual &&
83+
test_cmp expect actual &&
84+
test_must_fail git reflog exists $outside
85+
'
86+
87+
test_expect_success 'update-ref creates reflogs with --create-reflog' '
88+
test_when_finished "git update-ref -d $outside" &&
89+
git update-ref --create-reflog $outside $A &&
90+
git rev-parse $A >expect &&
91+
git rev-parse $outside >actual &&
92+
test_cmp expect actual &&
93+
git reflog exists $outside
94+
'
95+
7796
test_expect_success \
7897
"create $m (by HEAD)" \
7998
"git update-ref HEAD $A &&
@@ -472,6 +491,25 @@ test_expect_success 'stdin create ref works' '
472491
test_cmp expect actual
473492
'
474493

494+
test_expect_success 'stdin does not create reflogs by default' '
495+
test_when_finished "git update-ref -d $outside" &&
496+
echo "create $outside $m" >stdin &&
497+
git update-ref --stdin <stdin &&
498+
git rev-parse $m >expect &&
499+
git rev-parse $outside >actual &&
500+
test_cmp expect actual &&
501+
test_must_fail git reflog exists $outside
502+
'
503+
504+
test_expect_success 'stdin creates reflogs with --create-reflog' '
505+
echo "create $outside $m" >stdin &&
506+
git update-ref --create-reflog --stdin <stdin &&
507+
git rev-parse $m >expect &&
508+
git rev-parse $outside >actual &&
509+
test_cmp expect actual &&
510+
git reflog exists $outside
511+
'
512+
475513
test_expect_success 'stdin succeeds with quoted argument' '
476514
git update-ref -d $a &&
477515
echo "create $a \"$m\"" >stdin &&

t/t7004-tag.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,19 @@ test_expect_success 'creating a tag using default HEAD should succeed' '
5151
echo foo >foo &&
5252
git add foo &&
5353
git commit -m Foo &&
54-
git tag mytag
54+
git tag mytag &&
55+
test_must_fail git reflog exists refs/tags/mytag
56+
'
57+
58+
test_expect_success 'creating a tag with --create-reflog should create reflog' '
59+
test_when_finished "git tag -d tag_with_reflog" &&
60+
git tag --create-reflog tag_with_reflog &&
61+
git reflog exists refs/tags/tag_with_reflog
62+
'
63+
64+
test_expect_success '--create-reflog does not create reflog on failure' '
65+
test_must_fail git tag --create-reflog mytag &&
66+
test_must_fail git reflog exists refs/tags/mytag
5567
'
5668

5769
test_expect_success 'listing all tags if one exists should succeed' '

0 commit comments

Comments
 (0)