Skip to content

Commit 3ff8cbf

Browse files
committed
Merge branch 'ab/reflog-parse-options'
"git reflog" command now uses parse-options API to parse its command line options. * ab/reflog-parse-options: reflog: fix 'show' subcommand's argv reflog [show]: display sensible -h output reflog: convert to parse_options() API reflog exists: use parse_options() API git reflog [expire|delete]: make -h output consistent with SYNOPSIS reflog: move "usage" variables and use macros reflog tests: add missing "git reflog exists" tests reflog: refactor cmd_reflog() to "if" branches reflog.c: indent argument lists
2 parents 4b6846d + 840344d commit 3ff8cbf

File tree

6 files changed

+165
-67
lines changed

6 files changed

+165
-67
lines changed

builtin/reflog.c

Lines changed: 95 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,48 @@
55
#include "worktree.h"
66
#include "reflog.h"
77

8-
static const char reflog_exists_usage[] =
9-
N_("git reflog exists <ref>");
8+
#define BUILTIN_REFLOG_SHOW_USAGE \
9+
N_("git reflog [show] [<log-options>] [<ref>]")
10+
11+
#define BUILTIN_REFLOG_EXPIRE_USAGE \
12+
N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
13+
" [--rewrite] [--updateref] [--stale-fix]\n" \
14+
" [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
15+
16+
#define BUILTIN_REFLOG_DELETE_USAGE \
17+
N_("git reflog delete [--rewrite] [--updateref]\n" \
18+
" [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
19+
20+
#define BUILTIN_REFLOG_EXISTS_USAGE \
21+
N_("git reflog exists <ref>")
22+
23+
static const char *const reflog_show_usage[] = {
24+
BUILTIN_REFLOG_SHOW_USAGE,
25+
NULL,
26+
};
27+
28+
static const char *const reflog_expire_usage[] = {
29+
BUILTIN_REFLOG_EXPIRE_USAGE,
30+
NULL
31+
};
32+
33+
static const char *const reflog_delete_usage[] = {
34+
BUILTIN_REFLOG_DELETE_USAGE,
35+
NULL
36+
};
37+
38+
static const char *const reflog_exists_usage[] = {
39+
BUILTIN_REFLOG_EXISTS_USAGE,
40+
NULL,
41+
};
42+
43+
static const char *const reflog_usage[] = {
44+
BUILTIN_REFLOG_SHOW_USAGE,
45+
BUILTIN_REFLOG_EXPIRE_USAGE,
46+
BUILTIN_REFLOG_DELETE_USAGE,
47+
BUILTIN_REFLOG_EXISTS_USAGE,
48+
NULL
49+
};
1050

1151
static timestamp_t default_reflog_expire;
1252
static timestamp_t default_reflog_expire_unreachable;
@@ -147,14 +187,6 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char
147187
cb->expire_unreachable = default_reflog_expire_unreachable;
148188
}
149189

150-
static const char * reflog_expire_usage[] = {
151-
N_("git reflog expire [--expire=<time>] "
152-
"[--expire-unreachable=<time>] "
153-
"[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
154-
"[--verbose] [--all] <refs>..."),
155-
NULL
156-
};
157-
158190
static int expire_unreachable_callback(const struct option *opt,
159191
const char *arg,
160192
int unset)
@@ -183,6 +215,19 @@ static int expire_total_callback(const struct option *opt,
183215
return 0;
184216
}
185217

218+
static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
219+
{
220+
struct option options[] = {
221+
OPT_END()
222+
};
223+
224+
parse_options(argc, argv, prefix, options, reflog_show_usage,
225+
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
226+
PARSE_OPT_KEEP_UNKNOWN);
227+
228+
return cmd_log_reflog(argc, argv, prefix);
229+
}
230+
186231
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
187232
{
188233
struct cmd_reflog_expire_cb cmd = { 0 };
@@ -304,12 +349,6 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
304349
return status;
305350
}
306351

