Teach the "@{-1} syntax to "git branch"
This teaches the new "@{-1} syntax to refer to the previous branch to "git branch". After looking at somebody's faulty patch series on a topic branch too long, if you decide it is not worth merging, you can just say: $ git checkout master $ git branch -D @{-1} to get rid of it without having to type the name of the topic you now hate so much for wasting a lot of your time. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Feb 13, 2009 at 23:08 UTC
8415d5c7ef63237f6efab0c9aef0b0fdbcbfda25
3 files changed
+59
-17
branch.c
+14
-5
@@ -103,14 +103,22 @@ void create_branch(const char *head,
103
struct ref_lock *lock;
104
struct commit *commit;
105
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;
108
int forcing = 0;
109
+ int len;
110
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))
119
die("'%s' is not a valid branch name.", name);
120
113
- if (resolve_ref(ref, sha1, 1, NULL)) {
121
+ if (resolve_ref(ref.buf, sha1, 1, NULL)) {
122
if (!force)
123
die("A branch named '%s' already exists.", name);
124
else if (!is_bare_repository() && !strcmp(head, name))
@@ -142,7 +150,7 @@ void create_branch(const char *head,
150
die("Not a valid branch point: '%s'.", start_name);
151
hashcpy(sha1, commit->object.sha1);
152
145
- lock = lock_any_ref_for_update(ref, NULL, 0);
153
+ lock = lock_any_ref_for_update(ref.buf, NULL, 0);
154
if (!lock)
155
die("Failed to lock ref for update: %s.", strerror(errno));
156
@@ -162,6 +170,7 @@ void create_branch(const char *head,
170
if (write_ref_sha1(lock, sha1, msg) < 0)
171
die("Failed to write ref: %s.", strerror(errno));
172
173
+ strbuf_release(&ref);
174
free(real_ref);
175
}
176
builtin-branch.c
+19
-12
@@ -99,6 +99,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
99
const char *fmt, *remote;
100
int i;
101
int ret = 0;
102
+ struct strbuf bname = STRBUF_INIT;
103
104
switch (kinds) {
105
case REF_REMOTE_BRANCH:
@@ -119,20 +120,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
120
if (!head_rev)
121
die("Couldn't look up commit object for HEAD");
122
}
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)) {
130
error("Cannot delete the branch '%s' "
125
- "which you are currently on.", argv[i]);
131
+ "which you are currently on.", bname.buf);
132
ret = 1;
133
continue;
134
}
135
136
free(name);
137
132
- name = xstrdup(mkpath(fmt, argv[i]));
138
+ name = xstrdup(mkpath(fmt, bname.buf));
139
if (!resolve_ref(name, sha1, 1, NULL)) {
140
error("%sbranch '%s' not found.",
135
- remote, argv[i]);
141
+ remote, bname.buf);
142
ret = 1;
143
continue;
144
}
@@ -152,22 +158,23 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
158
if (!force &&
159
!in_merge_bases(rev, &head_rev, 1)) {
160
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);
164
ret = 1;
165
continue;
166
}
167
168
if (delete_ref(name, sha1, 0)) {
169
error("Error deleting %sbranch '%s'", remote,
164
- argv[i]);
170
+ bname.buf);
171
ret = 1;
172
} else {
173
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);
178
if (git_config_rename_section(buf.buf, NULL) < 0)
179
warning("Update of config-file failed");
180
strbuf_release(&buf);
t/t0100-previous.sh
new
+26
@@ -0,0 +1,26 @@
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_done
26
+