From 755b49ae965c9d17d91fbe7902050428f366bf69 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Mon, 20 Feb 2017 20:10:32 -0500 Subject: delete_ref: accept a reflog message argument When the current branch is renamed with 'git branch -m/-M' or deleted with 'git update-ref -m -d', the event is recorded in HEAD's log with an empty message. In preparation for adding a more meaningful message to HEAD's log in these cases, update delete_ref() to take a message argument and pass it along to ref_transaction_delete(). Modify all callers to pass NULL for the new message argument; no change in behavior is intended. Note that this is relevant for HEAD's log but not for the deleted ref's log, which is currently deleted along with the ref. Even if it were not, an entry for the deletion wouldn't be present in the deleted ref's log. files_transaction_commit() writes to the log if REF_NEEDS_COMMIT or REF_LOG_ONLY are set, but lock_ref_for_update() doesn't set REF_NEEDS_COMMIT for the deleted ref because REF_DELETING is set. In contrast, the update for HEAD has REF_LOG_ONLY set by split_head_update(), resulting in the deletion being logged. Signed-off-by: Kyle Meyer Signed-off-by: Junio C Hamano --- refs/files-backend.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'refs/files-backend.c') diff --git a/refs/files-backend.c b/refs/files-backend.c index c041d4ba21..299eb4d8af 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -2489,7 +2489,7 @@ static int files_delete_refs(struct ref_store *ref_store, for (i = 0; i < refnames->nr; i++) { const char *refname = refnames->items[i].string; - if (delete_ref(refname, NULL, flags)) + if (delete_ref(NULL, refname, NULL, flags)) result |= error(_("could not remove reference %s"), refname); } @@ -2616,7 +2616,7 @@ static int files_rename_ref(struct ref_store *ref_store, return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s", oldrefname, strerror(errno)); - if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) { + if (delete_ref(NULL, oldrefname, orig_sha1, REF_NODEREF)) { error("unable to delete old %s", oldrefname); goto rollback; } @@ -2630,7 +2630,7 @@ static int files_rename_ref(struct ref_store *ref_store, */ if (!read_ref_full(newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE, sha1, NULL) && - delete_ref(newrefname, NULL, REF_NODEREF)) { + delete_ref(NULL, newrefname, NULL, REF_NODEREF)) { if (errno==EISDIR) { struct strbuf path = STRBUF_INIT; int result; -- cgit v1.2.3 From 893dbf5ba16c47c7284209bc6c527195f368ee35 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Mon, 20 Feb 2017 20:10:34 -0500 Subject: rename_ref: replace empty message in HEAD's log When the current branch is renamed, the deletion of the old ref is recorded in HEAD's log with an empty message. Now that delete_ref() accepts a reflog message, provide a more descriptive message by passing along the log message that is given to rename_ref(). The next step will be to extend HEAD's log to also include the second part of the rename, the creation of the new branch. Helped-by: Jeff King Signed-off-by: Kyle Meyer Signed-off-by: Junio C Hamano --- refs/files-backend.c | 2 +- t/t3200-branch.sh | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'refs/files-backend.c') diff --git a/refs/files-backend.c b/refs/files-backend.c index 299eb4d8af..f6e7c192c5 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -2616,7 +2616,7 @@ static int files_rename_ref(struct ref_store *ref_store, return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s", oldrefname, strerror(errno)); - if (delete_ref(NULL, oldrefname, orig_sha1, REF_NODEREF)) { + if (delete_ref(logmsg, oldrefname, orig_sha1, REF_NODEREF)) { error("unable to delete old %s", oldrefname); goto rollback; } diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 8a833f354e..47bc151280 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -139,6 +139,11 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou test $(git rev-parse --abbrev-ref HEAD) = bam ' +test_expect_success 'git branch -M baz bam should add entry to .git/logs/HEAD' ' + msg="Branch: renamed refs/heads/baz to refs/heads/bam" && + grep " 0\{40\}.*$msg$" .git/logs/HEAD +' + test_expect_success 'git branch -M baz bam should succeed when baz is checked out as linked working tree' ' git checkout master && git worktree add -b baz bazdir && -- cgit v1.2.3 From 39ee4c6c2fc80960094ae1454922c2d10c72f210 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Mon, 20 Feb 2017 20:10:35 -0500 Subject: branch: record creation of renamed branch in HEAD's log Renaming the current branch adds an event to the current branch's log and to HEAD's log. However, the logged entries differ. The entry in the branch's log represents the entire renaming operation (the old and new hash are identical), whereas the entry in HEAD's log represents the deletion only (the new sha1 is null). Extend replace_each_worktree_head_symref(), whose only caller is branch_rename(), to take a reflog message argument. This allows the creation of the new ref to be recorded in HEAD's log. As a result, the renaming event is represented by two entries (a deletion and a creation entry) in HEAD's log. It's a bit unfortunate that the branch's log and HEAD's log now represent the renaming event in different ways. Given that the renaming operation is not atomic, the two-entry form is a more accurate representation of the operation and is more useful for debugging purposes if a failure occurs between the deletion and creation events. It would make sense to move the branch's log to the two-entry form, but this would involve changes to how the rename is carried out and to how the update flags and reflogs are processed for deletions, so it may not be worth the effort. Based-on-patch-by: Jeff King Signed-off-by: Kyle Meyer Signed-off-by: Junio C Hamano --- branch.c | 5 +++-- branch.h | 3 ++- builtin/branch.c | 5 +++-- refs.h | 3 ++- refs/files-backend.c | 4 ++-- t/t3200-branch.sh | 5 +++-- 6 files changed, 15 insertions(+), 10 deletions(-) (limited to 'refs/files-backend.c') diff --git a/branch.c b/branch.c index b955d4f316..5c12036b02 100644 --- a/branch.c +++ b/branch.c @@ -345,7 +345,8 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree) branch, wt->path); } -int replace_each_worktree_head_symref(const char *oldref, const char *newref) +int replace_each_worktree_head_symref(const char *oldref, const char *newref, + const char *logmsg) { int ret = 0; struct worktree **worktrees = get_worktrees(0); @@ -358,7 +359,7 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref) continue; if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]), - newref)) { + newref, logmsg)) { ret = -1; error(_("HEAD of working tree %s is not updated"), worktrees[i]->path); diff --git a/branch.h b/branch.h index 3103eb9add..b07788558c 100644 --- a/branch.h +++ b/branch.h @@ -71,6 +71,7 @@ extern void die_if_checked_out(const char *branch, int ignore_current_worktree); * This will be used when renaming a branch. Returns 0 if successful, non-zero * otherwise. */ -extern int replace_each_worktree_head_symref(const char *oldref, const char *newref); +extern int replace_each_worktree_head_symref(const char *oldref, const char *newref, + const char *logmsg); #endif diff --git a/builtin/branch.c b/builtin/branch.c index 8f8242e07c..e1f97dcfc4 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -579,14 +579,15 @@ static void rename_branch(const char *oldname, const char *newname, int force) if (rename_ref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch rename failed")); - strbuf_release(&logmsg); if (recovery) warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11); - if (replace_each_worktree_head_symref(oldref.buf, newref.buf)) + if (replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch renamed to %s, but HEAD is not updated!"), newname); + strbuf_release(&logmsg); + strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11); strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", newref.buf + 11); diff --git a/refs.h b/refs.h index 5880886a7c..e529f4c3a8 100644 --- a/refs.h +++ b/refs.h @@ -334,7 +334,8 @@ int create_symref(const char *refname, const char *target, const char *logmsg); * $GIT_DIR points to. * Return 0 if successful, non-zero otherwise. * */ -int set_worktree_head_symref(const char *gitdir, const char *target); +int set_worktree_head_symref(const char *gitdir, const char *target, + const char *logmsg); enum action_on_err { UPDATE_REFS_MSG_ON_ERR, diff --git a/refs/files-backend.c b/refs/files-backend.c index f6e7c192c5..42b137bb1c 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -3055,7 +3055,7 @@ static int files_create_symref(struct ref_store *ref_store, return ret; } -int set_worktree_head_symref(const char *gitdir, const char *target) +int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg) { static struct lock_file head_lock; struct ref_lock *lock; @@ -3083,7 +3083,7 @@ int set_worktree_head_symref(const char *gitdir, const char *target) lock->lk = &head_lock; lock->ref_name = xstrdup(head_rel); - ret = create_symref_locked(lock, head_rel, target, NULL); + ret = create_symref_locked(lock, head_rel, target, logmsg); unlock_ref(lock); /* will free lock */ strbuf_release(&head_path); diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 47bc151280..e36ed3b4e1 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -139,9 +139,10 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou test $(git rev-parse --abbrev-ref HEAD) = bam ' -test_expect_success 'git branch -M baz bam should add entry to .git/logs/HEAD' ' +test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' ' msg="Branch: renamed refs/heads/baz to refs/heads/bam" && - grep " 0\{40\}.*$msg$" .git/logs/HEAD + grep " 0\{40\}.*$msg$" .git/logs/HEAD && + grep "^0\{40\}.*$msg$" .git/logs/HEAD ' test_expect_success 'git branch -M baz bam should succeed when baz is checked out as linked working tree' ' -- cgit v1.2.3