307-
static const char * reflog_delete_usage[] = {
308-
N_("git reflog delete [--rewrite] [--updateref] "
309-
"[--dry-run | -n] [--verbose] <refs>..."),
310-
NULL
311-
};
312-
313352
static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
314353
{
315354
int i, status = 0;
@@ -342,57 +381,62 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
342381

343382
static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
344383
{
345-
int i, start = 0;
346-
347-
for (i = 1; i < argc; i++) {
348-
const char *arg = argv[i];
349-
if (!strcmp(arg, "--")) {
350-
i++;
351-
break;
352-
}
353-
else if (arg[0] == '-')
354-
usage(_(reflog_exists_usage));
355-
else
356-
break;
357-
}
358-
359-
start = i;
384+
struct option options[] = {
385+
OPT_END()
386+
};
387+
const char *refname;
360388

361-
if (argc - start != 1)
362-
usage(_(reflog_exists_usage));
389+
argc = parse_options(argc, argv, prefix, options, reflog_exists_usage,
390+
0);
391+
if (!argc)
392+
usage_with_options(reflog_exists_usage, options);
363393

364-
if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
365-
die(_("invalid ref format: %s"), argv[start]);
366-
return !reflog_exists(argv[start]);
394+
refname = argv[0];
395+
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
396+
die(_("invalid ref format: %s"), refname);
397+
return !reflog_exists(refname);
367398
}
368399

369400
/*
370401
* main "reflog"
371402
*/
372403

373-
static const char reflog_usage[] =
374-
"git reflog [ show | expire | delete | exists ]";
375-
376404
int cmd_reflog(int argc, const char **argv, const char *prefix)
377405
{
378-
if (argc > 1 && !strcmp(argv[1], "-h"))
379-
usage(_(reflog_usage));
406+
struct option options[] = {
407+
OPT_END()
408+
};
380409

381-
/* With no command, we default to showing it. */
382-
if (argc < 2 || *argv[1] == '-')
383-
return cmd_log_reflog(argc, argv, prefix);
410+
argc = parse_options(argc, argv, prefix, options, reflog_usage,
411+
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
412+
PARSE_OPT_KEEP_UNKNOWN |
413+
PARSE_OPT_NO_INTERNAL_HELP);
384414

385-
if (!strcmp(argv[1], "show"))
386-
return cmd_log_reflog(argc - 1, argv + 1, prefix);
415+
/*
416+
* With "git reflog" we default to showing it. !argc is
417+
* impossible with PARSE_OPT_KEEP_ARGV0.
418+
*/
419+
if (argc == 1)
420+
goto log_reflog;
387421

388-
if (!strcmp(argv[1], "expire"))
389-
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
422+
if (!strcmp(argv[1], "-h"))
423+
usage_with_options(reflog_usage, options);
424+
else if (*argv[1] == '-')
425+
goto log_reflog;
390426

391-
if (!strcmp(argv[1], "delete"))
427+
if (!strcmp(argv[1], "show"))
428+
return cmd_reflog_show(argc - 1, argv + 1, prefix);
429+
else if (!strcmp(argv[1], "expire"))
430+
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
431+
else if (!strcmp(argv[1], "delete"))
392432
return cmd_reflog_delete(argc - 1, argv + 1, prefix);
393-
394-
if (!strcmp(argv[1], "exists"))
433+
else if (!strcmp(argv[1], "exists"))
395434
return cmd_reflog_exists(argc - 1, argv + 1, prefix);
396435

436+
/*
437+
* Fall-through for e.g. "git reflog -1", "git reflog master",
438+
* as well as the plain "git reflog" above goto above.
439+
*/
440+
log_reflog:
397441
return cmd_log_reflog(argc, argv, prefix);
398442
}

reflog.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit
240240
* Return true iff the specified reflog entry should be expired.
241241
*/
242242
int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
243-
const char *email, timestamp_t timestamp, int tz,
244-
const char *message, void *cb_data)
243+
const char *email, timestamp_t timestamp, int tz,
244+
const char *message, void *cb_data)
245245
{
246246
struct expire_reflog_policy_cb *cb = cb_data;
247247
struct commit *old_commit, *new_commit;
@@ -273,10 +273,10 @@ int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
273273
}
274274

