mirror of
https://github.com/git/git
synced 2024-08-28 20:20:07 +00:00
Merge branch 'mv/maint-branch-m-symref' into maint
* 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.
This commit is contained in:
commit
3b8572a429
|
@ -160,7 +160,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delete_ref(name, sha1)) {
|
if (delete_ref(name, sha1, 0)) {
|
||||||
error("Error deleting %sbranch '%s'", remote,
|
error("Error deleting %sbranch '%s'", remote,
|
||||||
argv[i]);
|
argv[i]);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
|
@ -340,7 +340,7 @@ static int remove_branches(struct string_list *branches)
|
||||||
const char *refname = item->string;
|
const char *refname = item->string;
|
||||||
unsigned char *sha1 = item->util;
|
unsigned char *sha1 = item->util;
|
||||||
|
|
||||||
if (delete_ref(refname, sha1))
|
if (delete_ref(refname, sha1, 0))
|
||||||
result |= error("Could not remove branch %s", refname);
|
result |= error("Could not remove branch %s", refname);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -570,7 +570,7 @@ static int prune(int argc, const char **argv)
|
||||||
const char *refname = states.stale.items[i].util;
|
const char *refname = states.stale.items[i].util;
|
||||||
|
|
||||||
if (!dry_run)
|
if (!dry_run)
|
||||||
result |= delete_ref(refname, NULL);
|
result |= delete_ref(refname, NULL, 0);
|
||||||
|
|
||||||
printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
|
printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
|
||||||
abbrev_ref(refname, "refs/remotes/"));
|
abbrev_ref(refname, "refs/remotes/"));
|
||||||
|
|
|
@ -279,7 +279,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||||
update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
|
update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
|
||||||
}
|
}
|
||||||
else if (old_orig)
|
else if (old_orig)
|
||||||
delete_ref("ORIG_HEAD", old_orig);
|
delete_ref("ORIG_HEAD", old_orig, 0);
|
||||||
prepend_reflog_action("updating HEAD", msg, sizeof(msg));
|
prepend_reflog_action("updating HEAD", msg, sizeof(msg));
|
||||||
update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
|
update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
|
||||||
if (args.verbose)
|
if (args.verbose)
|
||||||
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
|
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
|
||||||
if (ref->deletion) {
|
if (ref->deletion) {
|
||||||
delete_ref(rs.dst, NULL);
|
delete_ref(rs.dst, NULL, 0);
|
||||||
} else
|
} else
|
||||||
update_ref("update by push", rs.dst,
|
update_ref("update by push", rs.dst,
|
||||||
ref->new_sha1, NULL, 0, 0);
|
ref->new_sha1, NULL, 0, 0);
|
||||||
|
|
|
@ -125,7 +125,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn)
|
||||||
static int delete_tag(const char *name, const char *ref,
|
static int delete_tag(const char *name, const char *ref,
|
||||||
const unsigned char *sha1)
|
const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
if (delete_ref(ref, sha1))
|
if (delete_ref(ref, sha1, 0))
|
||||||
return 1;
|
return 1;
|
||||||
printf("Deleted tag '%s'\n", name);
|
printf("Deleted tag '%s'\n", name);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -13,7 +13,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
const char *refname, *oldval, *msg=NULL;
|
const char *refname, *oldval, *msg=NULL;
|
||||||
unsigned char sha1[20], oldsha1[20];
|
unsigned char sha1[20], oldsha1[20];
|
||||||
int delete = 0, no_deref = 0;
|
int delete = 0, no_deref = 0, flags = 0;
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
|
OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
|
||||||
OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
|
OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
|
||||||
|
@ -47,9 +47,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
if (oldval && *oldval && get_sha1(oldval, oldsha1))
|
if (oldval && *oldval && get_sha1(oldval, oldsha1))
|
||||||
die("%s: not a valid old SHA1", oldval);
|
die("%s: not a valid old SHA1", oldval);
|
||||||
|
|
||||||
|
if (no_deref)
|
||||||
|
flags = REF_NODEREF;
|
||||||
if (delete)
|
if (delete)
|
||||||
return delete_ref(refname, oldval ? oldsha1 : NULL);
|
return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
|
||||||
else
|
else
|
||||||
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
|
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
|
||||||
no_deref ? REF_NODEREF : 0, DIE_ON_ERR);
|
flags, DIE_ON_ERR);
|
||||||
}
|
}
|
||||||
|
|
2
cache.h
2
cache.h
|
@ -424,7 +424,7 @@ extern int commit_locked_index(struct lock_file *);
|
||||||
extern void set_alternate_index_output(const char *);
|
extern void set_alternate_index_output(const char *);
|
||||||
extern int close_lock_file(struct lock_file *);
|
extern int close_lock_file(struct lock_file *);
|
||||||
extern void rollback_lock_file(struct lock_file *);
|
extern void rollback_lock_file(struct lock_file *);
|
||||||
extern int delete_ref(const char *, const unsigned char *sha1);
|
extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
|
||||||
|
|
||||||
/* Environment bits from configuration mechanism */
|
/* Environment bits from configuration mechanism */
|
||||||
extern int trust_executable_bit;
|
extern int trust_executable_bit;
|
||||||
|
|
|
@ -222,7 +222,7 @@ static const char *update(struct command *cmd)
|
||||||
warning ("Allowing deletion of corrupt ref.");
|
warning ("Allowing deletion of corrupt ref.");
|
||||||
old_sha1 = NULL;
|
old_sha1 = NULL;
|
||||||
}
|
}
|
||||||
if (delete_ref(name, old_sha1)) {
|
if (delete_ref(name, old_sha1, 0)) {
|
||||||
error("failed to delete %s", name);
|
error("failed to delete %s", name);
|
||||||
return "failed to delete";
|
return "failed to delete";
|
||||||
}
|
}
|
||||||
|
|
38
refs.c
38
refs.c
|
@ -915,25 +915,33 @@ static int repack_without_ref(const char *refname)
|
||||||
return commit_lock_file(&packlock);
|
return commit_lock_file(&packlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int delete_ref(const char *refname, const unsigned char *sha1)
|
int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
|
||||||
{
|
{
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
int err, i, ret = 0, flag = 0;
|
int err, i = 0, ret = 0, flag = 0;
|
||||||
|
|
||||||
lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
|
lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
|
||||||
if (!lock)
|
if (!lock)
|
||||||
return 1;
|
return 1;
|
||||||
if (!(flag & REF_ISPACKED)) {
|
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
|
||||||
/* loose */
|
/* loose */
|
||||||
i = strlen(lock->lk->filename) - 5; /* .lock */
|
const char *path;
|
||||||
lock->lk->filename[i] = 0;
|
|
||||||
err = unlink(lock->lk->filename);
|
if (!(delopt & REF_NODEREF)) {
|
||||||
|
i = strlen(lock->lk->filename) - 5; /* .lock */
|
||||||
|
lock->lk->filename[i] = 0;
|
||||||
|
path = lock->lk->filename;
|
||||||
|
} else {
|
||||||
|
path = git_path(refname);
|
||||||
|
}
|
||||||
|
err = unlink(path);
|
||||||
if (err && errno != ENOENT) {
|
if (err && errno != ENOENT) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
error("unlink(%s) failed: %s",
|
error("unlink(%s) failed: %s",
|
||||||
lock->lk->filename, strerror(errno));
|
path, strerror(errno));
|
||||||
}
|
}
|
||||||
lock->lk->filename[i] = '.';
|
if (!(delopt & REF_NODEREF))
|
||||||
|
lock->lk->filename[i] = '.';
|
||||||
}
|
}
|
||||||
/* removing the loose one could have resurrected an earlier
|
/* removing the loose one could have resurrected an earlier
|
||||||
* packed one. Also, if it was not loose we need to repack
|
* packed one. Also, if it was not loose we need to repack
|
||||||
|
@ -958,11 +966,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
struct stat loginfo;
|
struct stat loginfo;
|
||||||
int log = !lstat(git_path("logs/%s", oldref), &loginfo);
|
int log = !lstat(git_path("logs/%s", oldref), &loginfo);
|
||||||
|
const char *symref = NULL;
|
||||||
|
|
||||||
if (S_ISLNK(loginfo.st_mode))
|
if (log && S_ISLNK(loginfo.st_mode))
|
||||||
return error("reflog for %s is a symlink", oldref);
|
return error("reflog for %s is a symlink", oldref);
|
||||||
|
|
||||||
if (!resolve_ref(oldref, orig_sha1, 1, &flag))
|
symref = resolve_ref(oldref, orig_sha1, 1, &flag);
|
||||||
|
if (flag & REF_ISSYMREF)
|
||||||
|
return error("refname %s is a symbolic ref, renaming it is not supported",
|
||||||
|
oldref);
|
||||||
|
if (!symref)
|
||||||
return error("refname %s not found", oldref);
|
return error("refname %s not found", oldref);
|
||||||
|
|
||||||
if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
|
if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
|
||||||
|
@ -982,12 +995,12 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
|
||||||
return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
|
return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
|
||||||
oldref, strerror(errno));
|
oldref, strerror(errno));
|
||||||
|
|
||||||
if (delete_ref(oldref, orig_sha1)) {
|
if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
|
||||||
error("unable to delete old %s", oldref);
|
error("unable to delete old %s", oldref);
|
||||||
goto rollback;
|
goto rollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) {
|
if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
|
||||||
if (errno==EISDIR) {
|
if (errno==EISDIR) {
|
||||||
if (remove_empty_directories(git_path("%s", newref))) {
|
if (remove_empty_directories(git_path("%s", newref))) {
|
||||||
error("Directory not empty: %s", newref);
|
error("Directory not empty: %s", newref);
|
||||||
|
@ -1030,7 +1043,6 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
|
||||||
error("unable to lock %s for update", newref);
|
error("unable to lock %s for update", newref);
|
||||||
goto rollback;
|
goto rollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock->force_write = 1;
|
lock->force_write = 1;
|
||||||
hashcpy(lock->old_sha1, orig_sha1);
|
hashcpy(lock->old_sha1, orig_sha1);
|
||||||
if (write_ref_sha1(lock, orig_sha1, logmsg)) {
|
if (write_ref_sha1(lock, orig_sha1, logmsg)) {
|
||||||
|
|
|
@ -75,6 +75,24 @@ test_expect_success "delete $m (by HEAD)" '
|
||||||
'
|
'
|
||||||
rm -f .git/$m
|
rm -f .git/$m
|
||||||
|
|
||||||
|
cp -f .git/HEAD .git/HEAD.orig
|
||||||
|
test_expect_success "delete symref without dereference" '
|
||||||
|
git update-ref --no-deref -d HEAD &&
|
||||||
|
! test -f .git/HEAD
|
||||||
|
'
|
||||||
|
cp -f .git/HEAD.orig .git/HEAD
|
||||||
|
|
||||||
|
test_expect_success "delete symref without dereference when the referred ref is packed" '
|
||||||
|
echo foo >foo.c &&
|
||||||
|
git add foo.c &&
|
||||||
|
git commit -m foo &&
|
||||||
|
git pack-refs --all &&
|
||||||
|
git update-ref --no-deref -d HEAD &&
|
||||||
|
! test -f .git/HEAD
|
||||||
|
'
|
||||||
|
cp -f .git/HEAD.orig .git/HEAD
|
||||||
|
git update-ref -d $m
|
||||||
|
|
||||||
test_expect_success '(not) create HEAD with old sha1' "
|
test_expect_success '(not) create HEAD with old sha1' "
|
||||||
test_must_fail git update-ref HEAD $A $B
|
test_must_fail git update-ref HEAD $A $B
|
||||||
"
|
"
|
||||||
|
|
|
@ -112,6 +112,15 @@ test_expect_success 'config information was renamed, too' \
|
||||||
"test $(git config branch.s.dummy) = Hello &&
|
"test $(git config branch.s.dummy) = Hello &&
|
||||||
test_must_fail git config branch.s/s/dummy"
|
test_must_fail git config branch.s/s/dummy"
|
||||||
|
|
||||||
|
test_expect_success 'renaming a symref is not allowed' \
|
||||||
|
'
|
||||||
|
git symbolic-ref refs/heads/master2 refs/heads/master &&
|
||||||
|
test_must_fail git branch -m master2 master3 &&
|
||||||
|
git symbolic-ref refs/heads/master2 &&
|
||||||
|
test -f .git/refs/heads/master &&
|
||||||
|
! test -f .git/refs/heads/master3
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'git branch -m u v should fail when the reflog for u is a symlink' '
|
'git branch -m u v should fail when the reflog for u is a symlink' '
|
||||||
git branch -l u &&
|
git branch -l u &&
|
||||||
|
|
Loading…
Reference in a new issue