Skip to content

Commit 472e474

Browse files
committed
Merge branch 'jc/branch-previous'
* jc/branch-previous: Teach @{-1} to git merge Teach the "@{-1} syntax to "git branch"
2 parents 48c9ab7 + c9717ee commit 472e474

File tree

4 files changed

+94
-20
lines changed

4 files changed

+94
-20
lines changed

branch.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,22 @@ void create_branch(const char *head,
103103
struct ref_lock *lock;
104104
struct commit *commit;
105105
unsigned char sha1[20];
106-
char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
106+
char *real_ref, msg[PATH_MAX + 20];
107+
struct strbuf ref = STRBUF_INIT;
107108
int forcing = 0;
109+
int len;
108110

109-
snprintf(ref, sizeof ref, "refs/heads/%s", name);
110-
if (check_ref_format(ref))
111+
len = strlen(name);
112+
if (interpret_nth_last_branch(name, &ref) != len) {
113+
strbuf_reset(&ref);
114+
strbuf_add(&ref, name, len);
115+
}
116+
strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
117+
118+
if (check_ref_format(ref.buf))
111119
die("'%s' is not a valid branch name.", name);
112120

113-
if (resolve_ref(ref, sha1, 1, NULL)) {
121+
if (resolve_ref(ref.buf, sha1, 1, NULL)) {
114122
if (!force)
115123
die("A branch named '%s' already exists.", name);
116124
else if (!is_bare_repository() && !strcmp(head, name))
@@ -142,7 +150,7 @@ void create_branch(const char *head,
142150
die("Not a valid branch point: '%s'.", start_name);
143151
hashcpy(sha1, commit->object.sha1);
144152

145-
lock = lock_any_ref_for_update(ref, NULL, 0);
153+
lock = lock_any_ref_for_update(ref.buf, NULL, 0);
146154
if (!lock)
147155
die("Failed to lock ref for update: %s.", strerror(errno));
148156

@@ -162,6 +170,7 @@ void create_branch(const char *head,
162170
if (write_ref_sha1(lock, sha1, msg) < 0)
163171
die("Failed to write ref: %s.", strerror(errno));
164172

173+
strbuf_release(&ref);
165174
free(real_ref);
166175
}
167176

builtin-branch.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
9999
const char *fmt, *remote;
100100
int i;
101101
int ret = 0;
102+
struct strbuf bname = STRBUF_INIT;
102103

103104
switch (kinds) {
104105
case REF_REMOTE_BRANCH:
@@ -119,20 +120,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
119120
if (!head_rev)
120121
die("Couldn't look up commit object for HEAD");
121122
}
122-
for (i = 0; i < argc; i++) {
123-
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, argv[i])) {
123+
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
124+
int len = strlen(argv[i]);
125+
126+
if (interpret_nth_last_branch(argv[i], &bname) != len)
127+
strbuf_add(&bname, argv[i], len);
128+
129+
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
124130
error("Cannot delete the branch '%s' "
125-
"which you are currently on.", argv[i]);
131+
"which you are currently on.", bname.buf);
126132
ret = 1;
127133
continue;
128134
}
129135

130136
free(name);
131137

132-
name = xstrdup(mkpath(fmt, argv[i]));
138+
name = xstrdup(mkpath(fmt, bname.buf));
133139
if (!resolve_ref(name, sha1, 1, NULL)) {
134140
error("%sbranch '%s' not found.",
135-
remote, argv[i]);
141+
remote, bname.buf);
136142
ret = 1;
137143
continue;
138144
}
@@ -152,22 +158,23 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
152158
if (!force &&
153159
!in_merge_bases(rev, &head_rev, 1)) {
154160
error("The branch '%s' is not an ancestor of "
155-
"your current HEAD.\n"
156-
"If you are sure you want to delete it, "
157-
"run 'git branch -D %s'.", argv[i], argv[i]);
161+
"your current HEAD.\n"
162+
"If you are sure you want to delete it, "
163+
"run 'git branch -D %s'.", bname.buf, bname.buf);
158164
ret = 1;
159165
continue;
160166
}
161167

