Skip to content

Commit efcce2e

Browse files
committed
Merge branch 'mv/maint-branch-m-symref'
* mv/maint-branch-m-symref: update-ref --no-deref -d: handle the case when the pointed ref is packed git branch -m: forbid renaming of a symref Fix git update-ref --no-deref -d. rename_ref(): handle the case when the reflog of a ref does not exist Fix git branch -m for symrefs.
2 parents 7bc9ed0 + 045a476 commit efcce2e

File tree

11 files changed

+65
-24
lines changed

11 files changed

+65
-24
lines changed

builtin-branch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
160160
continue;
161161
}
162162

163-
if (delete_ref(name, sha1)) {
163+
if (delete_ref(name, sha1, 0)) {
164164
error("Error deleting %sbranch '%s'", remote,
165165
argv[i]);
166166
ret = 1;

builtin-receive-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ static const char *update(struct command *cmd)
236236
warning ("Allowing deletion of corrupt ref.");
237237
old_sha1 = NULL;
238238
}
239-
if (delete_ref(name, old_sha1)) {
239+
if (delete_ref(name, old_sha1, 0)) {
240240
error("failed to delete %s", name);
241241
return "failed to delete";
242242
}

builtin-remote.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ static int remove_branches(struct string_list *branches)
337337
const char *refname = item->string;
338338
unsigned char *sha1 = item->util;
339339

340-
if (delete_ref(refname, sha1))
340+
if (delete_ref(refname, sha1, 0))
341341
result |= error("Could not remove branch %s", refname);
342342
}
343343
return result;
@@ -565,7 +565,7 @@ static int prune(int argc, const char **argv)
565565
const char *refname = states.stale.items[i].util;
566566

567567
if (!dry_run)
568-
result |= delete_ref(refname, NULL);
568+
result |= delete_ref(refname, NULL, 0);
569569

570570
printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
571571
abbrev_ref(refname, "refs/remotes/"));

builtin-reset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
279279
update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
280280
}
281281
else if (old_orig)
282-
delete_ref("ORIG_HEAD", old_orig);
282+
delete_ref("ORIG_HEAD", old_orig, 0);
283283
prepend_reflog_action("updating HEAD", msg, sizeof(msg));
284284
update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
285285

builtin-send-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
240240
if (args.verbose)
241241
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
242242
if (ref->deletion) {
243-
delete_ref(rs.dst, NULL);
243+
delete_ref(rs.dst, NULL, 0);
244244
} else
245245
update_ref("update by push", rs.dst,
246246
ref->new_sha1, NULL, 0, 0);

builtin-tag.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn)
125125
static int delete_tag(const char *name, const char *ref,
126126
const unsigned char *sha1)
127127
{
128-
if (delete_ref(ref, sha1))
128+
if (delete_ref(ref, sha1, 0))
129129
return 1;
130130
printf("Deleted tag '%s'\n", name);
131131
return 0;

builtin-update-ref.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
1313
{
1414
const char *refname, *oldval, *msg=NULL;
1515
unsigned char sha1[20], oldsha1[20];
16-
int delete = 0, no_deref = 0;
16+
int delete = 0, no_deref = 0, flags = 0;
1717
struct option options[] = {
1818
OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
1919
OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
@@ -47,9 +47,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
4747
if (oldval && *oldval && get_sha1(oldval, oldsha1))
4848
die("%s: not a valid old SHA1", oldval);
4949

50+
if (no_deref)
51+
flags = REF_NODEREF;
5052
if (delete)
51-
return delete_ref(refname, oldval ? oldsha1 : NULL);
53+
return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
5254
else
5355
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
54-
no_deref ? REF_NODEREF : 0, DIE_ON_ERR);
56+
flags, DIE_ON_ERR);
5557
}

cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ extern int commit_locked_index(struct lock_file *);
434434
extern void set_alternate_index_output(const char *);
435435
extern int close_lock_file(struct lock_file *);
436436
extern void rollback_lock_file(struct lock_file *);
437-
extern int delete_ref(const char *, const unsigned char *sha1);
437+
extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
438438

439439
/* Environment bits from configuration mechanism */
440440
extern int trust_executable_bit;

