Skip to content

Commit 2e8af49

Browse files
rjustogitster
authored andcommitted
branch: test for failures while renaming branches
When we introduced replace_each_worktree_head_symref() in 70999e9 (branch -m: update all per-worktree HEADs, 2016-03-27), we implemented a best effort approach. If we are asked to rename a branch that is simultaneously checked out in multiple worktrees, we try to update all of those worktrees. If we fail updating any of them, we die() as a signal that something has gone wrong. However, at this point, the branch ref has already been renamed and also updated the HEADs of the successfully updated worktrees. Despite returning an error, we do not try to rollback those changes. Let's add a test to notice if we change this behavior in the future. In next commits we will change replace_each_worktree_head_symref() to work more closely with its only caller, copy_or_rename_branch(). Let's move the former closer to its caller, to facilitate those changes. Signed-off-by: Rubén Justo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 73876f4 commit 2e8af49

File tree

4 files changed

+47
-35
lines changed

4 files changed

+47
-35
lines changed

branch.c

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -830,30 +830,3 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree)
830830

831831
free_worktrees(worktrees);
832832
}
833-
834-
int replace_each_worktree_head_symref(const char *oldref, const char *newref,
835-
const char *logmsg)
836-
{
837-
int ret = 0;
838-
struct worktree **worktrees = get_worktrees();
839-
int i;
840-
841-
for (i = 0; worktrees[i]; i++) {
842-
struct ref_store *refs;
843-
844-
if (worktrees[i]->is_detached)
845-
continue;
846-
if (!worktrees[i]->head_ref)
847-
continue;
848-
if (strcmp(oldref, worktrees[i]->head_ref))
849-
continue;
850-
851-
refs = get_worktree_ref_store(worktrees[i]);
852-
if (refs_create_symref(refs, "HEAD", newref, logmsg))
853-
ret = error(_("HEAD of working tree %s is not updated"),
854-
worktrees[i]->path);
855-
}
856-
857-
free_worktrees(worktrees);
858-
return ret;
859-
}

branch.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,4 @@ int read_branch_desc(struct strbuf *, const char *branch_name);
155155
*/
156156
void die_if_checked_out(const char *branch, int ignore_current_worktree);
157157

158-
/*
159-
* Update all per-worktree HEADs pointing at the old ref to point the new ref.
160-
* This will be used when renaming a branch. Returns 0 if successful, non-zero
161-
* otherwise.
162-
*/
163-
int replace_each_worktree_head_symref(const char *oldref, const char *newref,
164-
const char *logmsg);
165-
166158
#endif

builtin/branch.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,38 @@ static void reject_rebase_or_bisect_branch(const char *target)
509509
free_worktrees(worktrees);
510510
}
511511

512+
/*
513+
* Update all per-worktree HEADs pointing at the old ref to point the new ref.
514+
* This will be used when renaming a branch. Returns 0 if successful, non-zero
515+
* otherwise.
516+
*/
517+
static int replace_each_worktree_head_symref(const char *oldref, const char *newref,
518+
const char *logmsg)
519+
{
520+
int ret = 0;
521+
struct worktree **worktrees = get_worktrees();
522+
int i;
523+
524+
for (i = 0; worktrees[i]; i++) {
525+
struct ref_store *refs;
526+
527+
if (worktrees[i]->is_detached)
528+
continue;
529+
if (!worktrees[i]->head_ref)
530+
continue;
531+
if (strcmp(oldref, worktrees[i]->head_ref))
532+
continue;
533+
534+
refs = get_worktree_ref_store(worktrees[i]);
535+
if (refs_create_symref(refs, "HEAD", newref, logmsg))
536+
ret = error(_("HEAD of working tree %s is not updated"),
537+
worktrees[i]->path);
538+
}
539+
540+
free_worktrees(worktrees);
541+
return ret;
542+
}
543+
512544
static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
513545
{
514546
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;

t/t3200-branch.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,21 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
239239
git worktree prune
240240
'
241241

242+
test_expect_success 'git branch -M fails if updating any linked working tree fails' '
243+
git worktree add -b baz bazdir1 &&
244+
git worktree add -f bazdir2 baz &&
245+
touch .git/worktrees/bazdir1/HEAD.lock &&
246+
test_must_fail git branch -M baz bam &&
247+
test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&
248+
git branch -M bam baz &&
249+
rm .git/worktrees/bazdir1/HEAD.lock &&
250+
touch .git/worktrees/bazdir2/HEAD.lock &&
251+
test_must_fail git branch -M baz bam &&
252+
test $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam &&
253+
rm -rf bazdir1 bazdir2 &&
254+
git worktree prune
255+
'
256+
242257
test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '
243258
git checkout -b baz &&
244259
git worktree add -f bazdir baz &&

0 commit comments

Comments
 (0)