162168
if (delete_ref(name, sha1, 0)) {
163169
error("Error deleting %sbranch '%s'", remote,
164-
argv[i]);
170+
bname.buf);
165171
ret = 1;
166172
} else {
167173
struct strbuf buf = STRBUF_INIT;
168-
printf("Deleted %sbranch %s (%s).\n", remote, argv[i],
169-
find_unique_abbrev(sha1, DEFAULT_ABBREV));
170-
strbuf_addf(&buf, "branch.%s", argv[i]);
174+
printf("Deleted %sbranch %s (%s).\n", remote,
175+
bname.buf,
176+
find_unique_abbrev(sha1, DEFAULT_ABBREV));
177+
strbuf_addf(&buf, "branch.%s", bname.buf);
171178
if (git_config_rename_section(buf.buf, NULL) < 0)
172179
warning("Update of config-file failed");
173180
strbuf_release(&buf);

builtin-merge.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,14 @@ static void merge_name(const char *remote, struct strbuf *msg)
356356
struct object *remote_head;
357357
unsigned char branch_head[20], buf_sha[20];
358358
struct strbuf buf = STRBUF_INIT;
359+
struct strbuf bname = STRBUF_INIT;
359360
const char *ptr;
360361
int len, early;
361362

363+
len = strlen(remote);
364+
if (interpret_nth_last_branch(remote, &bname) == len)
365+
remote = bname.buf;
366+
362367
memset(branch_head, 0, sizeof(branch_head));
363368
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
364369
if (!remote_head)
@@ -371,7 +376,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
371376
if (!hashcmp(remote_head->sha1, branch_head)) {
372377
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
373378
sha1_to_hex(branch_head), remote);
374-
return;
379+
goto cleanup;
375380
}
376381

377382
/* See if remote matches <name>^^^.. or <name>~<number> */
@@ -411,7 +416,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
411416
sha1_to_hex(remote_head->sha1),
412417
truname.buf + 11,
413418
(early ? " (early part)" : ""));
414-
return;
419+
strbuf_release(&truname);
420+
goto cleanup;
415421
}
416422
}
417423

@@ -432,10 +438,13 @@ static void merge_name(const char *remote, struct strbuf *msg)
432438
strbuf_remove(&line, ptr-line.buf+1, 13);
433439
strbuf_addbuf(msg, &line);
434440
strbuf_release(&line);
435-
return;
441+
goto cleanup;
436442
}
437443
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
438444
sha1_to_hex(remote_head->sha1), remote);
445+
cleanup:
446+
strbuf_release(&buf);
447+
strbuf_release(&bname);
439448
}
440449

441450
static int git_merge_config(const char *k, const char *v, void *cb)

t/t0100-previous.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/bin/sh
2+
3+
test_description='previous branch syntax @{-n}'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'branch -d @{-1}' '
8+
test_commit A &&
9+
git checkout -b junk &&
10+
git checkout - &&
11+
test "$(git symbolic-ref HEAD)" = refs/heads/master &&
12+
git branch -d @{-1} &&
13+
test_must_fail git rev-parse --verify refs/heads/junk
14+
'
15+
16+
test_expect_success 'branch -d @{-12} when there is not enough switches yet' '
17+
git reflog expire --expire=now &&
18+
git checkout -b junk2 &&
19+
git checkout - &&
20+
test "$(git symbolic-ref HEAD)" = refs/heads/master &&
21+
test_must_fail git branch -d @{-12} &&
22+
git rev-parse --verify refs/heads/master
23+
'
24+
25+
test_expect_success 'merge @{-1}' '
26+
git checkout A &&
27+
test_commit B &&
28+
git checkout A &&
29+
test_commit C &&
30+
git branch -f master B &&
31+
git branch -f other &&
32+
git checkout other &&
33+
git checkout master &&
34+
git merge @{-1} &&
35+
git cat-file commit HEAD | grep "Merge branch '\''other'\''"
36+
'
37+
38+
test_expect_success 'merge @{-1} when there is not enough switches yet' '
39+
git reflog expire --expire=now &&
40+
git checkout -f master &&
41+
git reset --hard B &&
42+
git branch -f other C &&
43+
git checkout other &&
44+
git checkout master &&
45+
test_must_fail git merge @{-12}
46+
'
47+
48+
test_done
49+

0 commit comments

Comments
 (0)