refs.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -921,25 +921,33 @@ static int repack_without_ref(const char *refname)
921921
return commit_lock_file(&packlock);
922922
}
923923

924-
int delete_ref(const char *refname, const unsigned char *sha1)
924+
int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
925925
{
926926
struct ref_lock *lock;
927-
int err, i, ret = 0, flag = 0;
927+
int err, i = 0, ret = 0, flag = 0;
928928

929929
lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
930930
if (!lock)
931931
return 1;
932-
if (!(flag & REF_ISPACKED)) {
932+
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
933933
/* loose */
934-
i = strlen(lock->lk->filename) - 5; /* .lock */
935-
lock->lk->filename[i] = 0;
936-
err = unlink(lock->lk->filename);
934+
const char *path;
935+
936+
if (!(delopt & REF_NODEREF)) {
937+
i = strlen(lock->lk->filename) - 5; /* .lock */
938+
lock->lk->filename[i] = 0;
939+
path = lock->lk->filename;
940+
} else {
941+
path = git_path(refname);
942+
}
943+
err = unlink(path);
937944
if (err && errno != ENOENT) {
938945
ret = 1;
939946
error("unlink(%s) failed: %s",
940-
lock->lk->filename, strerror(errno));
947+
path, strerror(errno));
941948
}
942-
lock->lk->filename[i] = '.';
949+
if (!(delopt & REF_NODEREF))
950+
lock->lk->filename[i] = '.';
943951
}
944952
/* removing the loose one could have resurrected an earlier
945953
* packed one. Also, if it was not loose we need to repack
@@ -964,11 +972,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
964972
struct ref_lock *lock;
965973
struct stat loginfo;
966974
int log = !lstat(git_path("logs/%s", oldref), &loginfo);
975+
const char *symref = NULL;
967976

968-
if (S_ISLNK(loginfo.st_mode))
977+
if (log && S_ISLNK(loginfo.st_mode))
969978
return error("reflog for %s is a symlink", oldref);
970979

971-
if (!resolve_ref(oldref, orig_sha1, 1, &flag))
980+
symref = resolve_ref(oldref, orig_sha1, 1, &flag);
981+
if (flag & REF_ISSYMREF)
982+
return error("refname %s is a symbolic ref, renaming it is not supported",
983+
oldref);
984+
if (!symref)
972985
return error("refname %s not found", oldref);
973986

974987
if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
@@ -988,12 +1001,12 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
9881001
return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
9891002
oldref, strerror(errno));
9901003

991-
if (delete_ref(oldref, orig_sha1)) {
1004+
if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
9921005
error("unable to delete old %s", oldref);
9931006
goto rollback;
9941007
}
9951008

996-
if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) {
1009+
if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
9971010
if (errno==EISDIR) {
9981011
if (remove_empty_directories(git_path("%s", newref))) {
9991012
error("Directory not empty: %s", newref);
@@ -1036,7 +1049,6 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
10361049
error("unable to lock %s for update", newref);
10371050
goto rollback;
10381051
}
1039-
10401052
lock->force_write = 1;
10411053
hashcpy(lock->old_sha1, orig_sha1);
10421054
if (write_ref_sha1(lock, orig_sha1, logmsg)) {

t/t1400-update-ref.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@ test_expect_success "delete $m (by HEAD)" '
7575
'
7676
rm -f .git/$m
7777

78+
cp -f .git/HEAD .git/HEAD.orig
79+
test_expect_success "delete symref without dereference" '
80+
git update-ref --no-deref -d HEAD &&
81+
! test -f .git/HEAD
82+
'
83+
cp -f .git/HEAD.orig .git/HEAD
84+
85+
test_expect_success "delete symref without dereference when the referred ref is packed" '
86+
echo foo >foo.c &&
87+
git add foo.c &&
88+
git commit -m foo &&
89+
git pack-refs --all &&
90+
git update-ref --no-deref -d HEAD &&
91+
! test -f .git/HEAD
92+
'
93+
cp -f .git/HEAD.orig .git/HEAD
94+
git update-ref -d $m
95+
7896
test_expect_success '(not) create HEAD with old sha1' "
7997
test_must_fail git update-ref HEAD $A $B
8098
"

0 commit comments

Comments
 (0)