summaryrefslogtreecommitdiff
path: root/refs
diff options
context:
space:
mode:
authorLibravatar David Turner <dturner@twopensource.com>2016-02-24 17:58:51 -0500
committerLibravatar Michael Haggerty <mhagger@alum.mit.edu>2016-06-13 11:23:49 +0200
commit12fd3496d19c33c6401c5fdc7558944d46124a0f (patch)
tree541a62489823b571ff738ef7a1f3ff875acafdb7 /refs
parentrefs: allow log-only updates (diff)
downloadtgif-12fd3496d19c33c6401c5fdc7558944d46124a0f.tar.xz
refs: don't dereference on rename
When renaming refs, don't dereference either the origin or the destination before renaming. The origin does not need to be dereferenced because it is presently forbidden to rename symbolic refs. Not dereferencing the destination fixes a bug where renaming on top of a broken symref would use the pointed-to ref name for the moved reflog. Add a test for the reflog bug. Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Diffstat (limited to 'refs')
-rw-r--r--refs/files-backend.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 2f98eebe94..15ba456d68 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -2333,7 +2333,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (log && S_ISLNK(loginfo.st_mode))
return error("reflog for %s is a symlink", oldrefname);
- if (!resolve_ref_unsafe(oldrefname, RESOLVE_REF_READING, orig_sha1, &flag))
+ if (!resolve_ref_unsafe(oldrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ orig_sha1, &flag))
return error("refname %s not found", oldrefname);
if (flag & REF_ISSYMREF)
@@ -2351,8 +2352,16 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
goto rollback;
}
- if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) &&
- delete_ref(newrefname, sha1, REF_NODEREF)) {
+ /*
+ * Since we are doing a shallow lookup, sha1 is not the
+ * correct value to pass to delete_ref as old_sha1. But that
+ * doesn't matter, because an old_sha1 check wouldn't add to
+ * the safety anyway; we want to delete the reference whatever
+ * its current value.
+ */
+ if (!read_ref_full(newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+ sha1, NULL) &&
+ delete_ref(newrefname, NULL, REF_NODEREF)) {
if (errno==EISDIR) {
struct strbuf path = STRBUF_INIT;
int result;
@@ -2376,7 +2385,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
logmoved = log;
- lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, 0, NULL, &err);
+ lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, REF_NODEREF,
+ NULL, &err);
if (!lock) {
error("unable to rename '%s' to '%s': %s", oldrefname, newrefname, err.buf);
strbuf_release(&err);
@@ -2394,7 +2404,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
return 0;
rollback:
- lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, 0, NULL, &err);
+ lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, REF_NODEREF,
+ NULL, &err);
if (!lock) {
error("unable to lock %s for rollback: %s", oldrefname, err.buf);
strbuf_release(&err);