From: Jiang Xin <worldhello.net@gmail.com>
To: Junio C Hamano <gitster@pobox.com>,
Patrick Steinhardt <ps@pks.im>,
Michael Heemskerk <mheemskerk@atlassian.com>,
Git List <git@vger.kernel.org>
Cc: Jiang Xin <zhiyou.jx@alibaba-inc.com>,
Jiang Xin <worldhello.net@gmail.com>
Subject: [PATCH v2 8/9] refs: reimplement files_copy_or_rename_ref() to run refs-txn hook
Date: Fri, 19 Aug 2022 11:21:46 +0800 [thread overview]
Message-ID: <20220819032147.28841-9-worldhello.net@gmail.com> (raw)
In-Reply-To: <CANYiYbFw71bX827akAG87RSKOozPk313Hoe573O9dQ65_U6sLQ@mail.gmail.com>
From: Jiang Xin <zhiyou.jx@alibaba-inc.com>
When copying or renaming a branch, the "reference-transaction" hook is
not executed. This is because we called two low-level functions
"lock_ref_oid_basic()" and "write_ref_to_lockfile()", and reinvented
the wheel in "commit_ref_update()" to update the reference instead of
implementing "files_copy_or_rename_ref()" by calling "refs_update_ref()"
to update a reference in a transaction. The reason for this is that we
want to create a proper reflog for the newly copied reference.
Refactor "files_copy_or_rename_ref()" by calling the extended version
of "refs_update_ref", i.e. "refs_update_ref_extended()", so we can
create the target branch for copying or renaming a branch and generate
a correct reflog file at the same time.
The behavior of the following git commands and two testcases have been
fixed in t1416:
* git branch -c <src> <dest> # copy branch
* git branch -m <old> <new> # rename branch
Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>
---
refs/files-backend.c | 97 +++-----------------------------
t/t1416-ref-transaction-hooks.sh | 28 +--------
2 files changed, 9 insertions(+), 116 deletions(-)
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 336384daa0..e029f5a885 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1376,10 +1376,6 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
static int write_ref_to_lockfile(struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err);
-static int commit_ref_update(struct files_ref_store *refs,
- struct ref_lock *lock,
- const struct object_id *oid, const char *logmsg,
- struct strbuf *err);
/*
* Emit a better error message than lockfile.c's
@@ -1418,13 +1414,13 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
files_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
struct object_id orig_oid;
int flag = 0, logmoved = 0;
- struct ref_lock *lock;
struct stat loginfo;
struct strbuf sb_oldref = STRBUF_INIT;
struct strbuf sb_newref = STRBUF_INIT;
struct strbuf tmp_renamed_log = STRBUF_INIT;
int log, ret;
struct strbuf err = STRBUF_INIT;
+ struct reflog_info reflog_info;
files_reflog_path(refs, &sb_oldref, oldrefname);
files_reflog_path(refs, &sb_newref, newrefname);
@@ -1510,8 +1506,10 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
logmoved = log;
- lock = lock_ref_oid_basic(refs, newrefname, &err);
- if (!lock) {
+ reflog_info.msg = (char *)logmsg;
+ reflog_info.old_oid = &orig_oid;
+ if (refs_update_ref_extended(ref_store, newrefname, &orig_oid, NULL,
+ REF_NO_DEREF, &reflog_info, &err)) {
if (copy)
error("unable to copy '%s' to '%s': %s", oldrefname, newrefname, err.buf);
else
@@ -1519,36 +1517,20 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
strbuf_release(&err);
goto rollback;
}
- oidcpy(&lock->old_oid, &orig_oid);
-
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
- commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
- error("unable to write current sha1 into %s: %s", newrefname, err.buf);
- strbuf_release(&err);
- goto rollback;
- }
ret = 0;
goto out;
rollback:
- lock = lock_ref_oid_basic(refs, oldrefname, &err);
- if (!lock) {
- error("unable to lock %s for rollback: %s", oldrefname, err.buf);
- strbuf_release(&err);
- goto rollbacklog;
- }
-
flag = log_all_ref_updates;
log_all_ref_updates = LOG_REFS_NONE;
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
- commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
+ if (refs_update_ref_extended(ref_store, oldrefname, &orig_oid, NULL,
+ REF_NO_DEREF, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
}
log_all_ref_updates = flag;
- rollbacklog:
if (logmoved && rename(sb_newref.buf, sb_oldref.buf))
error("unable to restore logfile %s from %s: %s",
oldrefname, newrefname, strerror(errno));
@@ -1815,71 +1797,6 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
return 0;
}
-/*
- * Commit a change to a loose reference that has already been written
- * to the loose reference lockfile. Also update the reflogs if
- * necessary, using the specified lockmsg (which can be NULL).
- */
-static int commit_ref_update(struct files_ref_store *refs,
- struct ref_lock *lock,
- const struct object_id *oid, const char *logmsg,
- struct strbuf *err)
-{
- files_assert_main_repository(refs, "commit_ref_update");
-
- clear_loose_ref_cache(refs);
- if (files_log_ref_write(refs, lock->ref_name,
- &lock->old_oid, oid,
- logmsg, 0, err)) {
- char *old_msg = strbuf_detach(err, NULL);
- strbuf_addf(err, "cannot update the ref '%s': %s",
- lock->ref_name, old_msg);
- free(old_msg);
- unlock_ref(lock);
- return -1;
- }
-
- if (strcmp(lock->ref_name, "HEAD") != 0) {
- /*
- * Special hack: If a branch is updated directly and HEAD
- * points to it (may happen on the remote side of a push
- * for example) then logically the HEAD reflog should be
- * updated too.
- * A generic solution implies reverse symref information,
- * but finding all symrefs pointing to the given branch
- * would be rather costly for this rare event (the direct
- * update of a branch) to be worth it. So let's cheat and
- * check with HEAD only which should cover 99% of all usage
- * scenarios (even 100% of the default ones).
- */
- int head_flag;
- const char *head_ref;
-
- head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD",
- RESOLVE_REF_READING,
- NULL, &head_flag);
- if (head_ref && (head_flag & REF_ISSYMREF) &&
- !strcmp(head_ref, lock->ref_name)) {
- struct strbuf log_err = STRBUF_INIT;
- if (files_log_ref_write(refs, "HEAD",
- &lock->old_oid, oid,
- logmsg, 0, &log_err)) {
- error("%s", log_err.buf);
- strbuf_release(&log_err);
- }
- }
- }
-
- if (commit_ref(lock)) {
- strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
- unlock_ref(lock);
- return -1;
- }
-
- unlock_ref(lock);
- return 0;
-}
-
static int create_ref_symlink(struct ref_lock *lock, const char *target)
{
int ret = -1;
diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh
index 6ba7ba746c..77996017d7 100755
--- a/t/t1416-ref-transaction-hooks.sh
+++ b/t/t1416-ref-transaction-hooks.sh
@@ -715,9 +715,7 @@ test_expect_success "branch: update branch without old-oid" '
test_cmp_heads_and_tags -C workdir expect
'
-# Failed because the reference-transaction hook was not executed at all
-# when copying a branch using "git branch -c".
-test_expect_failure "branch: copy branches" '
+test_expect_success "branch: copy branches" '
test_when_finished "rm -f $HOOK_OUTPUT" &&
cat >expect <<-\EOF &&
@@ -750,29 +748,7 @@ test_expect_failure "branch: copy branches" '
test_cmp_heads_and_tags -C workdir expect
'
-# Mismatched hook output for "git branch -m":
-#
-# * The "reference-transaction committed" command was not executed
-# for the target branch.
-#
-# The differences are as follows:
-#
-# @@ -3,14 +3,6 @@
-# ## Call hook: reference-transaction committed ##
-# <COMMIT-B> <ZERO-OID> refs/heads/topic4
-# ## Call hook: reference-transaction prepared ##
-# -<ZERO-OID> <COMMIT-B> refs/heads/topic6
-# -## Call hook: reference-transaction committed ##
-# -<ZERO-OID> <COMMIT-B> refs/heads/topic6
-# -## Call hook: reference-transaction prepared ##
-# <COMMIT-C> <ZERO-OID> refs/heads/topic5
-# ## Call hook: reference-transaction committed ##
-# <COMMIT-C> <ZERO-OID> refs/heads/topic5
-# -## Call hook: reference-transaction prepared ##
-# -<ZERO-OID> <COMMIT-C> refs/heads/topic7
-# -## Call hook: reference-transaction committed ##
-# -<ZERO-OID> <COMMIT-C> refs/heads/topic7
-test_expect_failure "branch: rename branches" '
+test_expect_success "branch: rename branches" '
test_when_finished "rm -f $HOOK_OUTPUT" &&
cat >expect <<-\EOF &&
--
2.36.1.25.gc87d5ad63a.dirty
next prev parent reply other threads:[~2022-08-19 3:22 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-29 10:12 [PATCH 0/9] Fix issues of reference-transaction hook for various git commands Jiang Xin
2022-07-29 10:12 ` [PATCH 1/9] t1416: more testcases for reference-transaction hook Jiang Xin
2022-07-30 6:44 ` Eric Sunshine
2022-07-31 3:25 ` Jiang Xin
2022-07-29 10:12 ` [PATCH 2/9] refs: update missing old-oid in transaction from lockfile Jiang Xin
2022-07-29 10:12 ` [PATCH 3/9] refs: add new field in transaction for running transaction hook Jiang Xin
2022-07-29 10:12 ` [PATCH 4/9] refs: do not run transaction hook for git-pack-refs Jiang Xin
2022-07-29 10:12 ` [PATCH 5/9] refs: avoid duplicate running of the reference-transaction hook Jiang Xin
2022-08-02 12:18 ` Michael Heemskerk
2022-08-05 1:41 ` Jiang Xin
2022-08-19 3:21 ` [PATCH v2 0/9] Fix issues of refx-txn hook for various git commands Jiang Xin
2022-08-19 3:21 ` [PATCH v2 1/9] t1416: more testcases for reference-transaction hook Jiang Xin
2022-08-19 3:21 ` [PATCH v2 2/9] refs: update missing old-oid in transaction from lockfile Jiang Xin
2022-08-19 3:21 ` [PATCH v2 3/9] refs: add new field in transaction for running transaction hook Jiang Xin
2022-08-19 3:21 ` [PATCH v2 4/9] refs: do not run transaction hook for git-pack-refs Jiang Xin
2022-08-19 3:21 ` [PATCH v2 5/9] refs: avoid duplicate running of the reference-transaction hook Jiang Xin
2022-08-19 3:21 ` [PATCH v2 6/9] refs: add reflog_info to hold more fields for reflog entry Jiang Xin
2022-08-19 3:21 ` [PATCH v2 7/9] refs: get error message via refs_update_ref_extended() Jiang Xin
2022-08-19 3:21 ` Jiang Xin [this message]
2022-08-19 3:21 ` [PATCH v2 9/9] refs: reimplement refs_delete_refs() and run hook once Jiang Xin
2022-07-29 10:12 ` [PATCH 6/9] refs: add reflog_info to hold more fields for reflog entry Jiang Xin
2022-08-01 11:32 ` Jiang Xin
2022-07-29 10:12 ` [PATCH 7/9] refs: get error message via refs_update_ref_extended() Jiang Xin
2022-07-29 10:12 ` [PATCH 8/9] refs: reimplement files_copy_or_rename_ref() to run hook Jiang Xin
2022-07-29 10:12 ` [PATCH 9/9] refs: reimplement refs_delete_refs() and run hook once Jiang Xin
2022-08-02 12:42 ` Michael Heemskerk
2022-08-09 11:05 ` Patrick Steinhardt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220819032147.28841-9-worldhello.net@gmail.com \
--to=worldhello.net@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=mheemskerk@atlassian.com \
--cc=ps@pks.im \
--cc=zhiyou.jx@alibaba-inc.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.