275275
int should_expire_reflog_ent_verbose(struct object_id *ooid,
276-
struct object_id *noid,
277-
const char *email,
278-
timestamp_t timestamp, int tz,
279-
const char *message, void *cb_data)
276+
struct object_id *noid,
277+
const char *email,
278+
timestamp_t timestamp, int tz,
279+
const char *message, void *cb_data)
280280
{
281281
struct expire_reflog_policy_cb *cb = cb_data;
282282
int expire;
@@ -323,8 +323,8 @@ static int is_head(const char *refname)
323323
}
324324

325325
void reflog_expiry_prepare(const char *refname,
326-
const struct object_id *oid,
327-
void *cb_data)
326+
const struct object_id *oid,
327+
void *cb_data)
328328
{
329329
struct expire_reflog_policy_cb *cb = cb_data;
330330
struct commit_list *elem;
@@ -379,8 +379,8 @@ void reflog_expiry_cleanup(void *cb_data)
379379
}
380380

381381
int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
382-
const char *email, timestamp_t timestamp, int tz,
383-
const char *message, void *cb_data)
382+
const char *email, timestamp_t timestamp, int tz,
383+
const char *message, void *cb_data)
384384
{
385385
struct cmd_reflog_expire_cb *cb = cb_data;
386386
if (!cb->expire_total || timestamp < cb->expire_total)

t/t1410-reflog.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,28 @@ test_expect_success setup '
106106
test_line_count = 4 output
107107
'
108108

109+
test_expect_success 'correct usage on sub-command -h' '
110+
test_expect_code 129 git reflog expire -h >err &&
111+
grep "git reflog expire" err
112+
'
113+
114+
test_expect_success 'correct usage on "git reflog show -h"' '
115+
test_expect_code 129 git reflog show -h >err &&
116+
grep -F "git reflog [show]" err
117+
'
118+
119+
test_expect_success 'pass through -- to sub-command' '
120+
test_when_finished "rm -rf repo" &&
121+
git init repo &&
122+
test_commit -C repo message --a-file contents dash-tag &&
123+
124+
git -C repo reflog show -- --does-not-exist >out &&
125+
test_must_be_empty out &&
126+
git -C repo reflog show >expect &&
127+
git -C repo reflog show -- --a-file >actual &&
128+
test_cmp expect actual
129+
'
130+
109131
test_expect_success rewind '
110132
test_tick && git reset --hard HEAD~2 &&
111133
test -f C &&

t/t1411-reflog-show.sh

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,4 @@ test_expect_success 'git log -g -p shows diffs vs. parents' '
169169
test_cmp expect actual
170170
'
171171

172-
test_expect_success 'reflog exists works' '
173-
git reflog exists refs/heads/main &&
174-
! git reflog exists refs/heads/nonexistent
175-
'
176-
177172
test_done

t/t1418-reflog-exists.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/sh
2+
3+
test_description='Test reflog display routines'
4+
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5+
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6+
7+
. ./test-lib.sh
8+
9+
test_expect_success 'setup' '
10+
test_commit A
11+
'
12+
13+
test_expect_success 'usage' '
14+
test_expect_code 129 git reflog exists &&
15+
test_expect_code 129 git reflog exists -h
16+
'
17+
18+
test_expect_success 'usage: unknown option' '
19+
test_expect_code 129 git reflog exists --unknown-option
20+
'
21+
22+
test_expect_success 'reflog exists works' '
23+
git reflog exists refs/heads/main &&
24+
test_must_fail git reflog exists refs/heads/nonexistent
25+
'
26+
27+
test_expect_success 'reflog exists works with a "--" delimiter' '
28+
git reflog exists -- refs/heads/main &&
29+
test_must_fail git reflog exists -- refs/heads/nonexistent
30+
'
31+
32+
test_expect_success 'reflog exists works with a "--end-of-options" delimiter' '
33+
git reflog exists --end-of-options refs/heads/main &&
34+
test_must_fail git reflog exists --end-of-options refs/heads/nonexistent
35+
'
36+
37+
test_done

t/test-lib-functions.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ test_commit () {
329329
else
330330
$echo "${3-$1}" >"$indir$file"
331331
fi &&
332-
git ${indir:+ -C "$indir"} add "$file" &&
332+
git ${indir:+ -C "$indir"} add -- "$file" &&
333333
if test -z "$notick"
334334
then
335335
test_tick

0 commit comments

Comments
 (0)