This gets rid of the special casing code for pseudorefs in refs.c This is in preparation for reftable. v2 * remove special casing of non-HEAD pseudorefs; update t1400 and t1405 accordingly * open question: should git-update-ref.txt be updated, when it talks about logAllRefUpdates? Han-Wen Nienhuys (3): t1400: use git rev-parse for testing PSEUDOREF existence Modify pseudo refs through ref backend storage Make HEAD a PSEUDOREF rather than PER_WORKTREE. refs.c | 127 +++----------------------------------- t/t1400-update-ref.sh | 30 ++++----- t/t1405-main-ref-store.sh | 5 +- 3 files changed, 29 insertions(+), 133 deletions(-) base-commit: 4a0fcf9f760c9774be77f51e1e88a7499b53d2e2 Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-673%2Fhanwen%2Fpseudoref-v2 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-673/hanwen/pseudoref-v2 Pull-Request: https://github.com/gitgitgadget/git/pull/673 Range-diff vs v1: -: ---------- > 1: 9c3dc4b2cb t1400: use git rev-parse for testing PSEUDOREF existence 1: 6821f57bdf ! 2: 871b411517 Modify pseudo refs through ref backend storage @@ Commit message well. Tooling that works directly on files under .git should be updated to use git commands to read refs instead. - This needs the following fixes + The following behaviors change: - * Only write log for HEAD pseudo ref. Fixes t1400 - 'core.logAllRefUpdates=always creates no reflog for ORIG_HEAD' + * Updates to pseudorefs (eg. ORIG_HEAD) with + core.logAllRefUpdates=always will create reflogs for the pseudoref. - * t1400: change hard coded error messages to check for. - - * don't deref non-HEAD pseudoref symrefs. This fixes t1405. Without - this, a deleting a FOO symref pointing to refs/heads/master will remove - master too. + * non-HEAD pseudoref symrefs are also dereferenced on deletion. Update + t1405 accordingly. Signed-off-by: Han-Wen Nienhuys <hanwen@xxxxxxxxxx> @@ refs.c: int refs_update_ref(struct ref_store *refs, const char *msg, if (ret) { const char *str = _("update_ref failed for ref '%s': %s"); - ## refs/files-backend.c ## -@@ refs/files-backend.c: static int files_delete_refs(struct ref_store *ref_store, const char *msg, - - for (i = 0; i < refnames->nr; i++) { - const char *refname = refnames->items[i].string; -- - if (refs_delete_ref(&refs->base, msg, refname, NULL, flags)) - result |= error(_("could not remove reference %s"), refname); - } -@@ refs/files-backend.c: static int lock_ref_for_update(struct files_ref_store *refs, - update->backend_data = lock; + ## t/t1400-update-ref.sh ## +@@ t/t1400-update-ref.sh: test_expect_success 'core.logAllRefUpdates=always creates reflog by default' ' + git reflog exists $outside + ' - if (update->type & REF_ISSYMREF) { -- if (update->flags & REF_NO_DEREF) { -+ if (update->flags & REF_NO_DEREF || -+ (ref_type(update->refname) == REF_TYPE_PSEUDOREF && -+ strcmp(update->refname, "HEAD"))) { - /* - * We won't be reading the referent as part of - * the transaction, so we have to read it here -@@ refs/files-backend.c: static int files_transaction_finish(struct ref_store *ref_store, - struct ref_update *update = transaction->updates[i]; - struct ref_lock *lock = update->backend_data; +-test_expect_success 'core.logAllRefUpdates=always creates no reflog for ORIG_HEAD' ' ++test_expect_success 'core.logAllRefUpdates=always creates reflog for ORIG_HEAD' ' + test_config core.logAllRefUpdates always && + git update-ref ORIG_HEAD $A && +- test_must_fail git reflog exists ORIG_HEAD ++ git reflog exists ORIG_HEAD + ' -- if (update->flags & REF_NEEDS_COMMIT || -- update->flags & REF_LOG_ONLY) { -+ if ((ref_type(lock->ref_name) != REF_TYPE_PSEUDOREF || -+ !strcmp(lock->ref_name, "HEAD")) && -+ (update->flags & REF_NEEDS_COMMIT || -+ update->flags & REF_LOG_ONLY)) { - if (files_log_ref_write(refs, - lock->ref_name, - &lock->old_oid, - - ## t/t1400-update-ref.sh ## + test_expect_success '--no-create-reflog overrides core.logAllRefUpdates=always' ' @@ t/t1400-update-ref.sh: test_expect_success 'git cat-file blob master@{2005-05-26 23:42}:F (expect OTHER test_expect_success 'given old value for missing pseudoref, do not create' ' test_must_fail git update-ref PSEUDOREF $A $B 2>err && - test_path_is_missing .git/PSEUDOREF && + test_must_fail git rev-parse PSEUDOREF && - test_i18ngrep "could not read ref" err + test_i18ngrep "unable to resolve reference" err ' @@ t/t1400-update-ref.sh: test_expect_success 'git cat-file blob master@{2005-05-26 @@ t/t1400-update-ref.sh: test_expect_success 'overwrite pseudoref with correct old value' ' test_expect_success 'do not overwrite pseudoref with wrong old value' ' test_must_fail git update-ref PSEUDOREF $D $E 2>err && - test $C = $(cat .git/PSEUDOREF) && + test $C = $(git rev-parse PSEUDOREF) && - test_i18ngrep "unexpected object ID" err + test_i18ngrep "cannot lock ref.*expected" err ' @@ t/t1400-update-ref.sh: test_expect_success 'overwrite pseudoref with correct old @@ t/t1400-update-ref.sh: test_expect_success 'do not delete pseudoref with wrong old value' ' git update-ref PSEUDOREF $A && test_must_fail git update-ref -d PSEUDOREF $B 2>err && - test $A = $(cat .git/PSEUDOREF) && + test $A = $(git rev-parse PSEUDOREF) && - test_i18ngrep "unexpected object ID" err + test_i18ngrep "cannot lock ref.*expected" err ' test_expect_success 'delete pseudoref with correct old value' ' + + ## t/t1405-main-ref-store.sh ## +@@ t/t1405-main-ref-store.sh: test_expect_success 'create_symref(FOO, refs/heads/master)' ' + test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' ' + git rev-parse FOO -- && + git rev-parse refs/tags/new-tag -- && ++ m=$(git rev-parse master) && + $RUN delete-refs 0 nothing FOO refs/tags/new-tag && + test_must_fail git rev-parse FOO -- && +- test_must_fail git rev-parse refs/tags/new-tag -- ++ test_must_fail git rev-parse refs/tags/new-tag --&& ++ test_must_fail git rev-parse master -- && ++ git update-ref refs/heads/master $m + ' + + test_expect_success 'rename_refs(master, new-master)' ' 2: 470821dc6d = 3: 1c2b9d5f17 Make HEAD a PSEUDOREF rather than PER_WORKTREE. -- gitgitgadget