Skip to content

Commit a7206cf

Browse files
committed
Merge branch 'ps/reflog-migrate-fixes' into jch
"git refs migrate" to migrate the reflog entries from a refs backend to another had a handful of bugs squashed. * ps/reflog-migrate-fixes: refs: fix invalid old object IDs when migrating reflogs refs: stop unsetting REF_HAVE_OLD for log-only updates refs/files: detect race when generating reflog entry for HEAD refs: fix identity for migrated reflogs ident: fix type of string length parameter builtin/reflog: implement subcommand to write new entries refs: export `ref_transaction_update_reflog()` builtin/reflog: improve grouping of subcommands Documentation/git-reflog: convert to use synopsis type
2 parents 9f8f531 + e6ac69a commit a7206cf

File tree

12 files changed

+420
-108
lines changed

12 files changed

+420
-108
lines changed

Documentation/git-reflog.adoc

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ git-reflog - Manage reflog information
88

99
SYNOPSIS
1010
--------
11-
[verse]
12-
'git reflog' [show] [<log-options>] [<ref>]
13-
'git reflog list'
14-
'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
11+
[synopsis]
12+
git reflog [show] [<log-options>] [<ref>]
13+
git reflog list
14+
git reflog exists <ref>
15+
git reflog write <ref> <old-oid> <new-oid> <message>
16+
git reflog delete [--rewrite] [--updateref]
17+
[--dry-run | -n] [--verbose] <ref>@{<specifier>}...
18+
git reflog drop [--all [--single-worktree] | <refs>...]
19+
git reflog expire [--expire=<time>] [--expire-unreachable=<time>]
1520
[--rewrite] [--updateref] [--stale-fix]
1621
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
17-
'git reflog delete' [--rewrite] [--updateref]
18-
[--dry-run | -n] [--verbose] <ref>@{<specifier>}...
19-
'git reflog drop' [--all [--single-worktree] | <refs>...]
20-
'git reflog exists' <ref>
2122

2223
DESCRIPTION
2324
-----------
@@ -43,11 +44,15 @@ actions, and in addition the `HEAD` reflog records branch switching.
4344

4445
The "list" subcommand lists all refs which have a corresponding reflog.
4546

46-
The "expire" subcommand prunes older reflog entries. Entries older
47-
than `expire` time, or entries older than `expire-unreachable` time
48-
and not reachable from the current tip, are removed from the reflog.
49-
This is typically not used directly by end users -- instead, see
50-
linkgit:git-gc[1].
47+
The "exists" subcommand checks whether a ref has a reflog. It exits
48+
with zero status if the reflog exists, and non-zero status if it does
49+
not.
50+
51+
The "write" subcommand writes a single entry to the reflog of a given
52+
reference. This new entry is appended to the reflog and will thus become
53+
the most recent entry. The reference name must be fully qualified. Both the old
54+
and new object IDs must not be abbreviated and must point to existing objects.
55+
The reflog message gets normalized.
5156

