"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
Re: got branch -d doesn't remove empty parent directory in reference
To:
Martijn van Duren <openbsd+got@list.imperialat.at>
Cc:
Gameoftrees <gameoftrees@openbsd.org>
Date:
Thu, 17 Sep 2026 10:26:13 +0200

Download raw body.

Thread
On Sat, Sep 12, 2026 at 04:42:30PM +0200, Martijn van Duren wrote:
> martijn@

Thanks, here is a fix. Does it work for you?

Please already push your test to got.gameoftrees.org if you have time.
Otherwise I'll send it along with my fix.

M  lib/reference.c  |  11+  1-

1 file changed, 11 insertions(+), 1 deletion(-)

commit - 8d7e66e9566a7274917590c6670ea30972d39172
commit + 12c30af2c8a873c913fd1073d99e2f60c08fb60d
blob - 40573c4679ab45fe6119a377d17ee557b87498f2
blob + 50259bff0ca1b0164f56f26dbebb54e36bd1b73d
--- lib/reference.c
+++ lib/reference.c
@@ -1535,7 +1535,7 @@ delete_loose_ref(struct got_reference *ref, struct got
 {
 	const struct got_error *err = NULL, *unlock_err = NULL;
 	const char *name = got_ref_get_name(ref);
-	char *path_refs = NULL, *path = NULL;
+	char *path_refs = NULL, *path = NULL, *parent = NULL;
 	struct got_lockfile *lf = NULL;
 
 	path_refs = get_refs_dir_path(repo, name);
@@ -1549,6 +1549,10 @@ delete_loose_ref(struct got_reference *ref, struct got
 		goto done;
 	}
 
+	err = got_path_dirname(&parent, path);
+	if (err)
+		goto done;
+
 	if (ref->lf == NULL) {
 		err = got_lockfile_lock(&lf, path, -1);
 		if (err)
@@ -1563,8 +1567,14 @@ done:
 	if (ref->lf == NULL && lf)
 		unlock_err = got_lockfile_unlock(lf, -1);
 
+	/* Remove empty directories to make parent reference name available. */
+	if (err == NULL && unlock_err == NULL &&
+	    rmdir(parent) == -1 && errno != ENOTEMPTY && errno != ENOENT)
+		err = got_error_from_errno2("rmdir", path);
+
 	free(path_refs);
 	free(path);
+	free(parent);
 	return err ? err : unlock_err;
 }
 
> 
> diff /home/martijn/src/got
> path + /home/martijn/src/got
> commit - f85c55bef56ccf3f41b8de4fc0482423541066c7
> blob - 6b14508b86ae76b06c4b422f9dddcb726e665798
> file + regress/cmdline/branch.sh
> --- regress/cmdline/branch.sh
> +++ regress/cmdline/branch.sh
> @@ -672,6 +672,45 @@ test_branch_list_worktree_state() {
>  	test_done "$testroot" "$ret"
>  }
>  
> +test_branch_del_child_create_parent() {
> +	local testroot=$(test_init branch_del_child_create_parent)
> +	local wt="$testroot/wt"
> +
> +	set -- "$(git_show_head "$testroot/repo")"
> +
> +	got checkout "$testroot/repo" "$wt" > /dev/null
> +	ret=$?
> +	if [ $ret -ne 0 ]; then
> +		echo "checkout failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	(cd "$wt" && got br -n a/b > /dev/null)
> +	ret=$?
> +	if [ $ret -ne 0 ]; then
> +		echo "branch a/b failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +	(cd "$wt" && got br -d a/b > /dev/null)
> +	ret=$?
> +	if [ $ret -ne 0 ]; then
> +		echo "branch deletion a/b failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +	(cd "$wt" && got br -n a > /dev/null)
> +	ret=$?
> +	if [ $ret -ne 0 ]; then
> +		echo "branch a failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	test_done "$testroot" "$ret"
> +}
> +
>  test_parseargs "$@"
>  run_test test_branch_create
>  run_test test_branch_list
> @@ -682,3 +721,4 @@ run_test test_branch_show
>  run_test test_branch_packed_ref_collision
>  run_test test_branch_commit_keywords
>  run_test test_branch_list_worktree_state
> +run_test test_branch_del_child_create_parent
> 
>