update-ref: allow --no-deref with --stdin

If passed both --no-deref and --stdin, update-ref would error out with a general usage message that did not at all suggest these options were incompatible. The manpage for update-ref did suggest through its synopsis line that --no-deref and --stdin were incompatible, but it sadly also incorrectly suggested that -d and --no-deref were incompatible. So the help around the --no-deref option is buggy in a few ways. The --stdin option did provide a different mechanism for avoiding dereferencing symbolic-refs: adding a line reading option no-deref before every other directive in the input. (Technically, if the user wants to do the extra work of first determining which refs they want to update or delete are symbolic, then they only need to put the extra "option no-deref" lines before the updates of those refs. But in some cases, that's more work than just adding the "option no-deref" before every other directive.) It's easier to allow the user to just pass --no-deref along with --stdin in order to tell update-ref that the user doesn't want any symbolic ref to be dereferenced. It also makes the update-ref documentation simpler. Implement that, and update the documentation to match. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Sep 5, 2018 at 10:25 UTC d345e9fbe75c8bec6469253f0ee7e34228f41917
3 files changed +45 -11
Documentation/git-update-ref.txt
+1 -1
@@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
8 SYNOPSIS
9 --------
10 [verse]
11 -'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
11 +'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<oldvalue>] | [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
12
13 DESCRIPTION
14 -----------
builtin/update-ref.c
+13 -10
@@ -15,6 +15,7 @@ static const char * const git_update_ref_usage[] = {
15
16 static char line_termination = '\n';
17 static unsigned int update_flags;
18 +static unsigned int default_flags;
19 static unsigned create_reflog_flag;
20 static const char *msg;
21
@@ -205,7 +206,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
206 msg, &err))
207 die("%s", err.buf);
208
208 - update_flags = 0;
209 + update_flags = default_flags;
210 free(refname);
211 strbuf_release(&err);
212
@@ -237,7 +238,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
238 msg, &err))
239 die("%s", err.buf);
240
240 - update_flags = 0;
241 + update_flags = default_flags;
242 free(refname);
243 strbuf_release(&err);
244
@@ -273,7 +274,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
274 update_flags, msg, &err))
275 die("%s", err.buf);
276
276 - update_flags = 0;
277 + update_flags = default_flags;
278 free(refname);
279 strbuf_release(&err);
280
@@ -302,7 +303,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
303 update_flags, &err))
304 die("%s", err.buf);
305
305 - update_flags = 0;
306 + update_flags = default_flags;
307 free(refname);
308 strbuf_release(&err);
309
@@ -357,7 +358,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
358 const char *refname, *oldval;
359 struct object_id oid, oldoid;
360 int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
360 - unsigned int flags = 0;
361 int create_reflog = 0;
362 struct option options[] = {
363 OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
@@ -378,6 +378,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
378
379 create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
380
381 + if (no_deref) {
382 + default_flags = REF_NO_DEREF;
383 + update_flags = default_flags;
384 + }
385 +
386 if (read_stdin) {
387 struct strbuf err = STRBUF_INIT;
388 struct ref_transaction *transaction;
@@ -385,7 +390,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
390 transaction = ref_transaction_begin(&err);
391 if (!transaction)
392 die("%s", err.buf);
388 - if (delete || no_deref || argc > 0)
393 + if (delete || argc > 0)
394 usage_with_options(git_update_ref_usage, options);
395 if (end_null)
396 line_termination = '\0';
@@ -427,8 +432,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
432 die("%s: not a valid old SHA1", oldval);
433 }
434
430 - if (no_deref)
431 - flags = REF_NO_DEREF;
435 if (delete)
436 /*
437 * For purposes of backwards compatibility, we treat
@@ -436,9 +439,9 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
439 */
440 return delete_ref(msg, refname,
441 (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
439 - flags);
442 + default_flags);
443 else
444 return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
442 - flags | create_reflog_flag,
445 + default_flags | create_reflog_flag,
446 UPDATE_REFS_DIE_ON_ERR);
447 }
t/t1400-update-ref.sh
+31
@@ -807,6 +807,37 @@ test_expect_success 'stdin delete symref works option no-deref' '
807 test_cmp expect actual
808 '
809
810 +test_expect_success 'stdin update symref works flag --no-deref' '
811 + git symbolic-ref TESTSYMREFONE $b &&
812 + git symbolic-ref TESTSYMREFTWO $b &&
813 + cat >stdin <<-EOF &&
814 + update TESTSYMREFONE $a $b
815 + update TESTSYMREFTWO $a $b
816 + EOF
817 + git update-ref --no-deref --stdin <stdin &&
818 + git rev-parse TESTSYMREFONE TESTSYMREFTWO >expect &&
819 + git rev-parse $a $a >actual &&
820 + test_cmp expect actual &&
821 + git rev-parse $m~1 >expect &&
822 + git rev-parse $b >actual &&
823 + test_cmp expect actual
824 +'
825 +
826 +test_expect_success 'stdin delete symref works flag --no-deref' '
827 + git symbolic-ref TESTSYMREFONE $b &&
828 + git symbolic-ref TESTSYMREFTWO $b &&
829 + cat >stdin <<-EOF &&
830 + delete TESTSYMREFONE $b
831 + delete TESTSYMREFTWO $b
832 + EOF
833 + git update-ref --no-deref --stdin <stdin &&
834 + test_must_fail git rev-parse --verify -q TESTSYMREFONE &&
835 + test_must_fail git rev-parse --verify -q TESTSYMREFTWO &&
836 + git rev-parse $m~1 >expect &&
837 + git rev-parse $b >actual &&
838 + test_cmp expect actual
839 +'
840 +
841 test_expect_success 'stdin delete ref works with right old value' '
842 echo "delete $b $m~1" >stdin &&
843 git update-ref --stdin <stdin &&