Merge branch 'jc/branch-previous'
* jc/branch-previous: Teach @{-1} to git merge Teach the "@{-1} syntax to "git branch"maint
commit
472e4744ad
19
branch.c
19
branch.c
|
@ -103,14 +103,22 @@ void create_branch(const char *head,
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
unsigned char sha1[20];
|
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 forcing = 0;
|
||||||
|
int len;
|
||||||
|
|
||||||
snprintf(ref, sizeof ref, "refs/heads/%s", name);
|
len = strlen(name);
|
||||||
if (check_ref_format(ref))
|
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);
|
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)
|
if (!force)
|
||||||
die("A branch named '%s' already exists.", name);
|
die("A branch named '%s' already exists.", name);
|
||||||
else if (!is_bare_repository() && !strcmp(head, name))
|
else if (!is_bare_repository() && !strcmp(head, name))
|
||||||
|
@ -142,7 +150,7 @@ void create_branch(const char *head,
|
||||||
die("Not a valid branch point: '%s'.", start_name);
|
die("Not a valid branch point: '%s'.", start_name);
|
||||||
hashcpy(sha1, commit->object.sha1);
|
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)
|
if (!lock)
|
||||||
die("Failed to lock ref for update: %s.", strerror(errno));
|
die("Failed to lock ref for update: %s.", strerror(errno));
|
||||||
|
|
||||||
|
@ -162,6 +170,7 @@ void create_branch(const char *head,
|
||||||
if (write_ref_sha1(lock, sha1, msg) < 0)
|
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||||
die("Failed to write ref: %s.", strerror(errno));
|
die("Failed to write ref: %s.", strerror(errno));
|
||||||
|
|
||||||
|
strbuf_release(&ref);
|
||||||
free(real_ref);
|
free(real_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
|
||||||
const char *fmt, *remote;
|
const char *fmt, *remote;
|
||||||
int i;
|
int i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct strbuf bname = STRBUF_INIT;
|
||||||
|
|
||||||
switch (kinds) {
|
switch (kinds) {
|
||||||
case REF_REMOTE_BRANCH:
|
case REF_REMOTE_BRANCH:
|
||||||
|
@ -119,20 +120,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
|
||||||
if (!head_rev)
|
if (!head_rev)
|
||||||
die("Couldn't look up commit object for HEAD");
|
die("Couldn't look up commit object for HEAD");
|
||||||
}
|
}
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
|
||||||
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, argv[i])) {
|
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' "
|
error("Cannot delete the branch '%s' "
|
||||||
"which you are currently on.", argv[i]);
|
"which you are currently on.", bname.buf);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
name = xstrdup(mkpath(fmt, argv[i]));
|
name = xstrdup(mkpath(fmt, bname.buf));
|
||||||
if (!resolve_ref(name, sha1, 1, NULL)) {
|
if (!resolve_ref(name, sha1, 1, NULL)) {
|
||||||
error("%sbranch '%s' not found.",
|
error("%sbranch '%s' not found.",
|
||||||
remote, argv[i]);
|
remote, bname.buf);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -154,20 +160,21 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
|
||||||
error("The branch '%s' is not an ancestor of "
|
error("The branch '%s' is not an ancestor of "
|
||||||
"your current HEAD.\n"
|
"your current HEAD.\n"
|
||||||
"If you are sure you want to delete it, "
|
"If you are sure you want to delete it, "
|
||||||
"run 'git branch -D %s'.", argv[i], argv[i]);
|
"run 'git branch -D %s'.", bname.buf, bname.buf);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delete_ref(name, sha1, 0)) {
|
if (delete_ref(name, sha1, 0)) {
|
||||||
error("Error deleting %sbranch '%s'", remote,
|
error("Error deleting %sbranch '%s'", remote,
|
||||||
argv[i]);
|
bname.buf);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
printf("Deleted %sbranch %s (%s).\n", remote, argv[i],
|
printf("Deleted %sbranch %s (%s).\n", remote,
|
||||||
|
bname.buf,
|
||||||
find_unique_abbrev(sha1, DEFAULT_ABBREV));
|
find_unique_abbrev(sha1, DEFAULT_ABBREV));
|
||||||
strbuf_addf(&buf, "branch.%s", argv[i]);
|
strbuf_addf(&buf, "branch.%s", bname.buf);
|
||||||
if (git_config_rename_section(buf.buf, NULL) < 0)
|
if (git_config_rename_section(buf.buf, NULL) < 0)
|
||||||
warning("Update of config-file failed");
|
warning("Update of config-file failed");
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
|
|
|
@ -356,9 +356,14 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
||||||
struct object *remote_head;
|
struct object *remote_head;
|
||||||
unsigned char branch_head[20], buf_sha[20];
|
unsigned char branch_head[20], buf_sha[20];
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
struct strbuf bname = STRBUF_INIT;
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
int len, early;
|
int len, early;
|
||||||
|
|
||||||
|
len = strlen(remote);
|
||||||
|
if (interpret_nth_last_branch(remote, &bname) == len)
|
||||||
|
remote = bname.buf;
|
||||||
|
|
||||||
memset(branch_head, 0, sizeof(branch_head));
|
memset(branch_head, 0, sizeof(branch_head));
|
||||||
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
|
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
|
||||||
if (!remote_head)
|
if (!remote_head)
|
||||||
|
@ -371,7 +376,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
||||||
if (!hashcmp(remote_head->sha1, branch_head)) {
|
if (!hashcmp(remote_head->sha1, branch_head)) {
|
||||||
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
|
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
|
||||||
sha1_to_hex(branch_head), remote);
|
sha1_to_hex(branch_head), remote);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if remote matches <name>^^^.. or <name>~<number> */
|
/* See if remote matches <name>^^^.. or <name>~<number> */
|
||||||
|
@ -411,7 +416,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
||||||
sha1_to_hex(remote_head->sha1),
|
sha1_to_hex(remote_head->sha1),
|
||||||
truname.buf + 11,
|
truname.buf + 11,
|
||||||
(early ? " (early part)" : ""));
|
(early ? " (early part)" : ""));
|
||||||
return;
|
strbuf_release(&truname);
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,10 +438,13 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
||||||
strbuf_remove(&line, ptr-line.buf+1, 13);
|
strbuf_remove(&line, ptr-line.buf+1, 13);
|
||||||
strbuf_addbuf(msg, &line);
|
strbuf_addbuf(msg, &line);
|
||||||
strbuf_release(&line);
|
strbuf_release(&line);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
|
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
|
||||||
sha1_to_hex(remote_head->sha1), remote);
|
sha1_to_hex(remote_head->sha1), remote);
|
||||||
|
cleanup:
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&bname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int git_merge_config(const char *k, const char *v, void *cb)
|
static int git_merge_config(const char *k, const char *v, void *cb)
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/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_expect_success 'merge @{-1}' '
|
||||||
|
git checkout A &&
|
||||||
|
test_commit B &&
|
||||||
|
git checkout A &&
|
||||||
|
test_commit C &&
|
||||||
|
git branch -f master B &&
|
||||||
|
git branch -f other &&
|
||||||
|
git checkout other &&
|
||||||
|
git checkout master &&
|
||||||
|
git merge @{-1} &&
|
||||||
|
git cat-file commit HEAD | grep "Merge branch '\''other'\''"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'merge @{-1} when there is not enough switches yet' '
|
||||||
|
git reflog expire --expire=now &&
|
||||||
|
git checkout -f master &&
|
||||||
|
git reset --hard B &&
|
||||||
|
git branch -f other C &&
|
||||||
|
git checkout other &&
|
||||||
|
git checkout master &&
|
||||||
|
test_must_fail git merge @{-12}
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
||||||
|
|
Loading…
Reference in New Issue