Skip to content

Commit 9c50374

Browse files
committed
Merge branch 'rs/branch-del-symref'
A symbolic ref refs/heads/SYM was not correctly removed with "git branch -d SYM"; the command removed the ref pointed by SYM instead. * rs/branch-del-symref: branch: show targets of deleted symrefs, not sha1s branch: skip commit checks when deleting symref branches branch: delete symref branch, not its target branch: factor out delete_branch_config() branch: factor out check_branch_commit()
2 parents eeb2535 + 13baa9f commit 9c50374

File tree

2 files changed

+68
-26
lines changed

2 files changed

+68
-26
lines changed

builtin/branch.c

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,37 @@ static int branch_merged(int kind, const char *name,
154154
return merged;
155155
}
156156

157+
static int check_branch_commit(const char *branchname, const char *refname,
158+
unsigned char *sha1, struct commit *head_rev,
159+
int kinds, int force)
160+
{
161+
struct commit *rev = lookup_commit_reference(sha1);
162+
if (!rev) {
163+
error(_("Couldn't look up commit object for '%s'"), refname);
164+
return -1;
165+
}
166+
if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
167+
error(_("The branch '%s' is not fully merged.\n"
168+
"If you are sure you want to delete it, "
169+
"run 'git branch -D %s'."), branchname, branchname);
170+
return -1;
171+
}
172+
return 0;
173+
}
174+
175+
static void delete_branch_config(const char *branchname)
176+
{
177+
struct strbuf buf = STRBUF_INIT;
178+
strbuf_addf(&buf, "branch.%s", branchname);
179+
if (git_config_rename_section(buf.buf, NULL) < 0)
180+
warning(_("Update of config-file failed"));
181+
strbuf_release(&buf);
182+
}
183+
157184
static int delete_branches(int argc, const char **argv, int force, int kinds,
158185
int quiet)
159186
{
160-
struct commit *rev, *head_rev = NULL;
187+
struct commit *head_rev = NULL;
161188
unsigned char sha1[20];
162189
char *name = NULL;
163190
const char *fmt;
@@ -187,6 +214,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
187214
die(_("Couldn't look up commit object for HEAD"));
188215
}
189216
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
217+
const char *target;
218+
int flags = 0;
219+
190220
strbuf_branchname(&bname, argv[i]);
191221
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
192222
error(_("Cannot delete the branch '%s' "
@@ -198,48 +228,41 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
198228
free(name);
199229

200230
name = mkpathdup(fmt, bname.buf);
201-
if (read_ref(name, sha1)) {
231+
target = resolve_ref_unsafe(name, sha1, 0, &flags);
232+
if (!target ||
233+
(!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
202234
error(remote_branch
203235
? _("remote branch '%s' not found.")
204236
: _("branch '%s' not found."), bname.buf);
205237
ret = 1;
206238
continue;
207239
}
208240

209-
rev = lookup_commit_reference(sha1);
210-
if (!rev) {
211-
error(_("Couldn't look up commit object for '%s'"), name);
212-
ret = 1;
213-
continue;
214-
}
215-
216-
if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
217-
error(_("The branch '%s' is not fully merged.\n"
218-
"If you are sure you want to delete it, "
219-
"run 'git branch -D %s'."), bname.buf, bname.buf);
241+
if (!(flags & REF_ISSYMREF) &&
242+
check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
243+
force)) {
220244
ret = 1;
221245
continue;
222246
}
223247

224-
if (delete_ref(name, sha1, 0)) {
248+
if (delete_ref(name, sha1, REF_NODEREF)) {
225249
error(remote_branch
226250
? _("Error deleting remote branch '%s'")
227251
: _("Error deleting branch '%s'"),
228252
bname.buf);
229253
ret = 1;
230-
} else {
231-
struct strbuf buf = STRBUF_INIT;
232-
if (!quiet)
233-
printf(remote_branch
234-
? _("Deleted remote branch %s (was %s).\n")
235-
: _("Deleted branch %s (was %s).\n"),
236-
bname.buf,
237-
find_unique_abbrev(sha1, DEFAULT_ABBREV));
238-
strbuf_addf(&buf, "branch.%s", bname.buf);
239-
if (git_config_rename_section(buf.buf, NULL) < 0)
240-
warning(_("Update of config-file failed"));
241-
strbuf_release(&buf);
254+
continue;
255+
}
256+
if (!quiet) {
257+
printf(remote_branch
258+
? _("Deleted remote branch %s (was %s).\n")
259+
: _("Deleted branch %s (was %s).\n"),
260+
bname.buf,
261+
(flags & REF_ISSYMREF)
262+
? target
263+
: find_unique_abbrev(sha1, DEFAULT_ABBREV));
242264
}
265+
delete_branch_config(bname.buf);
243266
}
244267

245268
free(name);

t/t3200-branch.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,25 @@ test_expect_success 'config information was renamed, too' \
262262
"test $(git config branch.s.dummy) = Hello &&
263263
test_must_fail git config branch.s/s/dummy"
264264

265+
test_expect_success 'deleting a symref' '
266+
git branch target &&
267+
git symbolic-ref refs/heads/symref refs/heads/target &&
268+
echo "Deleted branch symref (was refs/heads/target)." >expect &&
269+
git branch -d symref >actual &&
270+
test_path_is_file .git/refs/heads/target &&
271+
test_path_is_missing .git/refs/heads/symref &&
272+
test_i18ncmp expect actual
273+
'
274+
275+
test_expect_success 'deleting a dangling symref' '
276+
git symbolic-ref refs/heads/dangling-symref nowhere &&
277+
test_path_is_file .git/refs/heads/dangling-symref &&
278+
echo "Deleted branch dangling-symref (was nowhere)." >expect &&
279+
git branch -d dangling-symref >actual &&
280+
test_path_is_missing .git/refs/heads/dangling-symref &&
281+
test_i18ncmp expect actual
282+
'
283+
265284
test_expect_success 'renaming a symref is not allowed' \
266285
'
267286
git symbolic-ref refs/heads/master2 refs/heads/master &&

0 commit comments

Comments
 (0)