struct ref_lock *lock;
struct commit *commit;
unsigned char sha1[20];
- char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
+ char *real_ref, msg[PATH_MAX + 20];
+ struct strbuf ref = STRBUF_INIT;
int forcing = 0;
+ int len;
- snprintf(ref, sizeof ref, "refs/heads/%s", name);
- if (check_ref_format(ref))
+ len = strlen(name);
+ if (interpret_nth_last_branch(name, &ref) != len) {
+ strbuf_reset(&ref);
+ strbuf_add(&ref, name, len);
+ }
+ strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
+
+ if (check_ref_format(ref.buf))
die("'%s' is not a valid branch name.", name);
- if (resolve_ref(ref, sha1, 1, NULL)) {
+ if (resolve_ref(ref.buf, sha1, 1, NULL)) {
if (!force)
die("A branch named '%s' already exists.", name);
else if (!is_bare_repository() && !strcmp(head, name))
die("Not a valid branch point: '%s'.", start_name);
hashcpy(sha1, commit->object.sha1);
- lock = lock_any_ref_for_update(ref, NULL, 0);
+ lock = lock_any_ref_for_update(ref.buf, NULL, 0);
if (!lock)
die("Failed to lock ref for update: %s.", strerror(errno));
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
+ strbuf_release(&ref);
free(real_ref);
}
const char *fmt, *remote;
int i;
int ret = 0;
+ struct strbuf bname = STRBUF_INIT;
switch (kinds) {
case REF_REMOTE_BRANCH:
if (!head_rev)
die("Couldn't look up commit object for HEAD");
}
- for (i = 0; i < argc; i++) {
- if (kinds == REF_LOCAL_BRANCH && !strcmp(head, argv[i])) {
+ for (i = 0; i < argc; i++, strbuf_release(&bname)) {
+ int len = strlen(argv[i]);
+
+ if (interpret_nth_last_branch(argv[i], &bname) != len)
+ strbuf_add(&bname, argv[i], len);
+
+ if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
error("Cannot delete the branch '%s' "
- "which you are currently on.", argv[i]);
+ "which you are currently on.", bname.buf);
ret = 1;
continue;
}
free(name);
- name = xstrdup(mkpath(fmt, argv[i]));
+ name = xstrdup(mkpath(fmt, bname.buf));
if (!resolve_ref(name, sha1, 1, NULL)) {
error("%sbranch '%s' not found.",
- remote, argv[i]);
+ remote, bname.buf);
ret = 1;
continue;
}
if (!force &&
!in_merge_bases(rev, &head_rev, 1)) {
error("The branch '%s' is not an ancestor of "
- "your current HEAD.\n"
- "If you are sure you want to delete it, "
- "run 'git branch -D %s'.", argv[i], argv[i]);
+ "your current HEAD.\n"
+ "If you are sure you want to delete it, "
+ "run 'git branch -D %s'.", bname.buf, bname.buf);
ret = 1;
continue;
}
if (delete_ref(name, sha1, 0)) {
error("Error deleting %sbranch '%s'", remote,
- argv[i]);
+ bname.buf);
ret = 1;
} else {
struct strbuf buf = STRBUF_INIT;
- printf("Deleted %sbranch %s (%s).\n", remote, argv[i],
- find_unique_abbrev(sha1, DEFAULT_ABBREV));
- strbuf_addf(&buf, "branch.%s", argv[i]);
+ printf("Deleted %sbranch %s (%s).\n", remote,
+ bname.buf,
+ find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ strbuf_addf(&buf, "branch.%s", bname.buf);
if (git_config_rename_section(buf.buf, NULL) < 0)
warning("Update of config-file failed");
strbuf_release(&buf);
--- /dev/null
+#!/bin/sh
+
+test_description='previous branch syntax @{-n}'
+
+. ./test-lib.sh
+
+test_expect_success 'branch -d @{-1}' '
+ test_commit A &&
+ git checkout -b junk &&
+ git checkout - &&
+ test "$(git symbolic-ref HEAD)" = refs/heads/master &&
+ git branch -d @{-1} &&
+ test_must_fail git rev-parse --verify refs/heads/junk
+'
+
+test_expect_success 'branch -d @{-12} when there is not enough switches yet' '
+ git reflog expire --expire=now &&
+ git checkout -b junk2 &&
+ git checkout - &&
+ test "$(git symbolic-ref HEAD)" = refs/heads/master &&
+ test_must_fail git branch -d @{-12} &&
+ git rev-parse --verify refs/heads/master
+'
+
+test_done
+