@matheusbsbs / matheus-bagliano / commits / eca35a25a9
Fork 0

Fix git branch -m for symrefs.

This had two problems with symrefs. First, it copied the actual sha1 instead of the "pointer", second it failed to remove the old ref after a successful rename. Given that till now delete_ref() always dereferenced symrefs, a new parameters has been introduced to delete_ref() to allow deleting refs without a dereference. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Miklos Vajna committed Oct 26, 2008 at 03:33 UTC eca35a25a92a1ad725af2a549fc9158488c4cc43
10 files changed +55 -31
builtin-branch.c
+1 -1
@@ -160,7 +160,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
160 continue;
161 }
162
163 - if (delete_ref(name, sha1)) {
163 + if (delete_ref(name, sha1, 0)) {
164 error("Error deleting %sbranch '%s'", remote,
165 argv[i]);
166 ret = 1;
builtin-remote.c
+2 -2
@@ -340,7 +340,7 @@ static int remove_branches(struct string_list *branches)
340 const char *refname = item->string;
341 unsigned char *sha1 = item->util;
342
343 - if (delete_ref(refname, sha1))
343 + if (delete_ref(refname, sha1, 0))
344 result |= error("Could not remove branch %s", refname);
345 }
346 return result;
@@ -570,7 +570,7 @@ static int prune(int argc, const char **argv)
570 const char *refname = states.stale.items[i].util;
571
572 if (!dry_run)
573 - result |= delete_ref(refname, NULL);
573 + result |= delete_ref(refname, NULL, 0);
574
575 printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
576 abbrev_ref(refname, "refs/remotes/"));
builtin-reset.c
+1 -1
@@ -279,7 +279,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
279 update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
280 }
281 else if (old_orig)
282 - delete_ref("ORIG_HEAD", old_orig);
282 + delete_ref("ORIG_HEAD", old_orig, 0);
283 prepend_reflog_action("updating HEAD", msg, sizeof(msg));
284 update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
285
builtin-send-pack.c
+1 -1
@@ -226,7 +226,7 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
226 if (args.verbose)
227 fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
228 if (ref->deletion) {
229 - delete_ref(rs.dst, NULL);
229 + delete_ref(rs.dst, NULL, 0);
230 } else
231 update_ref("update by push", rs.dst,
232 ref->new_sha1, NULL, 0, 0);
builtin-tag.c
+1 -1
@@ -125,7 +125,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn)
125 static int delete_tag(const char *name, const char *ref,
126 const unsigned char *sha1)
127 {
128 - if (delete_ref(ref, sha1))
128 + if (delete_ref(ref, sha1, 0))
129 return 1;
130 printf("Deleted tag '%s'\n", name);
131 return 0;
builtin-update-ref.c
+1 -1
@@ -48,7 +48,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
48 die("%s: not a valid old SHA1", oldval);
49
50 if (delete)
51 - return delete_ref(refname, oldval ? oldsha1 : NULL);
51 + return delete_ref(refname, oldval ? oldsha1 : NULL, 0);
52 else
53 return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
54 no_deref ? REF_NODEREF : 0, DIE_ON_ERR);
cache.h
+1 -1
@@ -420,7 +420,7 @@ extern int commit_locked_index(struct lock_file *);
420 extern void set_alternate_index_output(const char *);
421 extern int close_lock_file(struct lock_file *);
422 extern void rollback_lock_file(struct lock_file *);
423 -extern int delete_ref(const char *, const unsigned char *sha1);
423 +extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
424
425 /* Environment bits from configuration mechanism */
426 extern int trust_executable_bit;
receive-pack.c
+1 -1
@@ -222,7 +222,7 @@ static const char *update(struct command *cmd)
222 warning ("Allowing deletion of corrupt ref.");
223 old_sha1 = NULL;
224 }
225 - if (delete_ref(name, old_sha1)) {
225 + if (delete_ref(name, old_sha1, 0)) {
226 error("failed to delete %s", name);
227 return "failed to delete";
228 }
refs.c
+37 -22
@@ -912,25 +912,33 @@ static int repack_without_ref(const char *refname)
912 return commit_lock_file(&packlock);
913 }
914
915 -int delete_ref(const char *refname, const unsigned char *sha1)
915 +int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
916 {
917 struct ref_lock *lock;
918 - int err, i, ret = 0, flag = 0;
918 + int err, i = 0, ret = 0, flag = 0;
919
920 lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
921 if (!lock)
922 return 1;
923 if (!(flag & REF_ISPACKED)) {
924 /* loose */
925 - i = strlen(lock->lk->filename) - 5; /* .lock */
926 - lock->lk->filename[i] = 0;
927 - err = unlink(lock->lk->filename);
925 + const char *path;
926 +
927 + if (!(delopt & REF_NODEREF)) {
928 + i = strlen(lock->lk->filename) - 5; /* .lock */
929 + lock->lk->filename[i] = 0;
930 + path = lock->lk->filename;
931 + } else {
932 + path = git_path(refname);
933 + }
934 + err = unlink(path);
935 if (err && errno != ENOENT) {
936 ret = 1;
937 error("unlink(%s) failed: %s",
931 - lock->lk->filename, strerror(errno));
938 + path, strerror(errno));
939 }
933 - lock->lk->filename[i] = '.';
940 + if (!(delopt & REF_NODEREF))
941 + lock->lk->filename[i] = '.';
942 }
943 /* removing the loose one could have resurrected an earlier
944 * packed one. Also, if it was not loose we need to repack
@@ -955,11 +963,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
963 struct ref_lock *lock;
964 struct stat loginfo;
965 int log = !lstat(git_path("logs/%s", oldref), &loginfo);
966 + const char *symref = NULL;
967 + int is_symref = 0;
968
969 if (S_ISLNK(loginfo.st_mode))
970 return error("reflog for %s is a symlink", oldref);
971
962 - if (!resolve_ref(oldref, orig_sha1, 1, &flag))
972 + symref = resolve_ref(oldref, orig_sha1, 1, &flag);
973 + if (flag & REF_ISSYMREF)
974 + is_symref = 1;
975 + if (!symref)
976 return error("refname %s not found", oldref);
977
978 if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
@@ -979,12 +992,12 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
992 return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
993 oldref, strerror(errno));
994
982 - if (delete_ref(oldref, orig_sha1)) {
995 + if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
996 error("unable to delete old %s", oldref);
997 goto rollback;
998 }
999
987 - if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) {
1000 + if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
1001 if (errno==EISDIR) {
1002 if (remove_empty_directories(git_path("%s", newref))) {
1003 error("Directory not empty: %s", newref);
@@ -1022,18 +1035,20 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
1035 }
1036 logmoved = log;
1037
1025 - lock = lock_ref_sha1_basic(newref, NULL, 0, NULL);
1026 - if (!lock) {
1027 - error("unable to lock %s for update", newref);
1028 - goto rollback;
1029 - }
1030 -
1031 - lock->force_write = 1;
1032 - hashcpy(lock->old_sha1, orig_sha1);
1033 - if (write_ref_sha1(lock, orig_sha1, logmsg)) {
1034 - error("unable to write current sha1 into %s", newref);
1035 - goto rollback;
1036 - }
1038 + if (!is_symref) {
1039 + lock = lock_ref_sha1_basic(newref, NULL, 0, NULL);
1040 + if (!lock) {
1041 + error("unable to lock %s for update", newref);
1042 + goto rollback;
1043 + }
1044 + lock->force_write = 1;
1045 + hashcpy(lock->old_sha1, orig_sha1);
1046 + if (write_ref_sha1(lock, orig_sha1, logmsg)) {
1047 + error("unable to write current sha1 into %s", newref);
1048 + goto rollback;
1049 + }
1050 + } else
1051 + create_symref(newref, symref, logmsg);
1052
1053 return 0;
1054
t/t3200-branch.sh
+9
@@ -112,6 +112,15 @@ test_expect_success 'config information was renamed, too' \
112 "test $(git config branch.s.dummy) = Hello &&
113 test_must_fail git config branch.s/s/dummy"
114
115 +test_expect_success 'renaming a symref' \
116 +'
117 + git symbolic-ref refs/heads/master2 refs/heads/master &&
118 + git branch -m master2 master3 &&
119 + git symbolic-ref refs/heads/master3 &&
120 + test -f .git/refs/heads/master &&
121 + ! test -f .git/refs/heads/master2
122 +'
123 +
124 test_expect_success \
125 'git branch -m u v should fail when the reflog for u is a symlink' '
126 git branch -l u &&