git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 23/33] refs: don't dereference on rename

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
May 6, 2016, 16:14 UTC
Message-ID
<c474a36117cfda48aae539817ad921629533aa16.1462550456.git.mhagger@alum.mit.edu>
In-Reply-To
<cover.1462550456.git.mhagger@alum.mit.edu>
From: David Turner <dturner@twopensource.com>

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>
---
 refs/files-backend.c | 21 ++++++++++++++++-----
 t/t3200-branch.sh    |  9 +++++++++
 2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 3f546d0..ad53b6e 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);
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index f3e3b6c..4281160 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -79,6 +79,15 @@ test_expect_success 'git branch -m dumps usage' '
 	test_i18ngrep "branch name required" err
 '
 
+test_expect_success 'git branch -m m broken_symref should work' '
+	test_when_finished "git branch -D broken_symref" &&
+	git branch -l m &&
+	git symbolic-ref refs/heads/broken_symref refs/heads/i_am_broken &&
+	git branch -m m broken_symref &&
+	git reflog exists refs/heads/broken_symref &&
+	test_must_fail git reflog exists refs/heads/i_am_broken
+'
+
 test_expect_success 'git branch -m m m/m should work' '
 	git branch -l m &&
 	git branch -m m m/m &&
-- 
2.8.1
Previous: Michael HaggertyNext: Michael Haggerty
Message 24 of 51 in “Yet more preparation for reference backends”
  1. 00/33 Yet more preparation for reference backendsMichael Haggerty, May 6, 2016
  2. 01/33 t1404: demonstrate a bug resolving referencesMichael Haggerty, May 6, 2016
  3. 02/33 commit_ref(): if there is an empty dir in the way, delete itMichael Haggerty, May 6, 2016
  4. 03/33 read_raw_ref(): don't get confused by an empty directoryMichael Haggerty, May 6, 2016
  5. 04/33 safe_create_leading_directories(): improve docstringMichael Haggerty, May 6, 2016
  6. 05/33 remove_dir_recursively(): add docstringMichael Haggerty, May 6, 2016
  7. 06/33 refname_is_safe(): use skip_prefix()Michael Haggerty, May 6, 2016
  8. 07/33 refname_is_safe(): don't allow the empty stringMichael Haggerty, May 6, 2016
  9. 08/33 refname_is_safe(): insist that the refname already be normalizedMichael Haggerty, May 6, 2016
  10. 09/33 commit_ref_update(): write error message to *err, not stderrMichael Haggerty, May 6, 2016
  11. 10/33 rename_ref(): remove unneeded local variableMichael Haggerty, May 6, 2016
  12. 11/33 ref_transaction_commit(): remove local variable nMichael Haggerty, May 6, 2016
  13. 12/33 read_raw_ref(): rename flags argument to typeMichael Haggerty, May 6, 2016
  14. 13/33 read_raw_ref(): clear *type at start of functionMichael Haggerty, May 6, 2016
  15. 14/33 read_raw_ref(): rename symref argument to referentMichael Haggerty, May 6, 2016
  16. 15/33 read_raw_ref(): improve docstringMichael Haggerty, May 6, 2016
  17. 16/33 read_raw_ref(): move docstring to header fileMichael Haggerty, May 6, 2016
  18. 17/33 lock_ref_sha1_basic(): remove unneeded local variableMichael Haggerty, May 6, 2016
  19. 18/33 refs: make error messages more consistentMichael Haggerty, May 6, 2016
  20. 19/33 ref_transaction_create(): disallow recursive pruningMichael Haggerty, May 6, 2016
  21. 20/33 ref_transaction_commit(): correctly report close_ref() failureMichael Haggerty, May 6, 2016
  22. 21/33 delete_branches(): use resolve_refdup()Michael Haggerty, May 6, 2016
  23. 22/33 refs: allow log-only updatesMichael Haggerty, May 6, 2016
  24. 23/33 refs: don't dereference on renameMichael Haggerty, May 6, 2016
  25. 24/33 verify_refname_available(): adjust constness in declarationMichael Haggerty, May 6, 2016
  26. 25/33 add_update(): initialize the whole ref_updateMichael Haggerty, May 6, 2016
  27. 26/33 lock_ref_for_update(): new functionMichael Haggerty, May 6, 2016
  28. 27/33 unlock_ref(): move definition higher in the fileMichael Haggerty, May 6, 2016
  29. 28/33 ref_transaction_update(): check refname_is_safe() at a minimumMichael Haggerty, May 6, 2016
  30. 29/33 refs: resolve symbolic refs firstMichael Haggerty, May 6, 2016
  31. Jeff KingMay 12, 2016
  32. Jeff KingMay 12, 2016
  33. Michael HaggertyMay 13, 2016
  34. 29/33 refs: resolve symbolic refs firstMichael Haggerty, May 13, 2016
  35. Jeff KingMay 13, 2016
  36. Jeff KingMay 13, 2016
  37. Torsten BögershausenMay 14, 2016
  38. 30/33 lock_ref_for_update(): don't re-read non-symbolic referencesMichael Haggerty, May 6, 2016
  39. 31/33 lock_ref_for_update(): don't resolve symrefsMichael Haggerty, May 6, 2016
  40. 32/33 commit_ref_update(): remove the flags parameterMichael Haggerty, May 6, 2016
  41. 33/33 lock_ref_sha1_basic(): only handle REF_NODEREF modeMichael Haggerty, May 6, 2016
  42. David TurnerMay 9, 2016
  43. Junio C HamanoMay 9, 2016
  44. Michael HaggertyMay 9, 2016
  45. Junio C HamanoMay 9, 2016
  46. Jeff KingMay 12, 2016
  47. Junio C HamanoMay 12, 2016
  48. Junio C HamanoMay 10, 2016
  49. Michael HaggertyJun 10, 2016
  50. Junio C HamanoJun 10, 2016
  51. [ADDENDUM v4] Yet more preparation for reference backendsMichael Haggerty, Jun 13, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.