5257
The "delete" subcommand deletes single entries from the reflog, but
5358
not the reflog itself. Its argument must be an _exact_ entry (e.g. "`git
@@ -58,9 +63,11 @@ The "drop" subcommand completely removes the reflog for the specified
5863
references. This is in contrast to "expire" and "delete", both of which
5964
can be used to delete reflog entries, but not the reflog itself.
6065

61-
The "exists" subcommand checks whether a ref has a reflog. It exits
62-
with zero status if the reflog exists, and non-zero status if it does
63-
not.
66+
The "expire" subcommand prunes older reflog entries. Entries older
67+
than `expire` time, or entries older than `expire-unreachable` time
68+
and not reachable from the current tip, are removed from the reflog.
69+
This is typically not used directly by end users -- instead, see
70+
linkgit:git-gc[1].
6471

6572
OPTIONS
6673
-------
@@ -71,6 +78,25 @@ Options for `show`
7178
`git reflog show` accepts any of the options accepted by `git log`.
7279

7380

81+
Options for `delete`
82+
~~~~~~~~~~~~~~~~~~~~
83+
84+
`git reflog delete` accepts options `--updateref`, `--rewrite`, `-n`,
85+
`--dry-run`, and `--verbose`, with the same meanings as when they are
86+
used with `expire`.
87+
88+
Options for `drop`
89+
~~~~~~~~~~~~~~~~~~
90+
91+
--all::
92+
Drop the reflogs of all references from all worktrees.
93+
94+
--single-worktree::
95+
By default when `--all` is specified, reflogs from all working
96+
trees are dropped. This option limits the processing to reflogs
97+
from the current working tree only.
98+
99+
74100
Options for `expire`
75101
~~~~~~~~~~~~~~~~~~~~
76102

@@ -130,24 +156,6 @@ which didn't protect objects referred to by reflogs.
130156
Print extra information on screen.
131157

132158

133-
Options for `delete`
134-
~~~~~~~~~~~~~~~~~~~~
135-
136-
`git reflog delete` accepts options `--updateref`, `--rewrite`, `-n`,
137-
`--dry-run`, and `--verbose`, with the same meanings as when they are
138-
used with `expire`.
139-
140-
Options for `drop`
141-
~~~~~~~~~~~~~~~~~~
142-
143-
--all::
144-
Drop the reflogs of all references from all worktrees.
145-
146-
--single-worktree::
147-
By default when `--all` is specified, reflogs from all working
148-
trees are dropped. This option limits the processing to reflogs
149-
from the current working tree only.
150-
151159
GIT
152160
---
153161
Part of the linkgit:git[1] suite

builtin/reflog.c

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "builtin.h"
44
#include "config.h"
55
#include "gettext.h"
6+
#include "hex.h"
7+
#include "odb.h"
68
#include "revision.h"
79
#include "reachable.h"
810
#include "wildmatch.h"
@@ -17,21 +19,24 @@
1719
#define BUILTIN_REFLOG_LIST_USAGE \
1820
N_("git reflog list")
1921

20-
#define BUILTIN_REFLOG_EXPIRE_USAGE \
21-
N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
22-
" [--rewrite] [--updateref] [--stale-fix]\n" \
23-
" [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
22+
#define BUILTIN_REFLOG_EXISTS_USAGE \
23+
N_("git reflog exists <ref>")
24+
25+
#define BUILTIN_REFLOG_WRITE_USAGE \
26+
N_("git reflog write <ref> <old-oid> <new-oid> <message>")
2427

2528
#define BUILTIN_REFLOG_DELETE_USAGE \
2629
N_("git reflog delete [--rewrite] [--updateref]\n" \
2730
" [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
2831

29-
#define BUILTIN_REFLOG_EXISTS_USAGE \
30-
N_("git reflog exists <ref>")
31-
3232
#define BUILTIN_REFLOG_DROP_USAGE \
3333
N_("git reflog drop [--all [--single-worktree] | <refs>...]")
3434

35+
#define BUILTIN_REFLOG_EXPIRE_USAGE \
36+
N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
37+
" [--rewrite] [--updateref] [--stale-fix]\n" \
38+
" [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
39+
3540
static const char *const reflog_show_usage[] = {
3641
BUILTIN_REFLOG_SHOW_USAGE,
3742
NULL,
@@ -42,33 +47,39 @@ static const char *const reflog_list_usage[] = {
4247
NULL,
4348
};
4449

45-
static const char *const reflog_expire_usage[] = {
46-
BUILTIN_REFLOG_EXPIRE_USAGE,
47-
NULL
50+
static const char *const reflog_exists_usage[] = {
51+
BUILTIN_REFLOG_EXISTS_USAGE,
52+
NULL,
53+
};
54+
55+
static const char *const reflog_write_usage[] = {
56+
BUILTIN_REFLOG_WRITE_USAGE,
57+
NULL,
4858
};
4959

5060
static const char *const reflog_delete_usage[] = {
5161
BUILTIN_REFLOG_DELETE_USAGE,
5262
NULL
5363
};
5464

55-
static const char *const reflog_exists_usage[] = {
56-
BUILTIN_REFLOG_EXISTS_USAGE,
57-
NULL,
58-
};
59-
6065
static const char *const reflog_drop_usage[] = {
6166
BUILTIN_REFLOG_DROP_USAGE,
6267
NULL,
6368
};
6469

70+
static const char *const reflog_expire_usage[] = {
71+
BUILTIN_REFLOG_EXPIRE_USAGE,
72+
NULL
73+
};
74+
6575
static const char *const reflog_usage[] = {
6676
BUILTIN_REFLOG_SHOW_USAGE,
6777
BUILTIN_REFLOG_LIST_USAGE,
68-
BUILTIN_REFLOG_EXPIRE_USAGE,
78+
BUILTIN_REFLOG_EXISTS_USAGE,
79+
BUILTIN_REFLOG_WRITE_USAGE,
6980
BUILTIN_REFLOG_DELETE_USAGE,
7081
BUILTIN_REFLOG_DROP_USAGE,
71-
BUILTIN_REFLOG_EXISTS_USAGE,
82+
BUILTIN_REFLOG_EXPIRE_USAGE,
7283
NULL
7384
};
7485

@@ -395,6 +406,59 @@ static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
395406
return ret;
396407
}
397408

409+
static int cmd_reflog_write(int argc, const char **argv, const char *prefix,
410+
struct repository *repo)
411+
{
412+
const struct option options[] = {
413+
OPT_END()
414+
};
415+
struct object_id old_oid, new_oid;
416+
struct strbuf err = STRBUF_INIT;
417+
struct ref_transaction *tx;
418+
const char *ref, *message;
419+
int ret;
420+
421+
argc = parse_options(argc, argv, prefix, options, reflog_write_usage, 0);
422+
if (argc != 4)
423+
usage_with_options(reflog_write_usage, options);
424+
425+
ref = argv[0];
426+
if (!is_root_ref(ref) && check_refname_format(ref, 0))
427+
die(_("invalid reference name: %s"), ref);
428+
429+
ret = get_oid_hex_algop(argv[1], &old_oid, repo->hash_algo);
430+
if (ret)
431+
die(_("invalid old object ID: '%s'"), argv[1]);
432+
if (!is_null_oid(&old_oid) && !odb_has_object(repo->objects, &old_oid, 0))
433+
die(_("old object '%s' does not exist"), argv[1]);
434+
435+
ret = get_oid_hex_algop(argv[2], &new_oid, repo->hash_algo);
436+
if (ret)
437+
die(_("invalid new object ID: '%s'"), argv[2]);
438+
if (!is_null_oid(&new_oid) && !odb_has_object(repo->objects, &new_oid, 0))
439+
die(_("new object '%s' does not exist"), argv[2]);
440+
441+
message = argv[3];
442+
443+
tx = ref_store_transaction_begin(get_main_ref_store(repo), 0, &err);
444+
if (!tx)
445+
die(_("cannot start transaction: %s"), err.buf);
446+
447+
ret = ref_transaction_update_reflog(tx, ref, &new_oid, &old_oid,
448+
git_committer_info(0),
449+
message, 0, &err);
450+
if (ret)
451+
die(_("cannot queue reflog update: %s"), err.buf);
452+
453+
ret = ref_transaction_commit(tx, &err);
454+
if (ret)
455+
die(_("cannot commit reflog update: %s"), err.buf);
456+
457+
ref_transaction_free(tx);
458+
strbuf_release(&err);
459+
return 0;
460+
}
461+
398462
/*
399463
* main "reflog"
400464
*/
@@ -407,10 +471,11 @@ int cmd_reflog(int argc,
407471
struct option options[] = {
408472
OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
409473
OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
410-
OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
411-
OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
412474
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
475+
OPT_SUBCOMMAND("write", &fn, cmd_reflog_write),
476+
OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
413477
OPT_SUBCOMMAND("drop", &fn, cmd_reflog_drop),
478+
OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
414479
OPT_END()
415480
};
416481

ident.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src)
272272
* can still be NULL if the input line only has the name/email part
273273
* (e.g. reading from a reflog entry).
274274
*/
275-
int split_ident_line(struct ident_split *split, const char *line, int len)
275+
int split_ident_line(struct ident_split *split, const char *line, size_t len)
276276
{
277277
const char *cp;
278278
size_t span;

ident.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void reset_ident_date(void);
3535
* Signals an success with 0, but time part of the result may be NULL
3636
* if the input lacks timestamp and zone
3737
*/
38-
int split_ident_line(struct ident_split *, const char *, int);
38+
int split_ident_line(struct ident_split *, const char *, size_t);
3939

4040
/*
4141
* Given a commit or tag object buffer and the commit or tag headers, replaces

0 commit comments

Comments
 (0)