{"thread":{"id":"56981","subject":"[PATCH 1/2] refs: update comment.","startedAt":"2021-11-25T16:09:44Z","lastAt":"2021-12-07T21:18:11Z","messageCount":42,"participants":["Han-Wen Nienhuys via GitGitGadget","Junio C Hamano","Han-Wen Nienhuys","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"442312","messageId":"pull.1147.git.git.1637855761.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":null,"subject":"[PATCH 0/2] Allow writing invalid OIDs into refs for testing purposes","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-25T15:55:59Z","receivedAt":"2021-11-25T16:09:44Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"this covers a few cases of direct filesystem access to the ref database in\ntests.\n\nHan-Wen Nienhuys (2):\n  refs: update comment.\n  refs: allow skipping OID verification\n\n refs.h               |  8 ++++++-\n refs/files-backend.c | 53 +++++++++++++++++++++++++-------------------\n t/t1006-cat-file.sh  |  5 ++---\n t/t3800-mktag.sh     |  6 +++--\n 4 files changed, 43 insertions(+), 29 deletions(-)\n\n\nbase-commit: 5f439a0ecfb4657100ec1e56ef9c6eca963b5a94\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1147%2Fhanwen%2Fskip-verification-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1147/hanwen/skip-verification-v1\nPull-Request: https://github.com/git/git/pull/1147\n-- \ngitgitgadget\n"},{"id":"442311","messageId":"b83bfda2443bd10930e46efadc9bd051de5ec43d.1637855761.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.git.git.1637855761.gitgitgadget@gmail.com","subject":"[PATCH 1/2] refs: update comment.","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-25T15:56:00Z","receivedAt":"2021-11-25T16:09:46Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nREF_IS_PRUNING is right below this comment, so it clearly does not belong in\nthis comment. This was apparently introduced in commit 5ac95fee (Nov 5, 2017\n\"refs: tidy up and adjust visibility of the `ref_update` flags\").\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs/files-backend.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 151b0056fe5..5cfdec1e820 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -16,8 +16,7 @@\n  * This backend uses the following flags in `ref_update::flags` for\n  * internal bookkeeping purposes. Their numerical values must not\n  * conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,\n- * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in\n- * `ref_update::flags`.\n+ * or REF_HAVE_OLD, which are also stored in `ref_update::flags`.\n  */\n \n /*\n-- \ngitgitgadget\n\n"},{"id":"442313","messageId":"900cea2ade9e86b135e4189070a68deea5e9b575.1637855761.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.git.git.1637855761.gitgitgadget@gmail.com","subject":"[PATCH 2/2] refs: allow skipping OID verification","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-25T15:56:01Z","receivedAt":"2021-11-25T16:09:48Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis introduces the REF_SKIP_OID_VERIFICATION flag, which lets the ref-store\ntest helper write non-existent or unparsable objects into the ref storage.\n\nUse this to make t1006 and t3800 independent of the files storage backend.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.h               |  8 ++++++-\n refs/files-backend.c | 50 +++++++++++++++++++++++++-------------------\n t/t1006-cat-file.sh  |  5 ++---\n t/t3800-mktag.sh     |  6 ++++--\n 4 files changed, 42 insertions(+), 27 deletions(-)\n\ndiff --git a/refs.h b/refs.h\nindex d5099d4984e..46e68fd4c2a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -611,12 +611,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_FORCE_CREATE_REFLOG (1 << 1)\n \n+/*\n+ * Blindly write an object_id. This is useful for testing data corruption\n+ * scenarios.\n+ */\n+#define REF_SKIP_OID_VERIFICATION (1 << 10)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n #define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG)\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 5cfdec1e820..28a349b24ad 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1351,7 +1351,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)\n }\n \n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err);\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err);\n static int commit_ref_update(struct files_ref_store *refs,\n \t\t\t     struct ref_lock *lock,\n \t\t\t     const struct object_id *oid, const char *logmsg,\n@@ -1468,7 +1469,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \t}\n \toidcpy(&lock->old_oid, &orig_oid);\n \n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1488,7 +1489,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = LOG_REFS_NONE;\n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1724,26 +1725,31 @@ static int files_log_ref_write(struct files_ref_store *refs,\n  * errors, rollback the lockfile, fill in *err and return -1.\n  */\n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err)\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err)\n {\n \tstatic char term = '\\n';\n \tstruct object *o;\n \tint fd;\n \n-\to = parse_object(the_repository, oid);\n-\tif (!o) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write ref '%s' with nonexistent object %s\",\n-\t\t\t    lock->ref_name, oid_to_hex(oid));\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n-\t}\n-\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write non-commit object %s to branch '%s'\",\n-\t\t\t    oid_to_hex(oid), lock->ref_name);\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n+\tif (!skip_oid_verification) {\n+\t\to = parse_object(the_repository, oid);\n+\t\tif (!o) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write ref '%s' with nonexistent object %s\",\n+\t\t\t\tlock->ref_name, oid_to_hex(oid));\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write non-commit object %s to branch '%s'\",\n+\t\t\t\toid_to_hex(oid), lock->ref_name);\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n \t}\n \tfd = get_lock_file_fd(&lock->lk);\n \tif (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||\n@@ -2150,7 +2156,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n }\n \n static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,\n-\t\t\t\t   struct object_id *peeled)\n+\t\t\t\t      struct object_id *peeled)\n {\n \tBUG(\"ref_iterator_peel() called for reflog_iterator\");\n }\n@@ -2534,8 +2540,10 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * The reference already has the desired\n \t\t\t * value, so we don't need to write it.\n \t\t\t */\n-\t\t} else if (write_ref_to_lockfile(lock, &update->new_oid,\n-\t\t\t\t\t\t err)) {\n+\t\t} else if (write_ref_to_lockfile(\n+\t\t\t\t   lock, &update->new_oid,\n+\t\t\t\t   update->flags & REF_SKIP_OID_VERIFICATION,\n+\t\t\t\t   err)) {\n \t\t\tchar *write_err = strbuf_detach(err, NULL);\n \n \t\t\t/*\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 658628375c8..f5333196b07 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -452,9 +452,8 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme\n \t# Create it manually, as \"git replace\" will die on bogus\n \t# types.\n \thead=$(git rev-parse --verify HEAD) &&\n-\ttest_when_finished \"rm -rf .git/refs/replace\" &&\n-\tmkdir -p .git/refs/replace &&\n-\techo $head >.git/refs/replace/$bogus_short_sha1 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID 1024 &&\n \n \tcat >expect <<-EOF &&\n \tcommit\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 0544d58a6ea..128d374f740 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -72,7 +72,8 @@ check_verify_failure () {\n \n \t\t# Manually create the broken, we cannot do it with\n \t\t# update-ref\n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID 1024 &&\n \n \t\t# Unlike fsck-ing unreachable content above, this\n \t\t# will always fail.\n@@ -83,7 +84,8 @@ check_verify_failure () {\n \t\t# Make sure the earlier test created it for us\n \t\tgit rev-parse \"$bad_tag\" &&\n \n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID 1024 &&\n \n \t\tprintf \"%s tag\\t%s\\n\" \"$bad_tag\" \"$tag_ref\" >expected &&\n \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n-- \ngitgitgadget\n"},{"id":"442346","messageId":"xmqqbl278j9o.fsf@gitster.g","threadId":"56981","inReplyTo":"900cea2ade9e86b135e4189070a68deea5e9b575.1637855761.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 2/2] refs: allow skipping OID verification","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-26T07:32:03Z","receivedAt":"2021-11-26T07:34:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Han-Wen Nienhuys <hanwen@google.com>\n>\n> This introduces the REF_SKIP_OID_VERIFICATION flag, which lets the ref-store\n> test helper write non-existent or unparsable objects into the ref storage.\n\nYay.\n\n> diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\n> index 658628375c8..f5333196b07 100755\n> --- a/t/t1006-cat-file.sh\n> +++ b/t/t1006-cat-file.sh\n> @@ -452,9 +452,8 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme\n>  \t# Create it manually, as \"git replace\" will die on bogus\n>  \t# types.\n>  \thead=$(git rev-parse --verify HEAD) &&\n> -\ttest_when_finished \"rm -rf .git/refs/replace\" &&\n> -\tmkdir -p .git/refs/replace &&\n> -\techo $head >.git/refs/replace/$bogus_short_sha1 &&\n> +\ttest_when_finished \"test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1\" &&\n> +\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID 1024 &&\n\nDouble yay.  Tests that are independent of backend is indeed much nicer.\n"},{"id":"442495","messageId":"0a297f0c3e884c2d4cfb24a6d3b9f1973fc83125.1638211786.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:44Z","receivedAt":"2021-11-29T21:52:40Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nUse this flag with the test-helper in t1430, to avoid direct writes to the ref\ndatabase.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.c                  |  7 ++---\n refs.h                  | 10 +++++--\n t/t1430-bad-ref-name.sh | 59 ++++++++++++++++++++++-------------------\n 3 files changed, 44 insertions(+), 32 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex d7cc0a23a3b..086b1341d2a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1078,9 +1078,10 @@ int ref_transaction_update(struct ref_transaction *transaction,\n {\n \tassert(err);\n \n-\tif ((new_oid && !is_null_oid(new_oid)) ?\n-\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n-\t    !refname_is_safe(refname)) {\n+\tif (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n+\t    ((new_oid && !is_null_oid(new_oid)) ?\n+\t\t     check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n+\t\t\t   !refname_is_safe(refname))) {\n \t\tstrbuf_addf(err, _(\"refusing to update ref with bad name '%s'\"),\n \t\t\t    refname);\n \t\treturn -1;\ndiff --git a/refs.h b/refs.h\nindex 46e68fd4c2a..684f8b33d17 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -617,12 +617,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_SKIP_OID_VERIFICATION (1 << 10)\n \n+/*\n+ * Skip verifying refname. This is useful for testing data corruption scenarios.\n+ */\n+#define REF_SKIP_REFNAME_VERIFICATION (1 << 11)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n-#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n+#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS                                  \\\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \\\n+\t REF_SKIP_REFNAME_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 4c77cf89a6c..56d0726944e 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -9,7 +9,8 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n test_expect_success setup '\n \ttest_commit one &&\n-\ttest_commit two\n+\ttest_commit two &&\n+\tmain_sha1=$(git rev-parse refs/heads/main)\n '\n \n test_expect_success 'fast-import: fail on invalid branch name \".badbranchname\"' '\n@@ -43,16 +44,16 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n '\n \n test_expect_success 'git branch shows badly named ref as warning' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch >output 2>error &&\n \ttest_i18ngrep -e \"ignoring ref with broken name refs/heads/broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete badly named ref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch -d broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -60,8 +61,8 @@ test_expect_success 'branch -d can delete badly named ref' '\n '\n \n test_expect_success 'branch -D can delete badly named ref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch -D broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -90,7 +91,7 @@ test_expect_success 'branch -D cannot delete absolute path' '\n '\n \n test_expect_success 'git branch cannot create a badly named ref' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \ttest_must_fail git branch broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -98,7 +99,7 @@ test_expect_success 'git branch cannot create a badly named ref' '\n '\n \n test_expect_success 'branch -m cannot rename to a bad ref name' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \ttest_might_fail git branch -D goodref &&\n \tgit branch goodref &&\n \ttest_must_fail git branch -m goodref broken...ref &&\n@@ -109,8 +110,9 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n '\n \n test_expect_failure 'branch -m can rename from a bad ref name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch -m broken...ref renamed &&\n \ttest_cmp_rev main renamed &&\n \tgit branch >output 2>error &&\n@@ -119,7 +121,7 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n '\n \n test_expect_success 'push cannot create a badly named ref' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \ttest_must_fail git push \"file://$(pwd)\" HEAD:refs/heads/broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -139,7 +141,7 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n \t\tcd dest &&\n \t\ttest_commit two &&\n \t\tgit checkout --detach &&\n-\t\tcp .git/refs/heads/main .git/refs/heads/broken...ref\n+\t\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048\n \t) &&\n \tgit -C src push --mirror \"file://$top/dest\" &&\n \tgit -C dest branch >output 2>error &&\n@@ -148,9 +150,9 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n '\n \n test_expect_success 'rev-parse skips symref pointing to broken name' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch shadow one &&\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n \ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n@@ -160,8 +162,8 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n '\n \n test_expect_success 'for-each-ref emits warnings for broken names' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n@@ -176,8 +178,8 @@ test_expect_success 'for-each-ref emits warnings for broken names' '\n '\n \n test_expect_success 'update-ref -d can delete broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit update-ref -d refs/heads/broken...ref >output 2>error &&\n \ttest_must_be_empty output &&\n \ttest_must_be_empty error &&\n@@ -187,8 +189,8 @@ test_expect_success 'update-ref -d can delete broken name' '\n '\n \n test_expect_success 'branch -d can delete broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch -d broken...ref >output 2>error &&\n \ttest_i18ngrep \"Deleted branch broken...ref (was broken)\" output &&\n \ttest_must_be_empty error &&\n@@ -198,8 +200,9 @@ test_expect_success 'branch -d can delete broken name' '\n '\n \n test_expect_success 'update-ref --no-deref -d can delete symref to broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n@@ -209,8 +212,9 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n '\n \n test_expect_success 'branch -d can delete symref to broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n@@ -238,8 +242,9 @@ test_expect_success 'branch -d can delete dangling symref to broken name' '\n '\n \n test_expect_success 'update-ref -d can delete broken name through symref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n-- \ngitgitgadget\n\n"},{"id":"442496","messageId":"3c100702fda81bf4ba572085ebce4e4fee94a4f3.1638211786.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v2 6/6] t1430: create valid symrefs using test-helper","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:46Z","receivedAt":"2021-11-29T21:52:42Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis still leaves some other direct filesystem access. Currently, the files\nbackend does not allow invalidly named symrefs. Fixes for this are currently in\nthe 'seen' branch\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/t1430-bad-ref-name.sh | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 5c600980b5f..05a4ee712ca 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -153,7 +153,7 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tgit branch shadow one &&\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n+\ttest-tool ref-store main create-symref refs/tags/shadow refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n \tgit rev-parse --verify shadow >actual 2>err &&\n@@ -203,7 +203,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n \n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -215,7 +215,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n \n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -224,7 +224,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -233,7 +233,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n '\n \n test_expect_success 'branch -d can delete dangling symref to broken name' '\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -245,7 +245,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n \n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...ref &&\n-- \ngitgitgadget\n"},{"id":"442497","messageId":"06c8ff7df15d325c7d66a63d30d94fcfe2ef91c0.1638211786.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v2 5/6] t1430: remove refs using test-tool","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:45Z","receivedAt":"2021-11-29T21:52:44Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/t1430-bad-ref-name.sh | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 56d0726944e..5c600980b5f 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -154,7 +154,7 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n \tgit branch shadow one &&\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n-\ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n \tgit rev-parse --verify shadow >actual 2>err &&\n \ttest_cmp expect actual &&\n@@ -165,9 +165,9 @@ test_expect_success 'for-each-ref emits warnings for broken names' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n \tgit for-each-ref >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output &&\n \t! grep -e \"badname\" output &&\n@@ -204,7 +204,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_must_be_empty output &&\n@@ -216,7 +216,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n@@ -225,7 +225,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_must_be_empty output &&\n@@ -234,7 +234,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n \n test_expect_success 'branch -d can delete dangling symref to broken name' '\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n@@ -246,7 +246,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \n \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...ref &&\n \ttest_must_be_empty output &&\n@@ -255,7 +255,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \n test_expect_success 'update-ref --no-deref -d can delete symref with broken name' '\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_must_be_empty output &&\n@@ -264,7 +264,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref with broken name\n \n test_expect_success 'branch -d can delete symref with broken name' '\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n \tgit branch -d broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/main)\" output &&\n@@ -273,7 +273,7 @@ test_expect_success 'branch -d can delete symref with broken name' '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' '\n \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_must_be_empty output &&\n@@ -282,7 +282,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref with br\n \n test_expect_success 'branch -d can delete dangling symref with broken name' '\n \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n \tgit branch -d broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/idonotexist)\" output &&\n-- \ngitgitgadget\n\n"},{"id":"442540","messageId":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.git.git.1637855761.gitgitgadget@gmail.com","subject":"[PATCH v2 0/6] Allow writing invalid OIDs into refs for testing purposes","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:40Z","receivedAt":"2021-11-29T22:34:33Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"this covers a few cases of direct filesystem access to the ref database in\ntests.\n\nv2 folds in more fixes for making t1430 reftable-proof.\n\n * add REF_SKIP_REFNAME_VERIFICATION as well\n * upgrade some more bits of t1430\n\nHan-Wen Nienhuys (6):\n  test-ref-store: plug memory leak in cmd_delete_refs\n  refs: update comment.\n  refs: allow skipping OID verification\n  refs: add REF_SKIP_REFNAME_VERIFICATION flag\n  t1430: remove refs using test-tool\n  t1430: create valid symrefs using test-helper\n\n refs.c                    |  7 +--\n refs.h                    | 16 ++++++-\n refs/files-backend.c      | 53 ++++++++++++----------\n t/helper/test-ref-store.c |  6 ++-\n t/t1006-cat-file.sh       |  5 +--\n t/t1430-bad-ref-name.sh   | 95 ++++++++++++++++++++-------------------\n t/t3800-mktag.sh          |  6 ++-\n 7 files changed, 108 insertions(+), 80 deletions(-)\n\n\nbase-commit: 35151cf0720460a897cde9b8039af364743240e7\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1147%2Fhanwen%2Fskip-verification-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1147/hanwen/skip-verification-v2\nPull-Request: https://github.com/git/git/pull/1147\n\nRange-diff vs v1:\n\n -:  ----------- > 1:  7fa5c247c8b test-ref-store: plug memory leak in cmd_delete_refs\n 1:  b83bfda2443 = 2:  82971ddbfcf refs: update comment.\n 2:  900cea2ade9 = 3:  93fe3f03fb2 refs: allow skipping OID verification\n -:  ----------- > 4:  0a297f0c3e8 refs: add REF_SKIP_REFNAME_VERIFICATION flag\n -:  ----------- > 5:  06c8ff7df15 t1430: remove refs using test-tool\n -:  ----------- > 6:  3c100702fda t1430: create valid symrefs using test-helper\n\n-- \ngitgitgadget\n"},{"id":"442543","messageId":"7fa5c247c8b1cdeb4fcd166cfb6e98425d21e5ae.1638211786.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v2 1/6] test-ref-store: plug memory leak in cmd_delete_refs","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:41Z","receivedAt":"2021-11-29T22:37:47Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex b314b81a45b..ccc2bb01bf3 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -86,11 +86,13 @@ static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n \tunsigned int flags = arg_flags(*argv++, \"flags\");\n \tconst char *msg = *argv++;\n \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n-\n+\tint result;\n \twhile (*argv)\n \t\tstring_list_append(&refnames, *argv++);\n \n-\treturn refs_delete_refs(refs, msg, &refnames, flags);\n+\tresult = refs_delete_refs(refs, msg, &refnames, flags);\n+\tstring_list_clear(&refnames, 0);\n+\treturn result;\n }\n \n static int cmd_rename_ref(struct ref_store *refs, const char **argv)\n-- \ngitgitgadget\n\n"},{"id":"442551","messageId":"93fe3f03fb2a10f36aff4a6e4702053daeaa1d64.1638211786.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v2 3/6] refs: allow skipping OID verification","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:43Z","receivedAt":"2021-11-29T22:54:35Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis introduces the REF_SKIP_OID_VERIFICATION flag, which lets the ref-store\ntest helper write non-existent or unparsable objects into the ref storage.\n\nUse this to make t1006 and t3800 independent of the files storage backend.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.h               |  8 ++++++-\n refs/files-backend.c | 50 +++++++++++++++++++++++++-------------------\n t/t1006-cat-file.sh  |  5 ++---\n t/t3800-mktag.sh     |  6 ++++--\n 4 files changed, 42 insertions(+), 27 deletions(-)\n\ndiff --git a/refs.h b/refs.h\nindex d5099d4984e..46e68fd4c2a 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -611,12 +611,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_FORCE_CREATE_REFLOG (1 << 1)\n \n+/*\n+ * Blindly write an object_id. This is useful for testing data corruption\n+ * scenarios.\n+ */\n+#define REF_SKIP_OID_VERIFICATION (1 << 10)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n #define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG)\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 5cfdec1e820..28a349b24ad 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1351,7 +1351,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)\n }\n \n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err);\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err);\n static int commit_ref_update(struct files_ref_store *refs,\n \t\t\t     struct ref_lock *lock,\n \t\t\t     const struct object_id *oid, const char *logmsg,\n@@ -1468,7 +1469,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \t}\n \toidcpy(&lock->old_oid, &orig_oid);\n \n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1488,7 +1489,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = LOG_REFS_NONE;\n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1724,26 +1725,31 @@ static int files_log_ref_write(struct files_ref_store *refs,\n  * errors, rollback the lockfile, fill in *err and return -1.\n  */\n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err)\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err)\n {\n \tstatic char term = '\\n';\n \tstruct object *o;\n \tint fd;\n \n-\to = parse_object(the_repository, oid);\n-\tif (!o) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write ref '%s' with nonexistent object %s\",\n-\t\t\t    lock->ref_name, oid_to_hex(oid));\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n-\t}\n-\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write non-commit object %s to branch '%s'\",\n-\t\t\t    oid_to_hex(oid), lock->ref_name);\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n+\tif (!skip_oid_verification) {\n+\t\to = parse_object(the_repository, oid);\n+\t\tif (!o) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write ref '%s' with nonexistent object %s\",\n+\t\t\t\tlock->ref_name, oid_to_hex(oid));\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write non-commit object %s to branch '%s'\",\n+\t\t\t\toid_to_hex(oid), lock->ref_name);\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n \t}\n \tfd = get_lock_file_fd(&lock->lk);\n \tif (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||\n@@ -2150,7 +2156,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n }\n \n static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,\n-\t\t\t\t   struct object_id *peeled)\n+\t\t\t\t      struct object_id *peeled)\n {\n \tBUG(\"ref_iterator_peel() called for reflog_iterator\");\n }\n@@ -2534,8 +2540,10 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * The reference already has the desired\n \t\t\t * value, so we don't need to write it.\n \t\t\t */\n-\t\t} else if (write_ref_to_lockfile(lock, &update->new_oid,\n-\t\t\t\t\t\t err)) {\n+\t\t} else if (write_ref_to_lockfile(\n+\t\t\t\t   lock, &update->new_oid,\n+\t\t\t\t   update->flags & REF_SKIP_OID_VERIFICATION,\n+\t\t\t\t   err)) {\n \t\t\tchar *write_err = strbuf_detach(err, NULL);\n \n \t\t\t/*\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 658628375c8..f5333196b07 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -452,9 +452,8 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme\n \t# Create it manually, as \"git replace\" will die on bogus\n \t# types.\n \thead=$(git rev-parse --verify HEAD) &&\n-\ttest_when_finished \"rm -rf .git/refs/replace\" &&\n-\tmkdir -p .git/refs/replace &&\n-\techo $head >.git/refs/replace/$bogus_short_sha1 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID 1024 &&\n \n \tcat >expect <<-EOF &&\n \tcommit\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 0544d58a6ea..128d374f740 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -72,7 +72,8 @@ check_verify_failure () {\n \n \t\t# Manually create the broken, we cannot do it with\n \t\t# update-ref\n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID 1024 &&\n \n \t\t# Unlike fsck-ing unreachable content above, this\n \t\t# will always fail.\n@@ -83,7 +84,8 @@ check_verify_failure () {\n \t\t# Make sure the earlier test created it for us\n \t\tgit rev-parse \"$bad_tag\" &&\n \n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID 1024 &&\n \n \t\tprintf \"%s tag\\t%s\\n\" \"$bad_tag\" \"$tag_ref\" >expected &&\n \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n-- \ngitgitgadget\n\n"},{"id":"442558","messageId":"82971ddbfcf233c4462fb13eff8b742d84c72db0.1638211786.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v2 2/6] refs: update comment.","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-11-29T18:49:42Z","receivedAt":"2021-11-29T23:04:44Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nREF_IS_PRUNING is right below this comment, so it clearly does not belong in\nthis comment. This was apparently introduced in commit 5ac95fee (Nov 5, 2017\n\"refs: tidy up and adjust visibility of the `ref_update` flags\").\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs/files-backend.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 151b0056fe5..5cfdec1e820 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -16,8 +16,7 @@\n  * This backend uses the following flags in `ref_update::flags` for\n  * internal bookkeeping purposes. Their numerical values must not\n  * conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,\n- * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in\n- * `ref_update::flags`.\n+ * or REF_HAVE_OLD, which are also stored in `ref_update::flags`.\n  */\n \n /*\n-- \ngitgitgadget\n\n"},{"id":"442573","messageId":"xmqqy2564kut.fsf@gitster.g","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 0/6] Allow writing invalid OIDs into refs for testing purposes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T23:12:42Z","receivedAt":"2021-11-29T23:13:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> this covers a few cases of direct filesystem access to the ref database in\n> tests.\n>\n> v2 folds in more fixes for making t1430 reftable-proof.\n>\n>  * add REF_SKIP_REFNAME_VERIFICATION as well\n>  * upgrade some more bits of t1430\n\nThanks, will replace.\n"},{"id":"442575","messageId":"xmqqsfve4kqj.fsf@gitster.g","threadId":"56981","inReplyTo":"7fa5c247c8b1cdeb4fcd166cfb6e98425d21e5ae.1638211786.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/6] test-ref-store: plug memory leak in cmd_delete_refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T23:15:16Z","receivedAt":"2021-11-29T23:15:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Han-Wen Nienhuys <hanwen@google.com>\n>\n> Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>\n> ---\n>  t/helper/test-ref-store.c | 6 ++++--\n>  1 file changed, 4 insertions(+), 2 deletions(-)\n>\n> diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\n> index b314b81a45b..ccc2bb01bf3 100644\n> --- a/t/helper/test-ref-store.c\n> +++ b/t/helper/test-ref-store.c\n> @@ -86,11 +86,13 @@ static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n>  \tunsigned int flags = arg_flags(*argv++, \"flags\");\n>  \tconst char *msg = *argv++;\n>  \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n> -\n> +\tint result;\n\nThanks, but let's not lose the blank line between the declarations\nand the first statement, which serves for readability.\n\n>  \twhile (*argv)\n>  \t\tstring_list_append(&refnames, *argv++);\n>  \n> -\treturn refs_delete_refs(refs, msg, &refnames, flags);\n> +\tresult = refs_delete_refs(refs, msg, &refnames, flags);\n> +\tstring_list_clear(&refnames, 0);\n> +\treturn result;\n>  }\n>  \n>  static int cmd_rename_ref(struct ref_store *refs, const char **argv)\n"},{"id":"442576","messageId":"xmqqo8624knk.fsf@gitster.g","threadId":"56981","inReplyTo":"82971ddbfcf233c4462fb13eff8b742d84c72db0.1638211786.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 2/6] refs: update comment.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T23:17:03Z","receivedAt":"2021-11-29T23:17:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Han-Wen Nienhuys <hanwen@google.com>\n>\n> REF_IS_PRUNING is right below this comment, so it clearly does not belong in\n> this comment. This was apparently introduced in commit 5ac95fee (Nov 5, 2017\n> \"refs: tidy up and adjust visibility of the `ref_update` flags\").\n\nThanks for carefully reading and correcting.\n\n>\n> Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>\n> ---\n>  refs/files-backend.c | 3 +--\n>  1 file changed, 1 insertion(+), 2 deletions(-)\n>\n> diff --git a/refs/files-backend.c b/refs/files-backend.c\n> index 151b0056fe5..5cfdec1e820 100644\n> --- a/refs/files-backend.c\n> +++ b/refs/files-backend.c\n> @@ -16,8 +16,7 @@\n>   * This backend uses the following flags in `ref_update::flags` for\n>   * internal bookkeeping purposes. Their numerical values must not\n>   * conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,\n> - * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in\n> - * `ref_update::flags`.\n> + * or REF_HAVE_OLD, which are also stored in `ref_update::flags`.\n>   */\n>  \n>  /*\n"},{"id":"442577","messageId":"xmqqk0gq4keo.fsf@gitster.g","threadId":"56981","inReplyTo":"0a297f0c3e884c2d4cfb24a6d3b9f1973fc83125.1638211786.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T23:22:23Z","receivedAt":"2021-11-29T23:22:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Han-Wen Nienhuys <hanwen@google.com>\n>\n> Use this flag with the test-helper in t1430, to avoid direct writes to the ref\n> database.\n\nOK, this is similar to 3/6 where invalid object names are allowed.\nThis is about allowing invalid refnames.  Makes sense.\n\n\n\n> Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>\n> ---\n>  refs.c                  |  7 ++---\n>  refs.h                  | 10 +++++--\n>  t/t1430-bad-ref-name.sh | 59 ++++++++++++++++++++++-------------------\n>  3 files changed, 44 insertions(+), 32 deletions(-)\n>\n> diff --git a/refs.c b/refs.c\n> index d7cc0a23a3b..086b1341d2a 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -1078,9 +1078,10 @@ int ref_transaction_update(struct ref_transaction *transaction,\n>  {\n>  \tassert(err);\n>  \n> -\tif ((new_oid && !is_null_oid(new_oid)) ?\n> -\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n> -\t    !refname_is_safe(refname)) {\n> +\tif (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n> +\t    ((new_oid && !is_null_oid(new_oid)) ?\n> +\t\t     check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n> +\t\t\t   !refname_is_safe(refname))) {\n\nOK.  Initially my eyes went \"Huh?\", but it was just re-indentation\nthat fooled them.\n\n> @@ -617,12 +617,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n>   */\n>  #define REF_SKIP_OID_VERIFICATION (1 << 10)\n>  \n> +/*\n> + * Skip verifying refname. This is useful for testing data corruption scenarios.\n> + */\n> +#define REF_SKIP_REFNAME_VERIFICATION (1 << 11)\n\nOK.\n"},{"id":"442579","messageId":"xmqqfsre4k40.fsf@gitster.g","threadId":"56981","inReplyTo":"93fe3f03fb2a10f36aff4a6e4702053daeaa1d64.1638211786.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 3/6] refs: allow skipping OID verification","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T23:28:47Z","receivedAt":"2021-11-29T23:28:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +/*\n> + * Blindly write an object_id. This is useful for testing data corruption\n> + * scenarios.\n> + */\n> +#define REF_SKIP_OID_VERIFICATION (1 << 10)\n\nThat makes sense.  Readers would expect that this flag is passed\nonly from test-helper but not in the regular code, at least without\nan option like \"git update-ref --skip-oid-verification ...\"?\n\nAfter applying these 6 patches, I do not seem to find anybody who\nactually flips this bit on.  Perhaps I missed a step or so?\n\n"},{"id":"442580","messageId":"xmqqbl224k09.fsf@gitster.g","threadId":"56981","inReplyTo":"0a297f0c3e884c2d4cfb24a6d3b9f1973fc83125.1638211786.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T23:31:02Z","receivedAt":"2021-11-29T23:31:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +\tif (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n> +\t    ((new_oid && !is_null_oid(new_oid)) ?\n> +\t\t     check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n> +\t\t\t   !refname_is_safe(refname))) {\n\nSo, if somebody passes REF_SKIP_REFNAME_VERIFICATION in flags, we\nwill not do the check.\n\nAgain, like 3/6, this new bit is flipped on by test-helper\nsomewhere?  Again I do not see anybody doing so in these 6 patches,\nbut I should double check.\n"},{"id":"442623","messageId":"CAFQ2z_M35tbF6+C2MkMRm7hO8CNdUSrGTcx+8Os348+rHu4ojg@mail.gmail.com","threadId":"56981","inReplyTo":"xmqqbl224k09.fsf@gitster.g","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Han-Wen Nienhuys","fromEmail":"hanwen@google.com","sentAt":"2021-11-30T10:31:39Z","receivedAt":"2021-11-30T10:31:55Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"On Tue, Nov 30, 2021 at 12:31 AM Junio C Hamano <gitster@pobox.com> wrote:\n> > +     if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n> > +         ((new_oid && !is_null_oid(new_oid)) ?\n> > +                  check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n> > +                        !refname_is_safe(refname))) {\n>\n> So, if somebody passes REF_SKIP_REFNAME_VERIFICATION in flags, we\n> will not do the check.\n>\n> Again, like 3/6, this new bit is flipped on by test-helper\n> somewhere?  Again I do not see anybody doing so in these 6 patches,\n> but I should double check.\n\nThe test helper takes the flag as an argument, in decimal. If you look\nfor 2048, you should find it.\n\n-- \nHan-Wen Nienhuys - Google Munich\nI work 80%. Don't expect answers from me on Fridays.\n--\n\nGoogle Germany GmbH, Erika-Mann-Strasse 33, 80636 Munich\n\nRegistergericht und -nummer: Hamburg, HRB 86891\n\nSitz der Gesellschaft: Hamburg\n\nGeschäftsführer: Paul Manicle, Halimah DeLaine Prado\n"},{"id":"442787","messageId":"xmqqh7bs177v.fsf@gitster.g","threadId":"56981","inReplyTo":"CAFQ2z_M35tbF6+C2MkMRm7hO8CNdUSrGTcx+8Os348+rHu4ojg@mail.gmail.com","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-01T19:00:04Z","receivedAt":"2021-12-01T19:00:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Han-Wen Nienhuys <hanwen@google.com> writes:\n\n> On Tue, Nov 30, 2021 at 12:31 AM Junio C Hamano <gitster@pobox.com> wrote:\n>> > +     if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n>> > +         ((new_oid && !is_null_oid(new_oid)) ?\n>> > +                  check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n>> > +                        !refname_is_safe(refname))) {\n>>\n>> So, if somebody passes REF_SKIP_REFNAME_VERIFICATION in flags, we\n>> will not do the check.\n>>\n>> Again, like 3/6, this new bit is flipped on by test-helper\n>> somewhere?  Again I do not see anybody doing so in these 6 patches,\n>> but I should double check.\n>\n> The test helper takes the flag as an argument, in decimal. If you look\n> for 2048, you should find it.\n\nAwful---when the symbolic constants change in the code, the test\nwill silently break?\n\nIt has been this way since 80f2a609 (t/helper: add test-ref-store to\ntest ref-store functions, 2017-03-26), so it is nothing new, but at\nsome point, we should do a better job.  Even if it is used only as a\ntool for testing, we shouldn't have to force developers to write in\nassembly ;-)\n\nPerhaps when the dust settles after this series graduates to be a\npart of released version.  It may be a good bite-sized microproject\nmaterial for aspiring new developers.\n\n\n\n"},{"id":"442789","messageId":"YafMS6qI+6t6SOtg@coredump.intra.peff.net","threadId":"56981","inReplyTo":"xmqqh7bs177v.fsf@gitster.g","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-12-01T19:26:03Z","receivedAt":"2021-12-01T19:26:45Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Dec 01, 2021 at 11:00:04AM -0800, Junio C Hamano wrote:\n\n> > The test helper takes the flag as an argument, in decimal. If you look\n> > for 2048, you should find it.\n> \n> Awful---when the symbolic constants change in the code, the test\n> will silently break?\n\nAgreed, this is quite nasty.\n\n> It has been this way since 80f2a609 (t/helper: add test-ref-store to\n> test ref-store functions, 2017-03-26), so it is nothing new, but at\n> some point, we should do a better job.  Even if it is used only as a\n> tool for testing, we shouldn't have to force developers to write in\n> assembly ;-)\n\nSort of. The code to pass the flags was added then, but nobody was using\nit until now.\n\nAt least for ref updates. Symref creation allowed \"1\" for force, but\nthat is a true boolean. It looks like some pack-refs calls pass \"3\" for\nPACK_REFS_PRUNE|PACK_REFS_ALL.\n\nSo it may be considered a \"new\" issue in that sense.\n\n> Perhaps when the dust settles after this series graduates to be a\n> part of released version.  It may be a good bite-sized microproject\n> material for aspiring new developers.\n\nIt is annoying to have to plumb through the names of the flags, but in\npractice I don't think we need all (or even most) of them. And it's\nequally annoying not to be able to grep for the flags. I already had a\nhard enough time just grepping for the callers, and resorted to:\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 3986665037..1b7a124a86 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -271,6 +271,8 @@ int cmd__ref_store(int argc, const char **argv)\n \tconst char *func;\n \tstruct command *cmd;\n \n+\ttrace_argv_printf(argv, \"trace: test-tool:\");\n+\n \tsetup_git_directory();\n \n \targv = get_store(argv + 1, &refs);\n\nto find them.\n\n-Peff\n"},{"id":"442879","messageId":"CAFQ2z_NvHK17w3Rd958uwNziT2w5wXhiAJTSkCgBi32smgQuOg@mail.gmail.com","threadId":"56981","inReplyTo":"YafMS6qI+6t6SOtg@coredump.intra.peff.net","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Han-Wen Nienhuys","fromEmail":"hanwen@google.com","sentAt":"2021-12-02T16:40:41Z","receivedAt":"2021-12-02T16:40:55Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"On Wed, Dec 1, 2021 at 8:26 PM Jeff King <peff@peff.net> wrote:\n>\n> On Wed, Dec 01, 2021 at 11:00:04AM -0800, Junio C Hamano wrote:\n>\n> > > The test helper takes the flag as an argument, in decimal. If you look\n> > > for 2048, you should find it.\n> >\n> > Awful---when the symbolic constants change in the code, the test\n> > will silently break?\n>\n> Agreed, this is quite nasty.\n\nI've added parsing symbolic constants in v3.\n\n-- \nHan-Wen Nienhuys - Google Munich\nI work 80%. Don't expect answers from me on Fridays.\n--\n\nGoogle Germany GmbH, Erika-Mann-Strasse 33, 80636 Munich\n\nRegistergericht und -nummer: Hamburg, HRB 86891\n\nSitz der Gesellschaft: Hamburg\n\nGeschäftsführer: Paul Manicle, Halimah DeLaine Prado\n"},{"id":"442899","messageId":"3649ef6d0fa14ea1796264188466cdfc42d6d9e1.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 1/8] test-ref-store: remove force-create argument for create-reflog","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:39:55Z","receivedAt":"2021-12-02T18:40:09Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nNobody uses force_create=0, so this flag is unnecessary.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c      | 2 +-\n t/t1405-main-ref-store.sh      | 5 ++---\n t/t1406-submodule-ref-store.sh | 2 +-\n 3 files changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 3986665037a..b795a56eedf 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -182,9 +182,9 @@ static int cmd_reflog_exists(struct ref_store *refs, const char **argv)\n static int cmd_create_reflog(struct ref_store *refs, const char **argv)\n {\n \tconst char *refname = notnull(*argv++, \"refname\");\n-\tint force_create = arg_flags(*argv++, \"force-create\");\n \tstruct strbuf err = STRBUF_INIT;\n \tint ret;\n+\tint force_create = 1;\n \n \tret = refs_create_reflog(refs, refname, force_create, &err);\n \tif (err.len)\ndiff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh\nindex 49718b7ea7f..5e0f7073286 100755\n--- a/t/t1405-main-ref-store.sh\n+++ b/t/t1405-main-ref-store.sh\n@@ -35,8 +35,7 @@ test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '\n \tgit rev-parse FOO -- &&\n \tgit rev-parse refs/tags/new-tag -- &&\n \tm=$(git rev-parse main) &&\n-\tREF_NO_DEREF=1 &&\n-\t$RUN delete-refs $REF_NO_DEREF nothing FOO refs/tags/new-tag &&\n+\t$RUN delete-refs REF_NO_DEREF nothing FOO refs/tags/new-tag &&\n \ttest_must_fail git rev-parse --symbolic-full-name FOO &&\n \ttest_must_fail git rev-parse FOO -- &&\n \ttest_must_fail git rev-parse refs/tags/new-tag --\n@@ -108,7 +107,7 @@ test_expect_success 'delete_reflog(HEAD)' '\n '\n \n test_expect_success 'create-reflog(HEAD)' '\n-\t$RUN create-reflog HEAD 1 &&\n+\t$RUN create-reflog HEAD &&\n \tgit reflog exists HEAD\n '\n \ndiff --git a/t/t1406-submodule-ref-store.sh b/t/t1406-submodule-ref-store.sh\nindex 0a87058971e..f1e57a9c051 100755\n--- a/t/t1406-submodule-ref-store.sh\n+++ b/t/t1406-submodule-ref-store.sh\n@@ -92,7 +92,7 @@ test_expect_success 'delete_reflog() not allowed' '\n '\n \n test_expect_success 'create-reflog() not allowed' '\n-\ttest_must_fail $RUN create-reflog HEAD 1\n+\ttest_must_fail $RUN create-reflog HEAD\n '\n \n test_done\n-- \ngitgitgadget\n\n"},{"id":"442900","messageId":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v2.git.git.1638211786.gitgitgadget@gmail.com","subject":"[PATCH v3 0/8] Allow writing invalid OIDs into refs for testing purposes","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:39:54Z","receivedAt":"2021-12-02T18:40:11Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"this covers a few cases of direct filesystem access to the ref database in\ntests.\n\nv3:\n\n * parse symbolic constants in ref-store test-helper.\n\nHan-Wen Nienhuys (8):\n  test-ref-store: remove force-create argument for create-reflog\n  test-ref-store: parse symbolic flag constants\n  test-ref-store: plug memory leak in cmd_delete_refs\n  refs: update comment.\n  refs: introduce REF_SKIP_OID_VERIFICATION flag\n  refs: introduce REF_SKIP_REFNAME_VERIFICATION flag\n  t1430: remove refs using test-tool\n  t1430: create valid symrefs using test-helper\n\n refs.c                         |  7 +--\n refs.h                         | 16 +++++-\n refs/files-backend.c           | 53 ++++++++++---------\n t/helper/test-ref-store.c      | 78 ++++++++++++++++++++++++----\n t/t1006-cat-file.sh            |  5 +-\n t/t1405-main-ref-store.sh      |  8 ++-\n t/t1406-submodule-ref-store.sh |  2 +-\n t/t1430-bad-ref-name.sh        | 93 ++++++++++++++++++----------------\n t/t3800-mktag.sh               |  6 ++-\n 9 files changed, 175 insertions(+), 93 deletions(-)\n\n\nbase-commit: abe6bb3905392d5eb6b01fa6e54d7e784e0522aa\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1147%2Fhanwen%2Fskip-verification-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1147/hanwen/skip-verification-v3\nPull-Request: https://github.com/git/git/pull/1147\n\nRange-diff vs v2:\n\n -:  ----------- > 1:  3649ef6d0fa test-ref-store: remove force-create argument for create-reflog\n -:  ----------- > 2:  3cdebd2dbca test-ref-store: parse symbolic flag constants\n 1:  7fa5c247c8b ! 3:  536005d65a2 test-ref-store: plug memory leak in cmd_delete_refs\n     @@ Commit message\n      \n       ## t/helper/test-ref-store.c ##\n      @@ t/helper/test-ref-store.c: static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n     - \tunsigned int flags = arg_flags(*argv++, \"flags\");\n     + \tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n       \tconst char *msg = *argv++;\n       \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n     --\n      +\tint result;\n     + \n       \twhile (*argv)\n       \t\tstring_list_append(&refnames, *argv++);\n       \n 2:  82971ddbfcf = 4:  466b4451015 refs: update comment.\n 3:  93fe3f03fb2 ! 5:  89d692a34b8 refs: allow skipping OID verification\n     @@ Metadata\n      Author: Han-Wen Nienhuys <hanwen@google.com>\n      \n       ## Commit message ##\n     -    refs: allow skipping OID verification\n     +    refs: introduce REF_SKIP_OID_VERIFICATION flag\n      \n     -    This introduces the REF_SKIP_OID_VERIFICATION flag, which lets the ref-store\n     -    test helper write non-existent or unparsable objects into the ref storage.\n     +    This lets the ref-store test helper write non-existent or unparsable objects\n     +    into the ref storage.\n      \n          Use this to make t1006 and t3800 independent of the files storage backend.\n      \n     @@ refs/files-backend.c: static int lock_ref_for_update(struct files_ref_store *ref\n       \n       \t\t\t/*\n      \n     + ## t/helper/test-ref-store.c ##\n     +@@ t/helper/test-ref-store.c: static int cmd_create_symref(struct ref_store *refs, const char **argv)\n     + static struct flag_definition transaction_flags[] = {\n     + \tFLAG_DEF(REF_NO_DEREF),\n     + \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n     ++\tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n     + \t{ NULL, 0 },\n     + };\n     + \n     +\n       ## t/t1006-cat-file.sh ##\n      @@ t/t1006-cat-file.sh: test_expect_success 'the --allow-unknown-type option does not consider replaceme\n       \t# Create it manually, as \"git replace\" will die on bogus\n     @@ t/t1006-cat-file.sh: test_expect_success 'the --allow-unknown-type option does n\n      -\tmkdir -p .git/refs/replace &&\n      -\techo $head >.git/refs/replace/$bogus_short_sha1 &&\n      +\ttest_when_finished \"test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID 1024 &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n       \n       \tcat >expect <<-EOF &&\n       \tcommit\n     @@ t/t3800-mktag.sh: check_verify_failure () {\n       \t\t# update-ref\n      -\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n      +\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n     -+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID 1024 &&\n     ++\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n       \n       \t\t# Unlike fsck-ing unreachable content above, this\n       \t\t# will always fail.\n     @@ t/t3800-mktag.sh: check_verify_failure () {\n       \n      -\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n      +\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n     -+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID 1024 &&\n     ++\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n       \n       \t\tprintf \"%s tag\\t%s\\n\" \"$bad_tag\" \"$tag_ref\" >expected &&\n       \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n 4:  0a297f0c3e8 ! 6:  af9e94935bf refs: add REF_SKIP_REFNAME_VERIFICATION flag\n     @@ Metadata\n      Author: Han-Wen Nienhuys <hanwen@google.com>\n      \n       ## Commit message ##\n     -    refs: add REF_SKIP_REFNAME_VERIFICATION flag\n     +    refs: introduce REF_SKIP_REFNAME_VERIFICATION flag\n      \n          Use this flag with the test-helper in t1430, to avoid direct writes to the ref\n          database.\n     @@ refs.h: struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n       /*\n        * Add a reference update to transaction. `new_oid` is the value that\n      \n     + ## t/helper/test-ref-store.c ##\n     +@@ t/helper/test-ref-store.c: static struct flag_definition transaction_flags[] = {\n     + \tFLAG_DEF(REF_NO_DEREF),\n     + \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n     + \tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n     ++\tFLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),\n     + \t{ NULL, 0 },\n     + };\n     + \n     +\n       ## t/t1430-bad-ref-name.sh ##\n      @@ t/t1430-bad-ref-name.sh: TEST_PASSES_SANITIZE_LEAK=true\n       \n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'fast-import: fail on invalid branc\n       test_expect_success 'git branch shows badly named ref as warning' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch >output 2>error &&\n       \ttest_i18ngrep -e \"ignoring ref with broken name refs/heads/broken\\.\\.\\.ref\" error &&\n       \t! grep -e \"broken\\.\\.\\.ref\" output\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'fast-import: fail on invalid branc\n       test_expect_success 'branch -d can delete badly named ref' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch -d broken...ref &&\n       \tgit branch >output 2>error &&\n       \t! grep -e \"broken\\.\\.\\.ref\" error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete badly named r\n       test_expect_success 'branch -D can delete badly named ref' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch -D broken...ref &&\n       \tgit branch >output 2>error &&\n       \t! grep -e \"broken\\.\\.\\.ref\" error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -D cannot delete absolute p\n       \n       test_expect_success 'git branch cannot create a badly named ref' '\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \ttest_must_fail git branch broken...ref &&\n       \tgit branch >output 2>error &&\n       \t! grep -e \"broken\\.\\.\\.ref\" error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'git branch cannot create a badly n\n       \n       test_expect_success 'branch -m cannot rename to a bad ref name' '\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \ttest_might_fail git branch -D goodref &&\n       \tgit branch goodref &&\n       \ttest_must_fail git branch -m goodref broken...ref &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -m cannot rename to a bad r\n       test_expect_failure 'branch -m can rename from a bad ref name' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n      +\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch -m broken...ref renamed &&\n       \ttest_cmp_rev main renamed &&\n       \tgit branch >output 2>error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_failure 'branch -m can rename from a bad re\n       \n       test_expect_success 'push cannot create a badly named ref' '\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \ttest_must_fail git push \"file://$(pwd)\" HEAD:refs/heads/broken...ref &&\n       \tgit branch >output 2>error &&\n       \t! grep -e \"broken\\.\\.\\.ref\" error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_failure 'push --mirror can delete badly nam\n       \t\ttest_commit two &&\n       \t\tgit checkout --detach &&\n      -\t\tcp .git/refs/heads/main .git/refs/heads/broken...ref\n     -+\t\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048\n     ++\t\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION\n       \t) &&\n       \tgit -C src push --mirror \"file://$top/dest\" &&\n       \tgit -C dest branch >output 2>error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_failure 'push --mirror can delete badly nam\n       \n       test_expect_success 'rev-parse skips symref pointing to broken name' '\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch shadow one &&\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n       \ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n       \tgit rev-parse --verify one >expect &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'rev-parse skips symref pointing to\n       test_expect_success 'for-each-ref emits warnings for broken names' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n       \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n       \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'for-each-ref emits warnings for br\n       test_expect_success 'update-ref -d can delete broken name' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit update-ref -d refs/heads/broken...ref >output 2>error &&\n       \ttest_must_be_empty output &&\n       \ttest_must_be_empty error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref -d can delete broken na\n       test_expect_success 'branch -d can delete broken name' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch -d broken...ref >output 2>error &&\n       \ttest_i18ngrep \"Deleted branch broken...ref (was broken)\" output &&\n       \ttest_must_be_empty error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete broken name'\n       test_expect_success 'update-ref --no-deref -d can delete symref to broken name' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n      +\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n       \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n       \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delet\n       test_expect_success 'branch -d can delete symref to broken name' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n      +\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n       \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n       \tgit branch -d badname >output 2>error &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete dangling symr\n       test_expect_success 'update-ref -d can delete broken name through symref' '\n      -\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n     -+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     ++\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n      +\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n       \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n       \tgit update-ref -d refs/heads/badname >output 2>error &&\n 5:  06c8ff7df15 ! 7:  d4f1d209468 t1430: remove refs using test-tool\n     @@ Commit message\n       ## t/t1430-bad-ref-name.sh ##\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'rev-parse skips symref pointing to broken name' '\n       \tgit branch shadow one &&\n     - \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     + \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n      -\ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/tags/shadow\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/tags/shadow\" &&\n       \tgit rev-parse --verify one >expect &&\n       \tgit rev-parse --verify shadow >actual 2>err &&\n       \ttest_cmp expect actual &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'for-each-ref emits warnings for broken names' '\n     - \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n       \tgit for-each-ref >output 2>error &&\n       \t! grep -e \"broken\\.\\.\\.ref\" output &&\n       \t! grep -e \"badname\" output &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n       \n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n       \ttest_must_be_empty output &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete symref to broken name' '\n       \n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit branch -d badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n       \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete symref to bro\n       test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n       \ttest_must_be_empty output &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delet\n       test_expect_success 'branch -d can delete dangling symref to broken name' '\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit branch -d badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n       \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref -d can delete broken name through symref' '\n       \n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit update-ref -d refs/heads/badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/broken...ref &&\n       \ttest_must_be_empty output &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref -d can delete broken na\n       test_expect_success 'update-ref --no-deref -d can delete symref with broken name' '\n       \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n       \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/broken...symref &&\n       \ttest_must_be_empty output &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delet\n       test_expect_success 'branch -d can delete symref with broken name' '\n       \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n       \tgit branch -d broken...symref >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/broken...symref &&\n       \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/main)\" output &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete symref with b\n       test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' '\n       \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n       \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/broken...symref &&\n       \ttest_must_be_empty output &&\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delet\n       test_expect_success 'branch -d can delete dangling symref with broken name' '\n       \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n      -\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n     -+\ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...symref\" &&\n     ++\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n       \tgit branch -d broken...symref >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/broken...symref &&\n       \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/idonotexist)\" output &&\n 6:  3c100702fda ! 8:  ca7f8aea3d9 t1430: create valid symrefs using test-helper\n     @@ Commit message\n      \n       ## t/t1430-bad-ref-name.sh ##\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'rev-parse skips symref pointing to broken name' '\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n       \tgit branch shadow one &&\n     - \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     + \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n      -\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n      +\ttest-tool ref-store main create-symref refs/tags/shadow refs/heads/broken...ref msg &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/tags/shadow\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/tags/shadow\" &&\n       \tgit rev-parse --verify one >expect &&\n       \tgit rev-parse --verify shadow >actual 2>err &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n     - \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     + \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n       \n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n      -\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      +\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n     -@@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete symref to broken name' '\n     - \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     +@@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n       \n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + test_expect_success 'branch -d can delete symref to broken name' '\n     + \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     +-\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n      -\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      +\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit branch -d badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete symref to broken name' '\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete symref to bro\n       test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n      -\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      +\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n      @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n     @@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref --no-deref -d can delet\n       test_expect_success 'branch -d can delete dangling symref to broken name' '\n      -\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      +\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit branch -d badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/badname &&\n     -@@ t/t1430-bad-ref-name.sh: test_expect_success 'update-ref -d can delete broken name through symref' '\n     - \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID 2048 &&\n     +@@ t/t1430-bad-ref-name.sh: test_expect_success 'branch -d can delete dangling symref to broken name' '\n       \n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/broken...ref\" &&\n     + test_expect_success 'update-ref -d can delete broken name through symref' '\n     + \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n     +-\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n      -\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n      +\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n     - \ttest_when_finished \"test-tool ref-store main delete-refs 1 msg refs/heads/badname\" &&\n     + \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n       \tgit update-ref -d refs/heads/badname >output 2>error &&\n       \ttest_path_is_missing .git/refs/heads/broken...ref &&\n\n-- \ngitgitgadget\n"},{"id":"442903","messageId":"3cdebd2dbcad2f6d428d88846569d6563249dad8.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 2/8] test-ref-store: parse symbolic flag constants","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:39:56Z","receivedAt":"2021-12-02T18:40:12Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis lets tests use REF_XXXX constants instead of hardcoded integers. The flag\nnames should be separated by a ','.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c | 69 +++++++++++++++++++++++++++++++++++----\n t/t1405-main-ref-store.sh |  3 +-\n 2 files changed, 63 insertions(+), 9 deletions(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex b795a56eedf..cbf1b5f506d 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -5,6 +5,50 @@\n #include \"object-store.h\"\n #include \"repository.h\"\n \n+struct flag_definition {\n+\tconst char *name;\n+\tuint64_t mask;\n+};\n+\n+#define FLAG_DEF(x)     \\\n+\t{               \\\n+#x, (x) \\\n+\t}\n+\n+static unsigned int parse_flags(const char *str, struct flag_definition *defs)\n+{\n+\tstruct string_list masks = STRING_LIST_INIT_DUP;\n+\tint i = 0;\n+\tunsigned int result = 0;\n+\n+\tif (!strcmp(str, \"0\"))\n+\t\treturn 0;\n+\n+\tstring_list_split(&masks, str, ',', 64);\n+\tfor (; i < masks.nr; i++) {\n+\t\tconst char *name = masks.items[i].string;\n+\t\tstruct flag_definition *def = defs;\n+\t\tint found = 0;\n+\t\twhile (def->name) {\n+\t\t\tif (!strcmp(def->name, name)) {\n+\t\t\t\tresult |= def->mask;\n+\t\t\t\tfound = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tdef++;\n+\t\t}\n+\t\tif (!found)\n+\t\t\tdie(\"unknown flag \\\"%s\\\"\", name);\n+\t}\n+\n+\tstring_list_clear(&masks, 0);\n+\treturn result;\n+}\n+\n+static struct flag_definition empty_flags[] = {\n+\t{ NULL, 0 },\n+};\n+\n static const char *notnull(const char *arg, const char *name)\n {\n \tif (!arg)\n@@ -12,9 +56,10 @@ static const char *notnull(const char *arg, const char *name)\n \treturn arg;\n }\n \n-static unsigned int arg_flags(const char *arg, const char *name)\n+static unsigned int arg_flags(const char *arg, const char *name,\n+\t\t\t      struct flag_definition *defs)\n {\n-\treturn atoi(notnull(arg, name));\n+\treturn parse_flags(notnull(arg, name), defs);\n }\n \n static const char **get_store(const char **argv, struct ref_store **refs)\n@@ -64,10 +109,14 @@ static const char **get_store(const char **argv, struct ref_store **refs)\n \treturn argv + 1;\n }\n \n+static struct flag_definition pack_flags[] = {\n+\tFLAG_DEF(PACK_REFS_PRUNE),\n+\tFLAG_DEF(PACK_REFS_ALL),\n+};\n \n static int cmd_pack_refs(struct ref_store *refs, const char **argv)\n {\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", pack_flags);\n \n \treturn refs_pack_refs(refs, flags);\n }\n@@ -81,9 +130,15 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv)\n \treturn refs_create_symref(refs, refname, target, logmsg);\n }\n \n+static struct flag_definition transaction_flags[] = {\n+\tFLAG_DEF(REF_NO_DEREF),\n+\tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n+\t{ NULL, 0 },\n+};\n+\n static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n {\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tconst char *msg = *argv++;\n \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n \n@@ -120,7 +175,7 @@ static int cmd_resolve_ref(struct ref_store *refs, const char **argv)\n {\n \tstruct object_id oid = *null_oid();\n \tconst char *refname = notnull(*argv++, \"refname\");\n-\tint resolve_flags = arg_flags(*argv++, \"resolve-flags\");\n+\tint resolve_flags = arg_flags(*argv++, \"resolve-flags\", empty_flags);\n \tint flags;\n \tconst char *ref;\n \tint ignore_errno;\n@@ -209,7 +264,7 @@ static int cmd_delete_ref(struct ref_store *refs, const char **argv)\n \tconst char *msg = notnull(*argv++, \"msg\");\n \tconst char *refname = notnull(*argv++, \"refname\");\n \tconst char *sha1_buf = notnull(*argv++, \"old-sha1\");\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tstruct object_id old_oid;\n \n \tif (get_oid_hex(sha1_buf, &old_oid))\n@@ -224,7 +279,7 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv)\n \tconst char *refname = notnull(*argv++, \"refname\");\n \tconst char *new_sha1_buf = notnull(*argv++, \"new-sha1\");\n \tconst char *old_sha1_buf = notnull(*argv++, \"old-sha1\");\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tstruct object_id old_oid;\n \tstruct object_id new_oid;\n \ndiff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh\nindex 5e0f7073286..63e0ae82bdf 100755\n--- a/t/t1405-main-ref-store.sh\n+++ b/t/t1405-main-ref-store.sh\n@@ -17,8 +17,7 @@ test_expect_success 'setup' '\n test_expect_success REFFILES 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' '\n \tN=`find .git/refs -type f | wc -l` &&\n \ttest \"$N\" != 0 &&\n-\tALL_OR_PRUNE_FLAG=3 &&\n-\t$RUN pack-refs ${ALL_OR_PRUNE_FLAG} &&\n+\t$RUN pack-refs PACK_REFS_PRUNE,PACK_REFS_ALL &&\n \tN=`find .git/refs -type f` &&\n \ttest -z \"$N\"\n '\n-- \ngitgitgadget\n\n"},{"id":"442901","messageId":"536005d65a26e8471bb0c5b9109a59319c636eb1.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 3/8] test-ref-store: plug memory leak in cmd_delete_refs","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:39:57Z","receivedAt":"2021-12-02T18:40:13Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex cbf1b5f506d..c8ae36e2172 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -141,11 +141,14 @@ static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n \tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tconst char *msg = *argv++;\n \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n+\tint result;\n \n \twhile (*argv)\n \t\tstring_list_append(&refnames, *argv++);\n \n-\treturn refs_delete_refs(refs, msg, &refnames, flags);\n+\tresult = refs_delete_refs(refs, msg, &refnames, flags);\n+\tstring_list_clear(&refnames, 0);\n+\treturn result;\n }\n \n static int cmd_rename_ref(struct ref_store *refs, const char **argv)\n-- \ngitgitgadget\n\n"},{"id":"442902","messageId":"466b4451015dfe4b2631f378dbf9631c04240f53.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 4/8] refs: update comment.","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:39:58Z","receivedAt":"2021-12-02T18:40:16Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nREF_IS_PRUNING is right below this comment, so it clearly does not belong in\nthis comment. This was apparently introduced in commit 5ac95fee (Nov 5, 2017\n\"refs: tidy up and adjust visibility of the `ref_update` flags\").\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs/files-backend.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4b14f30d48f..37329b98cca 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -16,8 +16,7 @@\n  * This backend uses the following flags in `ref_update::flags` for\n  * internal bookkeeping purposes. Their numerical values must not\n  * conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,\n- * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in\n- * `ref_update::flags`.\n+ * or REF_HAVE_OLD, which are also stored in `ref_update::flags`.\n  */\n \n /*\n-- \ngitgitgadget\n\n"},{"id":"442904","messageId":"89d692a34b8023c536deaa1e50bc41ceb511d0b3.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 5/8] refs: introduce REF_SKIP_OID_VERIFICATION flag","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:39:59Z","receivedAt":"2021-12-02T18:40:18Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis lets the ref-store test helper write non-existent or unparsable objects\ninto the ref storage.\n\nUse this to make t1006 and t3800 independent of the files storage backend.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.h                    |  8 ++++++-\n refs/files-backend.c      | 50 +++++++++++++++++++++++----------------\n t/helper/test-ref-store.c |  1 +\n t/t1006-cat-file.sh       |  5 ++--\n t/t3800-mktag.sh          |  6 +++--\n 5 files changed, 43 insertions(+), 27 deletions(-)\n\ndiff --git a/refs.h b/refs.h\nindex 45c34e99e3a..76efc589cca 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -615,12 +615,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_FORCE_CREATE_REFLOG (1 << 1)\n \n+/*\n+ * Blindly write an object_id. This is useful for testing data corruption\n+ * scenarios.\n+ */\n+#define REF_SKIP_OID_VERIFICATION (1 << 10)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n #define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG)\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 37329b98cca..d0019fcd8b7 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1353,7 +1353,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)\n }\n \n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err);\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err);\n static int commit_ref_update(struct files_ref_store *refs,\n \t\t\t     struct ref_lock *lock,\n \t\t\t     const struct object_id *oid, const char *logmsg,\n@@ -1500,7 +1501,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \t}\n \toidcpy(&lock->old_oid, &orig_oid);\n \n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1520,7 +1521,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = LOG_REFS_NONE;\n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1756,26 +1757,31 @@ static int files_log_ref_write(struct files_ref_store *refs,\n  * errors, rollback the lockfile, fill in *err and return -1.\n  */\n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err)\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err)\n {\n \tstatic char term = '\\n';\n \tstruct object *o;\n \tint fd;\n \n-\to = parse_object(the_repository, oid);\n-\tif (!o) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write ref '%s' with nonexistent object %s\",\n-\t\t\t    lock->ref_name, oid_to_hex(oid));\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n-\t}\n-\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write non-commit object %s to branch '%s'\",\n-\t\t\t    oid_to_hex(oid), lock->ref_name);\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n+\tif (!skip_oid_verification) {\n+\t\to = parse_object(the_repository, oid);\n+\t\tif (!o) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write ref '%s' with nonexistent object %s\",\n+\t\t\t\tlock->ref_name, oid_to_hex(oid));\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write non-commit object %s to branch '%s'\",\n+\t\t\t\toid_to_hex(oid), lock->ref_name);\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n \t}\n \tfd = get_lock_file_fd(&lock->lk);\n \tif (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||\n@@ -2189,7 +2195,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n }\n \n static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,\n-\t\t\t\t   struct object_id *peeled)\n+\t\t\t\t      struct object_id *peeled)\n {\n \tBUG(\"ref_iterator_peel() called for reflog_iterator\");\n }\n@@ -2575,8 +2581,10 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * The reference already has the desired\n \t\t\t * value, so we don't need to write it.\n \t\t\t */\n-\t\t} else if (write_ref_to_lockfile(lock, &update->new_oid,\n-\t\t\t\t\t\t err)) {\n+\t\t} else if (write_ref_to_lockfile(\n+\t\t\t\t   lock, &update->new_oid,\n+\t\t\t\t   update->flags & REF_SKIP_OID_VERIFICATION,\n+\t\t\t\t   err)) {\n \t\t\tchar *write_err = strbuf_detach(err, NULL);\n \n \t\t\t/*\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex c8ae36e2172..ac8fa2fe730 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -133,6 +133,7 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv)\n static struct flag_definition transaction_flags[] = {\n \tFLAG_DEF(REF_NO_DEREF),\n \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n+\tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n \t{ NULL, 0 },\n };\n \ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 658628375c8..0d4c55f74ec 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -452,9 +452,8 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme\n \t# Create it manually, as \"git replace\" will die on bogus\n \t# types.\n \thead=$(git rev-parse --verify HEAD) &&\n-\ttest_when_finished \"rm -rf .git/refs/replace\" &&\n-\tmkdir -p .git/refs/replace &&\n-\techo $head >.git/refs/replace/$bogus_short_sha1 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n \n \tcat >expect <<-EOF &&\n \tcommit\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 0544d58a6ea..e3cf0ffbe59 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -72,7 +72,8 @@ check_verify_failure () {\n \n \t\t# Manually create the broken, we cannot do it with\n \t\t# update-ref\n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n \n \t\t# Unlike fsck-ing unreachable content above, this\n \t\t# will always fail.\n@@ -83,7 +84,8 @@ check_verify_failure () {\n \t\t# Make sure the earlier test created it for us\n \t\tgit rev-parse \"$bad_tag\" &&\n \n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n \n \t\tprintf \"%s tag\\t%s\\n\" \"$bad_tag\" \"$tag_ref\" >expected &&\n \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n-- \ngitgitgadget\n\n"},{"id":"442905","messageId":"af9e94935bf6995c1d33cfe5fff1d897bb4119f5.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 6/8] refs: introduce REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:40:00Z","receivedAt":"2021-12-02T18:40:19Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nUse this flag with the test-helper in t1430, to avoid direct writes to the ref\ndatabase.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.c                    |  7 +++--\n refs.h                    | 10 +++++--\n t/helper/test-ref-store.c |  1 +\n t/t1430-bad-ref-name.sh   | 59 +++++++++++++++++++++------------------\n 4 files changed, 45 insertions(+), 32 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 996ac271641..93bfe5b30cf 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1083,9 +1083,10 @@ int ref_transaction_update(struct ref_transaction *transaction,\n {\n \tassert(err);\n \n-\tif ((new_oid && !is_null_oid(new_oid)) ?\n-\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n-\t    !refname_is_safe(refname)) {\n+\tif (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n+\t    ((new_oid && !is_null_oid(new_oid)) ?\n+\t\t     check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n+\t\t\t   !refname_is_safe(refname))) {\n \t\tstrbuf_addf(err, _(\"refusing to update ref with bad name '%s'\"),\n \t\t\t    refname);\n \t\treturn -1;\ndiff --git a/refs.h b/refs.h\nindex 76efc589cca..65017ceaefc 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -621,12 +621,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_SKIP_OID_VERIFICATION (1 << 10)\n \n+/*\n+ * Skip verifying refname. This is useful for testing data corruption scenarios.\n+ */\n+#define REF_SKIP_REFNAME_VERIFICATION (1 << 11)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n-#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n+#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS                                  \\\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \\\n+\t REF_SKIP_REFNAME_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex ac8fa2fe730..78270b3c880 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -134,6 +134,7 @@ static struct flag_definition transaction_flags[] = {\n \tFLAG_DEF(REF_NO_DEREF),\n \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n \tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n+\tFLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),\n \t{ NULL, 0 },\n };\n \ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 4c77cf89a6c..326e5bd5e80 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -9,7 +9,8 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n test_expect_success setup '\n \ttest_commit one &&\n-\ttest_commit two\n+\ttest_commit two &&\n+\tmain_sha1=$(git rev-parse refs/heads/main)\n '\n \n test_expect_success 'fast-import: fail on invalid branch name \".badbranchname\"' '\n@@ -43,16 +44,16 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n '\n \n test_expect_success 'git branch shows badly named ref as warning' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch >output 2>error &&\n \ttest_i18ngrep -e \"ignoring ref with broken name refs/heads/broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete badly named ref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -d broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -60,8 +61,8 @@ test_expect_success 'branch -d can delete badly named ref' '\n '\n \n test_expect_success 'branch -D can delete badly named ref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -D broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -90,7 +91,7 @@ test_expect_success 'branch -D cannot delete absolute path' '\n '\n \n test_expect_success 'git branch cannot create a badly named ref' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \ttest_must_fail git branch broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -98,7 +99,7 @@ test_expect_success 'git branch cannot create a badly named ref' '\n '\n \n test_expect_success 'branch -m cannot rename to a bad ref name' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \ttest_might_fail git branch -D goodref &&\n \tgit branch goodref &&\n \ttest_must_fail git branch -m goodref broken...ref &&\n@@ -109,8 +110,9 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n '\n \n test_expect_failure 'branch -m can rename from a bad ref name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -m broken...ref renamed &&\n \ttest_cmp_rev main renamed &&\n \tgit branch >output 2>error &&\n@@ -119,7 +121,7 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n '\n \n test_expect_success 'push cannot create a badly named ref' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \ttest_must_fail git push \"file://$(pwd)\" HEAD:refs/heads/broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -139,7 +141,7 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n \t\tcd dest &&\n \t\ttest_commit two &&\n \t\tgit checkout --detach &&\n-\t\tcp .git/refs/heads/main .git/refs/heads/broken...ref\n+\t\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION\n \t) &&\n \tgit -C src push --mirror \"file://$top/dest\" &&\n \tgit -C dest branch >output 2>error &&\n@@ -148,9 +150,9 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n '\n \n test_expect_success 'rev-parse skips symref pointing to broken name' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch shadow one &&\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n \ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n@@ -160,8 +162,8 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n '\n \n test_expect_success 'for-each-ref emits warnings for broken names' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n@@ -176,8 +178,8 @@ test_expect_success 'for-each-ref emits warnings for broken names' '\n '\n \n test_expect_success 'update-ref -d can delete broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit update-ref -d refs/heads/broken...ref >output 2>error &&\n \ttest_must_be_empty output &&\n \ttest_must_be_empty error &&\n@@ -187,8 +189,8 @@ test_expect_success 'update-ref -d can delete broken name' '\n '\n \n test_expect_success 'branch -d can delete broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -d broken...ref >output 2>error &&\n \ttest_i18ngrep \"Deleted branch broken...ref (was broken)\" output &&\n \ttest_must_be_empty error &&\n@@ -198,8 +200,9 @@ test_expect_success 'branch -d can delete broken name' '\n '\n \n test_expect_success 'update-ref --no-deref -d can delete symref to broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n@@ -209,8 +212,9 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n '\n \n test_expect_success 'branch -d can delete symref to broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n@@ -238,8 +242,9 @@ test_expect_success 'branch -d can delete dangling symref to broken name' '\n '\n \n test_expect_success 'update-ref -d can delete broken name through symref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n-- \ngitgitgadget\n\n"},{"id":"442906","messageId":"d4f1d209468405a250c83ebc4fa9b50ad0bf9260.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 7/8] t1430: remove refs using test-tool","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:40:01Z","receivedAt":"2021-12-02T18:40:25Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/t1430-bad-ref-name.sh | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 326e5bd5e80..84e912777c5 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -154,7 +154,7 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n \tgit branch shadow one &&\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n-\ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n \tgit rev-parse --verify shadow >actual 2>err &&\n \ttest_cmp expect actual &&\n@@ -165,9 +165,9 @@ test_expect_success 'for-each-ref emits warnings for broken names' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit for-each-ref >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output &&\n \t! grep -e \"badname\" output &&\n@@ -204,7 +204,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_must_be_empty output &&\n@@ -216,7 +216,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n@@ -225,7 +225,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_must_be_empty output &&\n@@ -234,7 +234,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n \n test_expect_success 'branch -d can delete dangling symref to broken name' '\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n@@ -246,7 +246,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...ref &&\n \ttest_must_be_empty output &&\n@@ -255,7 +255,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \n test_expect_success 'update-ref --no-deref -d can delete symref with broken name' '\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_must_be_empty output &&\n@@ -264,7 +264,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref with broken name\n \n test_expect_success 'branch -d can delete symref with broken name' '\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit branch -d broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/main)\" output &&\n@@ -273,7 +273,7 @@ test_expect_success 'branch -d can delete symref with broken name' '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' '\n \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_must_be_empty output &&\n@@ -282,7 +282,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref with br\n \n test_expect_success 'branch -d can delete dangling symref with broken name' '\n \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit branch -d broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/idonotexist)\" output &&\n-- \ngitgitgadget\n\n"},{"id":"442907","messageId":"ca7f8aea3d9423bb3e572618920e4ca3b3f26492.1638470403.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v3 8/8] t1430: create valid symrefs using test-helper","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-02T18:40:02Z","receivedAt":"2021-12-02T18:40:27Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis still leaves some other direct filesystem access. Currently, the files\nbackend does not allow invalidly named symrefs. Fixes for this are currently in\nthe 'seen' branch\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/t1430-bad-ref-name.sh | 14 ++++++--------\n 1 file changed, 6 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 84e912777c5..ff1c967d550 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -153,7 +153,7 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch shadow one &&\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n+\ttest-tool ref-store main create-symref refs/tags/shadow refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n \tgit rev-parse --verify shadow >actual 2>err &&\n@@ -203,7 +203,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -213,9 +213,8 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \n test_expect_success 'branch -d can delete symref to broken name' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n-\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -224,7 +223,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -233,7 +232,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n '\n \n test_expect_success 'branch -d can delete dangling symref to broken name' '\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -243,9 +242,8 @@ test_expect_success 'branch -d can delete dangling symref to broken name' '\n \n test_expect_success 'update-ref -d can delete broken name through symref' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n-\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...ref &&\n-- \ngitgitgadget\n"},{"id":"442910","messageId":"xmqqtufqu8sg.fsf@gitster.g","threadId":"56981","inReplyTo":"CAFQ2z_NvHK17w3Rd958uwNziT2w5wXhiAJTSkCgBi32smgQuOg@mail.gmail.com","subject":"Re: [PATCH v2 4/6] refs: add REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-02T19:05:35Z","receivedAt":"2021-12-02T19:05:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Han-Wen Nienhuys <hanwen@google.com> writes:\n\n> On Wed, Dec 1, 2021 at 8:26 PM Jeff King <peff@peff.net> wrote:\n>>\n>> On Wed, Dec 01, 2021 at 11:00:04AM -0800, Junio C Hamano wrote:\n>>\n>> > > The test helper takes the flag as an argument, in decimal. If you look\n>> > > for 2048, you should find it.\n>> >\n>> > Awful---when the symbolic constants change in the code, the test\n>> > will silently break?\n>>\n>> Agreed, this is quite nasty.\n>\n> I've added parsing symbolic constants in v3.\n\nThanks for going an extra mile.\n"},{"id":"442935","messageId":"Yam3iHj1a48X+psK@coredump.intra.peff.net","threadId":"56981","inReplyTo":"3cdebd2dbcad2f6d428d88846569d6563249dad8.1638470403.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 2/8] test-ref-store: parse symbolic flag constants","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-12-03T06:22:00Z","receivedAt":"2021-12-03T06:22:02Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Dec 02, 2021 at 06:39:56PM +0000, Han-Wen Nienhuys via GitGitGadget wrote:\n\n> From: Han-Wen Nienhuys <hanwen@google.com>\n> \n> This lets tests use REF_XXXX constants instead of hardcoded integers. The flag\n> names should be separated by a ','.\n\nSo much nicer. Thank you for cleaning this up.\n\nOne small bug:\n\n> +static unsigned int parse_flags(const char *str, struct flag_definition *defs)\n> +{\n> +\tstruct string_list masks = STRING_LIST_INIT_DUP;\n> +\tint i = 0;\n> +\tunsigned int result = 0;\n> +\n> +\tif (!strcmp(str, \"0\"))\n> +\t\treturn 0;\n> +\n> +\tstring_list_split(&masks, str, ',', 64);\n> +\tfor (; i < masks.nr; i++) {\n> +\t\tconst char *name = masks.items[i].string;\n> +\t\tstruct flag_definition *def = defs;\n> +\t\tint found = 0;\n> +\t\twhile (def->name) {\n> +\t\t\tif (!strcmp(def->name, name)) {\n> +\t\t\t\tresult |= def->mask;\n> +\t\t\t\tfound = 1;\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\tdef++;\n> +\t\t}\n\nWe assume defs ends with a NULL entry here...\n\n> +static struct flag_definition empty_flags[] = {\n> +\t{ NULL, 0 },\n> +};\n\n...and this one does so...\n\n> +static struct flag_definition pack_flags[] = {\n> +\tFLAG_DEF(PACK_REFS_PRUNE),\n> +\tFLAG_DEF(PACK_REFS_ALL),\n> +};\n\n...but this one does not. So passing an unknown flag will result in us\nwalking off the end of the list.\n\n> +static struct flag_definition transaction_flags[] = {\n> +\tFLAG_DEF(REF_NO_DEREF),\n> +\tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n> +\t{ NULL, 0 },\n> +};\n\nThis one is good. We might want to drop the trailing comma on the NULL\nentries, to make it more clear that they have to come last.\n\nThe other option would be using ARRAY_SIZE() instead of a NULL\nterminator, but of course that has to happen in the caller. Which means\neither extra work there, or yet another macro. :)\n\n-Peff\n"},{"id":"443275","messageId":"3649ef6d0fa14ea1796264188466cdfc42d6d9e1.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 1/8] test-ref-store: remove force-create argument for create-reflog","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:13Z","receivedAt":"2021-12-07T13:38:27Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nNobody uses force_create=0, so this flag is unnecessary.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c      | 2 +-\n t/t1405-main-ref-store.sh      | 5 ++---\n t/t1406-submodule-ref-store.sh | 2 +-\n 3 files changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 3986665037a..b795a56eedf 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -182,9 +182,9 @@ static int cmd_reflog_exists(struct ref_store *refs, const char **argv)\n static int cmd_create_reflog(struct ref_store *refs, const char **argv)\n {\n \tconst char *refname = notnull(*argv++, \"refname\");\n-\tint force_create = arg_flags(*argv++, \"force-create\");\n \tstruct strbuf err = STRBUF_INIT;\n \tint ret;\n+\tint force_create = 1;\n \n \tret = refs_create_reflog(refs, refname, force_create, &err);\n \tif (err.len)\ndiff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh\nindex 49718b7ea7f..5e0f7073286 100755\n--- a/t/t1405-main-ref-store.sh\n+++ b/t/t1405-main-ref-store.sh\n@@ -35,8 +35,7 @@ test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '\n \tgit rev-parse FOO -- &&\n \tgit rev-parse refs/tags/new-tag -- &&\n \tm=$(git rev-parse main) &&\n-\tREF_NO_DEREF=1 &&\n-\t$RUN delete-refs $REF_NO_DEREF nothing FOO refs/tags/new-tag &&\n+\t$RUN delete-refs REF_NO_DEREF nothing FOO refs/tags/new-tag &&\n \ttest_must_fail git rev-parse --symbolic-full-name FOO &&\n \ttest_must_fail git rev-parse FOO -- &&\n \ttest_must_fail git rev-parse refs/tags/new-tag --\n@@ -108,7 +107,7 @@ test_expect_success 'delete_reflog(HEAD)' '\n '\n \n test_expect_success 'create-reflog(HEAD)' '\n-\t$RUN create-reflog HEAD 1 &&\n+\t$RUN create-reflog HEAD &&\n \tgit reflog exists HEAD\n '\n \ndiff --git a/t/t1406-submodule-ref-store.sh b/t/t1406-submodule-ref-store.sh\nindex 0a87058971e..f1e57a9c051 100755\n--- a/t/t1406-submodule-ref-store.sh\n+++ b/t/t1406-submodule-ref-store.sh\n@@ -92,7 +92,7 @@ test_expect_success 'delete_reflog() not allowed' '\n '\n \n test_expect_success 'create-reflog() not allowed' '\n-\ttest_must_fail $RUN create-reflog HEAD 1\n+\ttest_must_fail $RUN create-reflog HEAD\n '\n \n test_done\n-- \ngitgitgadget\n\n"},{"id":"443276","messageId":"865458bc0cb1c2abbc4c378f9e4e4317a05fa0b9.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 2/8] test-ref-store: parse symbolic flag constants","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:14Z","receivedAt":"2021-12-07T13:38:28Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis lets tests use REF_XXXX constants instead of hardcoded integers. The flag\nnames should be separated by a ','.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c | 66 ++++++++++++++++++++++++++++++++++-----\n t/t1405-main-ref-store.sh |  3 +-\n 2 files changed, 60 insertions(+), 9 deletions(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex b795a56eedf..abb0ba101ae 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -5,6 +5,48 @@\n #include \"object-store.h\"\n #include \"repository.h\"\n \n+struct flag_definition {\n+\tconst char *name;\n+\tuint64_t mask;\n+};\n+\n+#define FLAG_DEF(x)     \\\n+\t{               \\\n+#x, (x) \\\n+\t}\n+\n+static unsigned int parse_flags(const char *str, struct flag_definition *defs)\n+{\n+\tstruct string_list masks = STRING_LIST_INIT_DUP;\n+\tint i = 0;\n+\tunsigned int result = 0;\n+\n+\tif (!strcmp(str, \"0\"))\n+\t\treturn 0;\n+\n+\tstring_list_split(&masks, str, ',', 64);\n+\tfor (; i < masks.nr; i++) {\n+\t\tconst char *name = masks.items[i].string;\n+\t\tstruct flag_definition *def = defs;\n+\t\tint found = 0;\n+\t\twhile (def->name) {\n+\t\t\tif (!strcmp(def->name, name)) {\n+\t\t\t\tresult |= def->mask;\n+\t\t\t\tfound = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tdef++;\n+\t\t}\n+\t\tif (!found)\n+\t\t\tdie(\"unknown flag \\\"%s\\\"\", name);\n+\t}\n+\n+\tstring_list_clear(&masks, 0);\n+\treturn result;\n+}\n+\n+static struct flag_definition empty_flags[] = { { NULL, 0 } };\n+\n static const char *notnull(const char *arg, const char *name)\n {\n \tif (!arg)\n@@ -12,9 +54,10 @@ static const char *notnull(const char *arg, const char *name)\n \treturn arg;\n }\n \n-static unsigned int arg_flags(const char *arg, const char *name)\n+static unsigned int arg_flags(const char *arg, const char *name,\n+\t\t\t      struct flag_definition *defs)\n {\n-\treturn atoi(notnull(arg, name));\n+\treturn parse_flags(notnull(arg, name), defs);\n }\n \n static const char **get_store(const char **argv, struct ref_store **refs)\n@@ -64,10 +107,13 @@ static const char **get_store(const char **argv, struct ref_store **refs)\n \treturn argv + 1;\n }\n \n+static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),\n+\t\t\t\t\t       FLAG_DEF(PACK_REFS_ALL),\n+\t\t\t\t\t       { NULL, 0 } };\n \n static int cmd_pack_refs(struct ref_store *refs, const char **argv)\n {\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", pack_flags);\n \n \treturn refs_pack_refs(refs, flags);\n }\n@@ -81,9 +127,15 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv)\n \treturn refs_create_symref(refs, refname, target, logmsg);\n }\n \n+static struct flag_definition transaction_flags[] = {\n+\tFLAG_DEF(REF_NO_DEREF),\n+\tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n+\t{ NULL, 0 }\n+};\n+\n static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n {\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tconst char *msg = *argv++;\n \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n \n@@ -120,7 +172,7 @@ static int cmd_resolve_ref(struct ref_store *refs, const char **argv)\n {\n \tstruct object_id oid = *null_oid();\n \tconst char *refname = notnull(*argv++, \"refname\");\n-\tint resolve_flags = arg_flags(*argv++, \"resolve-flags\");\n+\tint resolve_flags = arg_flags(*argv++, \"resolve-flags\", empty_flags);\n \tint flags;\n \tconst char *ref;\n \tint ignore_errno;\n@@ -209,7 +261,7 @@ static int cmd_delete_ref(struct ref_store *refs, const char **argv)\n \tconst char *msg = notnull(*argv++, \"msg\");\n \tconst char *refname = notnull(*argv++, \"refname\");\n \tconst char *sha1_buf = notnull(*argv++, \"old-sha1\");\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tstruct object_id old_oid;\n \n \tif (get_oid_hex(sha1_buf, &old_oid))\n@@ -224,7 +276,7 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv)\n \tconst char *refname = notnull(*argv++, \"refname\");\n \tconst char *new_sha1_buf = notnull(*argv++, \"new-sha1\");\n \tconst char *old_sha1_buf = notnull(*argv++, \"old-sha1\");\n-\tunsigned int flags = arg_flags(*argv++, \"flags\");\n+\tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tstruct object_id old_oid;\n \tstruct object_id new_oid;\n \ndiff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh\nindex 5e0f7073286..63e0ae82bdf 100755\n--- a/t/t1405-main-ref-store.sh\n+++ b/t/t1405-main-ref-store.sh\n@@ -17,8 +17,7 @@ test_expect_success 'setup' '\n test_expect_success REFFILES 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' '\n \tN=`find .git/refs -type f | wc -l` &&\n \ttest \"$N\" != 0 &&\n-\tALL_OR_PRUNE_FLAG=3 &&\n-\t$RUN pack-refs ${ALL_OR_PRUNE_FLAG} &&\n+\t$RUN pack-refs PACK_REFS_PRUNE,PACK_REFS_ALL &&\n \tN=`find .git/refs -type f` &&\n \ttest -z \"$N\"\n '\n-- \ngitgitgadget\n\n"},{"id":"443277","messageId":"dcd4e9f5f26a9c3df8151a24e5c703f72641c8e3.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 3/8] test-ref-store: plug memory leak in cmd_delete_refs","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:15Z","receivedAt":"2021-12-07T13:38:29Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/helper/test-ref-store.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex abb0ba101ae..8fee3cfce1a 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -138,11 +138,14 @@ static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n \tunsigned int flags = arg_flags(*argv++, \"flags\", transaction_flags);\n \tconst char *msg = *argv++;\n \tstruct string_list refnames = STRING_LIST_INIT_NODUP;\n+\tint result;\n \n \twhile (*argv)\n \t\tstring_list_append(&refnames, *argv++);\n \n-\treturn refs_delete_refs(refs, msg, &refnames, flags);\n+\tresult = refs_delete_refs(refs, msg, &refnames, flags);\n+\tstring_list_clear(&refnames, 0);\n+\treturn result;\n }\n \n static int cmd_rename_ref(struct ref_store *refs, const char **argv)\n-- \ngitgitgadget\n\n"},{"id":"443278","messageId":"67d22211ac4b1b62b2c3f76893765255a59ade8a.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 4/8] refs: update comment.","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:16Z","receivedAt":"2021-12-07T13:38:30Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nREF_IS_PRUNING is right below this comment, so it clearly does not belong in\nthis comment. This was apparently introduced in commit 5ac95fee (Nov 5, 2017\n\"refs: tidy up and adjust visibility of the `ref_update` flags\").\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs/files-backend.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4b14f30d48f..37329b98cca 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -16,8 +16,7 @@\n  * This backend uses the following flags in `ref_update::flags` for\n  * internal bookkeeping purposes. Their numerical values must not\n  * conflict with REF_NO_DEREF, REF_FORCE_CREATE_REFLOG, REF_HAVE_NEW,\n- * REF_HAVE_OLD, or REF_IS_PRUNING, which are also stored in\n- * `ref_update::flags`.\n+ * or REF_HAVE_OLD, which are also stored in `ref_update::flags`.\n  */\n \n /*\n-- \ngitgitgadget\n\n"},{"id":"443279","messageId":"a8713dd59ee10aaceaeb271b3de4302121e699a9.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 5/8] refs: introduce REF_SKIP_OID_VERIFICATION flag","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:17Z","receivedAt":"2021-12-07T13:38:32Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis lets the ref-store test helper write non-existent or unparsable objects\ninto the ref storage.\n\nUse this to make t1006 and t3800 independent of the files storage backend.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.h                    |  8 ++++++-\n refs/files-backend.c      | 50 +++++++++++++++++++++++----------------\n t/helper/test-ref-store.c |  1 +\n t/t1006-cat-file.sh       |  5 ++--\n t/t3800-mktag.sh          |  6 +++--\n 5 files changed, 43 insertions(+), 27 deletions(-)\n\ndiff --git a/refs.h b/refs.h\nindex 45c34e99e3a..76efc589cca 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -615,12 +615,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_FORCE_CREATE_REFLOG (1 << 1)\n \n+/*\n+ * Blindly write an object_id. This is useful for testing data corruption\n+ * scenarios.\n+ */\n+#define REF_SKIP_OID_VERIFICATION (1 << 10)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n #define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG)\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 37329b98cca..d0019fcd8b7 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1353,7 +1353,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)\n }\n \n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err);\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err);\n static int commit_ref_update(struct files_ref_store *refs,\n \t\t\t     struct ref_lock *lock,\n \t\t\t     const struct object_id *oid, const char *logmsg,\n@@ -1500,7 +1501,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \t}\n \toidcpy(&lock->old_oid, &orig_oid);\n \n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1520,7 +1521,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,\n \n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = LOG_REFS_NONE;\n-\tif (write_ref_to_lockfile(lock, &orig_oid, &err) ||\n+\tif (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||\n \t    commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -1756,26 +1757,31 @@ static int files_log_ref_write(struct files_ref_store *refs,\n  * errors, rollback the lockfile, fill in *err and return -1.\n  */\n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const struct object_id *oid, struct strbuf *err)\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t int skip_oid_verification, struct strbuf *err)\n {\n \tstatic char term = '\\n';\n \tstruct object *o;\n \tint fd;\n \n-\to = parse_object(the_repository, oid);\n-\tif (!o) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write ref '%s' with nonexistent object %s\",\n-\t\t\t    lock->ref_name, oid_to_hex(oid));\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n-\t}\n-\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n-\t\tstrbuf_addf(err,\n-\t\t\t    \"trying to write non-commit object %s to branch '%s'\",\n-\t\t\t    oid_to_hex(oid), lock->ref_name);\n-\t\tunlock_ref(lock);\n-\t\treturn -1;\n+\tif (!skip_oid_verification) {\n+\t\to = parse_object(the_repository, oid);\n+\t\tif (!o) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write ref '%s' with nonexistent object %s\",\n+\t\t\t\tlock->ref_name, oid_to_hex(oid));\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n+\t\t\tstrbuf_addf(\n+\t\t\t\terr,\n+\t\t\t\t\"trying to write non-commit object %s to branch '%s'\",\n+\t\t\t\toid_to_hex(oid), lock->ref_name);\n+\t\t\tunlock_ref(lock);\n+\t\t\treturn -1;\n+\t\t}\n \t}\n \tfd = get_lock_file_fd(&lock->lk);\n \tif (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||\n@@ -2189,7 +2195,7 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n }\n \n static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,\n-\t\t\t\t   struct object_id *peeled)\n+\t\t\t\t      struct object_id *peeled)\n {\n \tBUG(\"ref_iterator_peel() called for reflog_iterator\");\n }\n@@ -2575,8 +2581,10 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * The reference already has the desired\n \t\t\t * value, so we don't need to write it.\n \t\t\t */\n-\t\t} else if (write_ref_to_lockfile(lock, &update->new_oid,\n-\t\t\t\t\t\t err)) {\n+\t\t} else if (write_ref_to_lockfile(\n+\t\t\t\t   lock, &update->new_oid,\n+\t\t\t\t   update->flags & REF_SKIP_OID_VERIFICATION,\n+\t\t\t\t   err)) {\n \t\t\tchar *write_err = strbuf_detach(err, NULL);\n \n \t\t\t/*\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 8fee3cfce1a..0f3aa84c9f0 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -130,6 +130,7 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv)\n static struct flag_definition transaction_flags[] = {\n \tFLAG_DEF(REF_NO_DEREF),\n \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n+\tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n \t{ NULL, 0 }\n };\n \ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 658628375c8..0d4c55f74ec 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -452,9 +452,8 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme\n \t# Create it manually, as \"git replace\" will die on bogus\n \t# types.\n \thead=$(git rev-parse --verify HEAD) &&\n-\ttest_when_finished \"rm -rf .git/refs/replace\" &&\n-\tmkdir -p .git/refs/replace &&\n-\techo $head >.git/refs/replace/$bogus_short_sha1 &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/replace/$bogus_short_sha1\" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n \n \tcat >expect <<-EOF &&\n \tcommit\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 0544d58a6ea..e3cf0ffbe59 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -72,7 +72,8 @@ check_verify_failure () {\n \n \t\t# Manually create the broken, we cannot do it with\n \t\t# update-ref\n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n \n \t\t# Unlike fsck-ing unreachable content above, this\n \t\t# will always fail.\n@@ -83,7 +84,8 @@ check_verify_failure () {\n \t\t# Make sure the earlier test created it for us\n \t\tgit rev-parse \"$bad_tag\" &&\n \n-\t\techo \"$bad_tag\" >\"bad-tag/$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main delete-refs 0 msg \"$tag_ref\" &&\n+\t\ttest-tool -C bad-tag ref-store main update-ref msg \"$tag_ref\" $bad_tag $ZERO_OID REF_SKIP_OID_VERIFICATION &&\n \n \t\tprintf \"%s tag\\t%s\\n\" \"$bad_tag\" \"$tag_ref\" >expected &&\n \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n-- \ngitgitgadget\n\n"},{"id":"443280","messageId":"577726dc9dffb14558cfe5d3183c6b96c149b3fb.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 6/8] refs: introduce REF_SKIP_REFNAME_VERIFICATION flag","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:18Z","receivedAt":"2021-12-07T13:38:33Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nUse this flag with the test-helper in t1430, to avoid direct writes to the ref\ndatabase.\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n refs.c                    |  7 +++--\n refs.h                    | 10 +++++--\n t/helper/test-ref-store.c |  1 +\n t/t1430-bad-ref-name.sh   | 59 +++++++++++++++++++++------------------\n 4 files changed, 45 insertions(+), 32 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 996ac271641..93bfe5b30cf 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1083,9 +1083,10 @@ int ref_transaction_update(struct ref_transaction *transaction,\n {\n \tassert(err);\n \n-\tif ((new_oid && !is_null_oid(new_oid)) ?\n-\t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n-\t    !refname_is_safe(refname)) {\n+\tif (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&\n+\t    ((new_oid && !is_null_oid(new_oid)) ?\n+\t\t     check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :\n+\t\t\t   !refname_is_safe(refname))) {\n \t\tstrbuf_addf(err, _(\"refusing to update ref with bad name '%s'\"),\n \t\t\t    refname);\n \t\treturn -1;\ndiff --git a/refs.h b/refs.h\nindex 76efc589cca..65017ceaefc 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -621,12 +621,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);\n  */\n #define REF_SKIP_OID_VERIFICATION (1 << 10)\n \n+/*\n+ * Skip verifying refname. This is useful for testing data corruption scenarios.\n+ */\n+#define REF_SKIP_REFNAME_VERIFICATION (1 << 11)\n+\n /*\n  * Bitmask of all of the flags that are allowed to be passed in to\n  * ref_transaction_update() and friends:\n  */\n-#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \\\n-\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)\n+#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS                                  \\\n+\t(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \\\n+\t REF_SKIP_REFNAME_VERIFICATION)\n \n /*\n  * Add a reference update to transaction. `new_oid` is the value that\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 0f3aa84c9f0..8bca4f2af1b 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -131,6 +131,7 @@ static struct flag_definition transaction_flags[] = {\n \tFLAG_DEF(REF_NO_DEREF),\n \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n \tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n+\tFLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),\n \t{ NULL, 0 }\n };\n \ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 4c77cf89a6c..326e5bd5e80 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -9,7 +9,8 @@ TEST_PASSES_SANITIZE_LEAK=true\n \n test_expect_success setup '\n \ttest_commit one &&\n-\ttest_commit two\n+\ttest_commit two &&\n+\tmain_sha1=$(git rev-parse refs/heads/main)\n '\n \n test_expect_success 'fast-import: fail on invalid branch name \".badbranchname\"' '\n@@ -43,16 +44,16 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n '\n \n test_expect_success 'git branch shows badly named ref as warning' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch >output 2>error &&\n \ttest_i18ngrep -e \"ignoring ref with broken name refs/heads/broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete badly named ref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -d broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -60,8 +61,8 @@ test_expect_success 'branch -d can delete badly named ref' '\n '\n \n test_expect_success 'branch -D can delete badly named ref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -D broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -90,7 +91,7 @@ test_expect_success 'branch -D cannot delete absolute path' '\n '\n \n test_expect_success 'git branch cannot create a badly named ref' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \ttest_must_fail git branch broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -98,7 +99,7 @@ test_expect_success 'git branch cannot create a badly named ref' '\n '\n \n test_expect_success 'branch -m cannot rename to a bad ref name' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \ttest_might_fail git branch -D goodref &&\n \tgit branch goodref &&\n \ttest_must_fail git branch -m goodref broken...ref &&\n@@ -109,8 +110,9 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n '\n \n test_expect_failure 'branch -m can rename from a bad ref name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -m broken...ref renamed &&\n \ttest_cmp_rev main renamed &&\n \tgit branch >output 2>error &&\n@@ -119,7 +121,7 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n '\n \n test_expect_success 'push cannot create a badly named ref' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \ttest_must_fail git push \"file://$(pwd)\" HEAD:refs/heads/broken...ref &&\n \tgit branch >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" error &&\n@@ -139,7 +141,7 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n \t\tcd dest &&\n \t\ttest_commit two &&\n \t\tgit checkout --detach &&\n-\t\tcp .git/refs/heads/main .git/refs/heads/broken...ref\n+\t\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION\n \t) &&\n \tgit -C src push --mirror \"file://$top/dest\" &&\n \tgit -C dest branch >output 2>error &&\n@@ -148,9 +150,9 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n '\n \n test_expect_success 'rev-parse skips symref pointing to broken name' '\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch shadow one &&\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n \ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n@@ -160,8 +162,8 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n '\n \n test_expect_success 'for-each-ref emits warnings for broken names' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n@@ -176,8 +178,8 @@ test_expect_success 'for-each-ref emits warnings for broken names' '\n '\n \n test_expect_success 'update-ref -d can delete broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit update-ref -d refs/heads/broken...ref >output 2>error &&\n \ttest_must_be_empty output &&\n \ttest_must_be_empty error &&\n@@ -187,8 +189,8 @@ test_expect_success 'update-ref -d can delete broken name' '\n '\n \n test_expect_success 'branch -d can delete broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch -d broken...ref >output 2>error &&\n \ttest_i18ngrep \"Deleted branch broken...ref (was broken)\" output &&\n \ttest_must_be_empty error &&\n@@ -198,8 +200,9 @@ test_expect_success 'branch -d can delete broken name' '\n '\n \n test_expect_success 'update-ref --no-deref -d can delete symref to broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n@@ -209,8 +212,9 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n '\n \n test_expect_success 'branch -d can delete symref to broken name' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n@@ -238,8 +242,9 @@ test_expect_success 'branch -d can delete dangling symref to broken name' '\n '\n \n test_expect_success 'update-ref -d can delete broken name through symref' '\n-\tcp .git/refs/heads/main .git/refs/heads/broken...ref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n+\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n \ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n-- \ngitgitgadget\n\n"},{"id":"443281","messageId":"d85cfa3fee1d6f38f34916d2429d45701ad450b3.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 7/8] t1430: remove refs using test-tool","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:19Z","receivedAt":"2021-12-07T13:38:35Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/t1430-bad-ref-name.sh | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 326e5bd5e80..84e912777c5 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -154,7 +154,7 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n \tgit branch shadow one &&\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n-\ttest_when_finished \"rm -f .git/refs/tags/shadow\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n \tgit rev-parse --verify shadow >actual 2>err &&\n \ttest_cmp expect actual &&\n@@ -165,9 +165,9 @@ test_expect_success 'for-each-ref emits warnings for broken names' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit for-each-ref >output 2>error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output &&\n \t! grep -e \"badname\" output &&\n@@ -204,7 +204,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_must_be_empty output &&\n@@ -216,7 +216,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n@@ -225,7 +225,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_must_be_empty output &&\n@@ -234,7 +234,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n \n test_expect_success 'branch -d can delete dangling symref to broken name' '\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n \ttest_i18ngrep \"Deleted branch badname (was refs/heads/broken\\.\\.\\.ref)\" output &&\n@@ -246,7 +246,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n-\ttest_when_finished \"rm -f .git/refs/heads/badname\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...ref &&\n \ttest_must_be_empty output &&\n@@ -255,7 +255,7 @@ test_expect_success 'update-ref -d can delete broken name through symref' '\n \n test_expect_success 'update-ref --no-deref -d can delete symref with broken name' '\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_must_be_empty output &&\n@@ -264,7 +264,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref with broken name\n \n test_expect_success 'branch -d can delete symref with broken name' '\n \tprintf \"ref: refs/heads/main\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit branch -d broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/main)\" output &&\n@@ -273,7 +273,7 @@ test_expect_success 'branch -d can delete symref with broken name' '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' '\n \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_must_be_empty output &&\n@@ -282,7 +282,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref with br\n \n test_expect_success 'branch -d can delete dangling symref with broken name' '\n \tprintf \"ref: refs/heads/idonotexist\\n\" >.git/refs/heads/broken...symref &&\n-\ttest_when_finished \"rm -f .git/refs/heads/broken...symref\" &&\n+\ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...symref\" &&\n \tgit branch -d broken...symref >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...symref &&\n \ttest_i18ngrep \"Deleted branch broken...symref (was refs/heads/idonotexist)\" output &&\n-- \ngitgitgadget\n\n"},{"id":"443282","messageId":"7597620ec83a2e956316d27835db423372d618a8.1638884300.git.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"[PATCH v4 8/8] t1430: create valid symrefs using test-helper","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:20Z","receivedAt":"2021-12-07T13:38:37Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"From: Han-Wen Nienhuys <hanwen@google.com>\n\nThis still leaves some other direct filesystem access. Currently, the files\nbackend does not allow invalidly named symrefs. Fixes for this are currently in\nthe 'seen' branch\n\nSigned-off-by: Han-Wen Nienhuys <hanwen@google.com>\n---\n t/t1430-bad-ref-name.sh | 14 ++++++--------\n 1 file changed, 6 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 84e912777c5..ff1c967d550 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -153,7 +153,7 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n \tgit branch shadow one &&\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/tags/shadow &&\n+\ttest-tool ref-store main create-symref refs/tags/shadow refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/tags/shadow\" &&\n \tgit rev-parse --verify one >expect &&\n \tgit rev-parse --verify shadow >actual 2>err &&\n@@ -203,7 +203,7 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n \n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -213,9 +213,8 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name'\n \n test_expect_success 'branch -d can delete symref to broken name' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n-\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -224,7 +223,7 @@ test_expect_success 'branch -d can delete symref to broken name' '\n '\n \n test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref --no-deref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -233,7 +232,7 @@ test_expect_success 'update-ref --no-deref -d can delete dangling symref to brok\n '\n \n test_expect_success 'branch -d can delete dangling symref to broken name' '\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit branch -d badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/badname &&\n@@ -243,9 +242,8 @@ test_expect_success 'branch -d can delete dangling symref to broken name' '\n \n test_expect_success 'update-ref -d can delete broken name through symref' '\n \ttest-tool ref-store main update-ref msg \"refs/heads/broken...ref\" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&\n-\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref\" &&\n-\tprintf \"ref: refs/heads/broken...ref\\n\" >.git/refs/heads/badname &&\n+\ttest-tool ref-store main create-symref refs/heads/badname refs/heads/broken...ref msg &&\n \ttest_when_finished \"test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/badname\" &&\n \tgit update-ref -d refs/heads/badname >output 2>error &&\n \ttest_path_is_missing .git/refs/heads/broken...ref &&\n-- \ngitgitgadget\n"},{"id":"443283","messageId":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","threadId":"56981","inReplyTo":"pull.1147.v3.git.git.1638470403.gitgitgadget@gmail.com","subject":"[PATCH v4 0/8] Allow writing invalid OIDs into refs for testing purposes","fromName":"Han-Wen Nienhuys via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-12-07T13:38:12Z","receivedAt":"2021-12-07T13:39:21Z","isPatch":true,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"this covers a few cases of direct filesystem access to the ref database in\ntests.\n\nv4:\n\n * fix stack OOB read due to missing array terminator.\n\nHan-Wen Nienhuys (8):\n  test-ref-store: remove force-create argument for create-reflog\n  test-ref-store: parse symbolic flag constants\n  test-ref-store: plug memory leak in cmd_delete_refs\n  refs: update comment.\n  refs: introduce REF_SKIP_OID_VERIFICATION flag\n  refs: introduce REF_SKIP_REFNAME_VERIFICATION flag\n  t1430: remove refs using test-tool\n  t1430: create valid symrefs using test-helper\n\n refs.c                         |  7 +--\n refs.h                         | 16 +++++-\n refs/files-backend.c           | 53 ++++++++++---------\n t/helper/test-ref-store.c      | 75 +++++++++++++++++++++++----\n t/t1006-cat-file.sh            |  5 +-\n t/t1405-main-ref-store.sh      |  8 ++-\n t/t1406-submodule-ref-store.sh |  2 +-\n t/t1430-bad-ref-name.sh        | 93 ++++++++++++++++++----------------\n t/t3800-mktag.sh               |  6 ++-\n 9 files changed, 172 insertions(+), 93 deletions(-)\n\n\nbase-commit: abe6bb3905392d5eb6b01fa6e54d7e784e0522aa\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1147%2Fhanwen%2Fskip-verification-v4\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1147/hanwen/skip-verification-v4\nPull-Request: https://github.com/git/git/pull/1147\n\nRange-diff vs v3:\n\n 1:  3649ef6d0fa = 1:  3649ef6d0fa test-ref-store: remove force-create argument for create-reflog\n 2:  3cdebd2dbca ! 2:  865458bc0cb test-ref-store: parse symbolic flag constants\n     @@ t/helper/test-ref-store.c\n      +\treturn result;\n      +}\n      +\n     -+static struct flag_definition empty_flags[] = {\n     -+\t{ NULL, 0 },\n     -+};\n     ++static struct flag_definition empty_flags[] = { { NULL, 0 } };\n      +\n       static const char *notnull(const char *arg, const char *name)\n       {\n     @@ t/helper/test-ref-store.c: static const char **get_store(const char **argv, stru\n       \treturn argv + 1;\n       }\n       \n     -+static struct flag_definition pack_flags[] = {\n     -+\tFLAG_DEF(PACK_REFS_PRUNE),\n     -+\tFLAG_DEF(PACK_REFS_ALL),\n     -+};\n     ++static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),\n     ++\t\t\t\t\t       FLAG_DEF(PACK_REFS_ALL),\n     ++\t\t\t\t\t       { NULL, 0 } };\n       \n       static int cmd_pack_refs(struct ref_store *refs, const char **argv)\n       {\n     @@ t/helper/test-ref-store.c: static int cmd_create_symref(struct ref_store *refs,\n      +static struct flag_definition transaction_flags[] = {\n      +\tFLAG_DEF(REF_NO_DEREF),\n      +\tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n     -+\t{ NULL, 0 },\n     ++\t{ NULL, 0 }\n      +};\n      +\n       static int cmd_delete_refs(struct ref_store *refs, const char **argv)\n 3:  536005d65a2 = 3:  dcd4e9f5f26 test-ref-store: plug memory leak in cmd_delete_refs\n 4:  466b4451015 = 4:  67d22211ac4 refs: update comment.\n 5:  89d692a34b8 ! 5:  a8713dd59ee refs: introduce REF_SKIP_OID_VERIFICATION flag\n     @@ t/helper/test-ref-store.c: static int cmd_create_symref(struct ref_store *refs,\n       \tFLAG_DEF(REF_NO_DEREF),\n       \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n      +\tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n     - \t{ NULL, 0 },\n     + \t{ NULL, 0 }\n       };\n       \n      \n 6:  af9e94935bf ! 6:  577726dc9df refs: introduce REF_SKIP_REFNAME_VERIFICATION flag\n     @@ t/helper/test-ref-store.c: static struct flag_definition transaction_flags[] = {\n       \tFLAG_DEF(REF_FORCE_CREATE_REFLOG),\n       \tFLAG_DEF(REF_SKIP_OID_VERIFICATION),\n      +\tFLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),\n     - \t{ NULL, 0 },\n     + \t{ NULL, 0 }\n       };\n       \n      \n 7:  d4f1d209468 = 7:  d85cfa3fee1 t1430: remove refs using test-tool\n 8:  ca7f8aea3d9 = 8:  7597620ec83 t1430: create valid symrefs using test-helper\n\n-- \ngitgitgadget\n"},{"id":"443371","messageId":"xmqqtufk5d2p.fsf@gitster.g","threadId":"56981","inReplyTo":"pull.1147.v4.git.git.1638884300.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 0/8] Allow writing invalid OIDs into refs for testing purposes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-07T21:18:06Z","receivedAt":"2021-12-07T21:18:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Han-Wen Nienhuys via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> this covers a few cases of direct filesystem access to the ref database in\n> tests.\n>\n> v4:\n>\n>  * fix stack OOB read due to missing array terminator.\n\nLooks good to me.  I'll tentatively mark it for 'next' and will\nmerge it by the end of this week unless problems are found in the\nseries.\n\nThanks for a pleasant read.\n"}]}