76
return strbuf_detach(&ref, NULL);
77
}
78
79
+/*
80
+ * Wrapper around parse_refname which skips the next delimiter.
81
+ */
82
+static char *parse_next_refname(const char **next)
83
+{
84
+ if (line_termination) {
85
+ /* Without -z, consume SP and use next argument */
86
+ if (!**next || **next == line_termination)
87
+ return NULL;
88
+ if (**next != ' ')
89
+ die("expected SP but got: %s", *next);
90
+ } else {
91
+ /* With -z, read the next NUL-terminated line */
92
+ if (**next)
93
+ return NULL;
94
+ }
95
+ /* Skip the delimiter */
96
+ (*next)++;
97
+
98
+ return parse_refname(next);
99
+}
100
+
101
+
102
/*
103
* The value being parsed is <old-oid> (as opposed to <new-oid>; the
104
* difference affects which error messages are generated):
320
die("verify %s: extra input: %s", refname, next);
321
322
if (ref_transaction_verify(transaction, refname, &old_oid,
300
- update_flags, &err))
323
+ NULL, update_flags, &err))
324
+ die("%s", err.buf);
325
+
326
+ update_flags = default_flags;
327
+ free(refname);
328
+ strbuf_release(&err);
329
+}
330
+
331
+static void parse_cmd_symref_verify(struct ref_transaction *transaction,
332
+ const char *next, const char *end)
333
+{
334
+ struct strbuf err = STRBUF_INIT;
335
+ struct object_id old_oid;
336
+ char *refname, *old_target;
337
+
338
+ if (!(update_flags & REF_NO_DEREF))
339
+ die("symref-verify: cannot operate with deref mode");
340
+
341
+ refname = parse_refname(&next);
342
+ if (!refname)
343
+ die("symref-verify: missing <ref>");
344
+
345
+ /*
346
+ * old_ref is optional, if not provided, we need to ensure that the
347
+ * ref doesn't exist.
348
+ */
349
+ old_target = parse_next_refname(&next);
350
+ if (!old_target)
351
+ oidcpy(&old_oid, null_oid());
352
+
353
+ if (*next != line_termination)
354
+ die("symref-verify %s: extra input: %s", refname, next);
355
+
356
+ if (ref_transaction_verify(transaction, refname,
357
+ old_target ? NULL : &old_oid,
358
+ old_target, update_flags, &err))
359
die("%s", err.buf);
360
361
update_flags = default_flags;
362
free(refname);
363
+ free(old_target);
364
strbuf_release(&err);
365
}
366
439
unsigned args;
440
enum update_refs_state state;
441
} command[] = {
383
- { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
384
- { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
385
- { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
386
- { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
387
- { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
388
- { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
389
- { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
390
- { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
391
- { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
442
+ { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
443
+ { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
444
+ { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
445
+ { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
446
+ { "symref-verify", parse_cmd_symref_verify, 2, UPDATE_REFS_OPEN },
447
+ { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
448
+ { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
449
+ { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
450
+ { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
451
+ { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
452
};
453
454
static void update_refs_stdin(void)