Git development
 help / color / mirror / Atom feed
From: Phillip Wood <phillip.wood123@gmail.com>
To: Harald Nordgren via GitGitGadget <gitgitgadget@gmail.com>,
	git@vger.kernel.org
Cc: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>,
	Johannes Sixt <j6t@kdbg.org>,
	Harald Nordgren <haraldnordgren@gmail.com>
Subject: Re: [PATCH v18 0/7] branch: delete-merged
Date: Fri, 10 Jul 2026 16:26:59 +0100	[thread overview]
Message-ID: <c1ff2ca9-5744-490b-8d40-b40fc3100718@gmail.com> (raw)
In-Reply-To: <pull.2285.v18.git.git.1782338106.gitgitgadget@gmail.com>

Hi Harald

I've looked through the first five patches and left a few comments and 
queries. I'll look at the last two at the start of next week so don't 
re-roll just yet, but my all means reply to the comments, especially 
where I've asked questions. So far I like what I've seen.

Thanks

Phillip

On 24/06/2026 22:54, Harald Nordgren via GitGitGadget wrote:
> Delete branches that have already been merged on upstream.
> 
> Changes in v18:
> 
>   * Instead of keeping the whole chain of upstream branches, keep only the
>     ones an unmerged branch still needs. When a kept (merged) branch in turn
>     tracks a branch that is being deleted, clear its now-stale upstream
>     config.
>   * Rework spare_stacked_bases() to record the kept bases and, in a second
>     pass, clear the upstream of any whose own base is going away. Build the
>     to-delete list with strset_for_each_entry() instead of re-walking the
>     candidate array.
> 
> Changes in v17:
> 
>   * Keep a merged branch when another surviving branch still tracks it as its
>     upstream, so --delete-merged no longer deletes a branch out from under
>     one stacked on top of it.
>   * Move the --dry-run and branch.<name>.deleteMerged opt-out fully into
>     their own commits.
> 
> Changes in v16:
> 
>   * Convert delete_merged_branches() to take an unsigned int flags argument
>     instead of separate quiet/dry_run booleans, matching delete_branches()
>   * Reuse the strbuf across the skip-config loop (strbuf_reset per iteration,
>     single strbuf_release after) instead of allocating and freeing it each
>     time
>   * Rewrite the --delete-merged tests as integration tests: branches that
>     land commits upstream, with deletion and the checked-out, upstream-gone,
>     and push-equals-upstream safety cases exercised together in one run and
>     output asserted via test_cmp
>   * Collapse the many per-aspect test repos into a single reused repo set up
>     by a setup_repo_for_delete_merged helper, and rename helpers off the old
>     pm_/prune naming
>   * Nest single-repo setup sequences in ( cd ... ) subshells instead of
>     prefixing every command with -C
> 
> Changes in v15:
> 
>   * Renamed --prune-merged to --delete-merged throughout. Not necessarily
>     final, but something to advance the discussion.
>   * --delete-merged now silently skips not-yet-merged branches instead of
>     warning.
>   * Initialized the delete_branches() flag locals where declared. Only force
>     stays deferred.
>   * delete_branches()/check_branch_commit() doc and code cleanups: redundant
>     branch NULL checks dropped, ref_array candidates = { 0 }, a BUG() for the
>     unreachable non-branch ref, and reworked --delete-merged doc wording.
>   * Broadened the --forked tests (local commits for realism, remote add -f,
>     --forked coverage), renamed the misleading trunk fixture, and replaced
>     the misnamed detached branch with git checkout --detach.
> 
> Changes in v14:
> 
>   * Fixed a git branch -d -r regression (broke t5404/t5505/t5514): the
>     remotes path set a local force but not the DELETE_BRANCH_FORCE bit that
>     check_branch_commit() reads, so it wrongly ran the merge check.
>   * Made flags the single source of truth in delete_branches() so the bit and
>     the derived locals can't disagree.
>   * Works locally, but GitHub CI has problems that are there for other
>     branches too, hopefully not related
>     (https://github.com/git/git/pull/2285).
> 
> Changes in v13:
> 
>   * Reworked --forked into a real ref-filter applied in apply_ref_filter()
>     instead of a post-pass, so non-matching branches are never allocated.
>   * Match exact --forked patterns on full refnames (only globs use the
>     abbreviated upstream), and dropped the old helper machinery, forward
>     declaration, and string_list in favor of a strvec.
>   * Replaced the boolean parameters of
>     delete_branches()/check_branch_commit() with a single unsigned int flags.
>   * --prune-merged now collects candidates via filter_refs() rather than its
>     own branch walk.
>   * --prune-merged now takes its patterns as positional arguments (e.g. git
>     branch --prune-merged origin/main 'feature*') instead of repeating the
>     option.
> 
> Changes in v12:
> 
>   * Reworked --forked from a standalone action into a --list-mode filter.
>   * Switched --forked and --prune-merged to repeatable OPT_STRING_LIST
>     options.
>   * Dropped the bare-remote-name resolution for --forked, the argument is now
>     a ref or a glob.
> 
> Changes in v11:
> 
>   * The flags now take a branch, not a remote. --forked and --prune-merged
>     accept a literal upstream short name like origin/main or a wildmatch
>     pattern like origin/. The old --all-remotes flag is gone, since origin/
>     covers that case.
>   * The prune guard now compares @{push} against @{upstream}. A branch is
>     spared when these are equal. That is the trunk like case, such as local
>     main tracking and pushing to origin/main, where "fully merged to
>     upstream" cannot be told apart from "just pulled". Only branches that
>     push somewhere other than their upstream, typically fork based topics,
>     are candidates. The earlier /HEAD by name guard that the reviewer
>     rejected is gone.
>   * New --dry-run for --prune-merged.
> 
> Changes in v10:
> 
>   * --forked / --prune-merged now take a branch glob instead of a remote name
>     — origin, origin/*, origin/release-- all work. This replaces the
>     remote-only form and subsumes the old --all-remotes flag, which has been
>     dropped.
>   * New --dry-run for --prune-merged.
> 
> Changes in v9:
> 
>   * --force no longer has special meaning with --prune-merged; reachability
>     is always enforced. Use git branch -D to delete an unmerged branch.
>     Matches how git branch's other read/safe actions treat --force.
>   * Synopsis drops [-f]; "not fully merged" hint points at git branch -D.
>   * Dropped the --prune-merged --force tests.
> 
> Changes in v8:
> 
>   * Delete only when the branch's work is actually reachable from its
>     upstream
>   * Skip branches whose upstream is gone (even with --force)
>   * Simplified the internal safety flag to live in one place
> 
> Changes in v7:
> 
>   * --prune-merged now checks if a branch is merged into its own upstream
>     first. If the upstream is gone, it checks against the remote's default
>     branch instead. If neither exists, the branch is refused (use --force to
>     delete anyway).
> 
> Changes in v6:
> 
>   * --prune-merged now measures merged-ness against the remote's default
>     branch instead of the candidate's upstream — so the decision no longer
>     depends on which branch happens to be checked out locally.
>   * delete_branches() / check_branch_commit() gained a per-candidate override
>     that lets a caller substitute a different "what counts as merged"
>     reference (or skip the check). branch -d callers pass NULL and keep their
>     existing semantics.
>   * prune_merged_branches() resolves each candidate's push-remote HEAD and
>     threads it through, so --prune-merged --all-remotes measures each
>     candidate against its own remote rather than a single global reference.
> 
> Changes in v5:
> 
>   * Drop commit 'fetch: add --prune-merged'
> 
> Changes in v4:
> 
>   * Resolve each remote's HEAD and collect the targets into a
>     protected_default_refs set in collect_forked_set.
>   * In prune_merged_branches, skip a candidate when its upstream is a
>     protected default ref and the local branch name matches the default
>     branch's leaf name (so a local main tracking origin/main is spared, but a
>     renamed trunk tracking origin/main is not).
>   * Also skip when the candidate's push ref points at a protected default
>     ref, so a topic branch configured to push to origin/main is never pruned.
>   * Tests: spare the local default branch; only protect by matching leaf name
>     (not by upstream alone); spare a branch whose push ref is the remote
>     default.
> 
> Changes in v3:
> 
>   * s/remote-tracking refs/remote-tracking branches/g
> 
> Changes in v2:
> 
>   * The whole feature moved out of git fetch and into git branch. git fetch
>     --prune-merged now just calls git branch --prune-merged after fetching.
>   * The fetch.pruneLocalBranches and remote..pruneLocalBranches config
>     options are gone, replaced by per-branch opt-out via branch..pruneMerged.
>   * New git branch --forked lists local branches whose upstream lives on the
>     given remote (read-only building block).
>   * New git branch --prune-merged deletes those branches, but only if their
>     tip is reachable from the upstream tracking ref; --force skips that
>     safety check.
>   * New git branch --all-remotes lets --forked/--prune-merged operate across
>     every configured remote at once.
>   * The currently checked-out branch in any worktree is always preserved.
>   * branch..pruneMerged=false lets you exempt a branch (e.g. a long-running
>     topic branch) even with --force; doesn't affect explicit git branch -d.
>   * delete_branches() got a warn_only mode so bulk deletion prints a one-line
>     warning per skipped branch instead of the noisy four-line hint that git
>     branch -d shows.
>   * New section in git-branch docs; git-fetch docs trimmed to just mention
>     --prune-merged.
>   * New tests in t3200-branch.sh for the new branch flags; t5510-fetch.sh
>     shrunk since most logic moved.
> 
> Harald Nordgren (7):
>    branch: add --forked filter for --list mode
>    branch: convert delete_branches() to a flags argument
>    branch: let delete_branches skip unmerged branches on bulk refusal
>    branch: prepare delete_branches for a bulk caller
>    branch: add --delete-merged <branch>
>    branch: add branch.<name>.deleteMerged opt-out
>    branch: add --dry-run for --delete-merged
> 
>   Documentation/config/branch.adoc |   7 +
>   Documentation/git-branch.adoc    |  48 ++++-
>   builtin/branch.c                 | 266 +++++++++++++++++++++---
>   ref-filter.c                     |  70 +++++++
>   ref-filter.h                     |  10 +
>   t/t3200-branch.sh                | 342 +++++++++++++++++++++++++++++++
>   6 files changed, 715 insertions(+), 28 deletions(-)
> 
> 
> base-commit: ab776a62a78576513ee121424adb19597fbb7613
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2285%2FHaraldNordgren%2Ffetch-prune-local-branches-v18
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2285/HaraldNordgren/fetch-prune-local-branches-v18
> Pull-Request: https://github.com/git/git/pull/2285
> 
> Range-diff vs v17:
> 
>   1:  d8cc17bd7f = 1:  3e29ff17bd branch: add --forked filter for --list mode
>   2:  d14b0403f0 = 2:  cdd4fea4a7 branch: convert delete_branches() to a flags argument
>   3:  ef2719dac3 = 3:  a0fd5b4a6c branch: let delete_branches skip unmerged branches on bulk refusal
>   4:  80518f5d11 = 4:  a56d8fe93e branch: prepare delete_branches for a bulk caller
>   5:  46da7c8140 ! 5:  a84c555d99 branch: add --delete-merged <branch>
>       @@ Commit message
>            upstream. The work has already landed on the upstream they track,
>            so the local copy is no longer needed.
>        
>       -    Three kinds of branches are not deleted:
>       +    A branch is not deleted when:
>        
>       -      * any branch checked out in any worktree
>       -      * any branch whose upstream remote-tracking branch no longer
>       -        exists, since a missing upstream is not by itself a sign of
>       -        integration
>       -      * any branch whose push destination equals its upstream
>       -        (<branch>@{push} is the same as <branch>@{upstream}), such as
>       -        a local "main" that tracks and pushes to "origin/main". Right
>       -        after a pull it just looks "fully merged", so it is kept. Only
>       -        branches that push somewhere other than their upstream,
>       -        typically topics in a fork workflow, are candidates.
>       +      * it is checked out in any worktree
>       +      * its upstream remote-tracking branch no longer exists, since a
>       +        missing upstream is not by itself a sign of integration
>       +      * its push destination equals its upstream (<branch>@{push} is
>       +        the same as <branch>@{upstream}), such as a local "main" that
>       +        tracks and pushes to "origin/main". Right after a pull it just
>       +        looks "fully merged", so it is kept. Only branches that push
>       +        somewhere other than their upstream, typically topics in a fork
>       +        workflow, are candidates.
>        
>            A branch whose work is not yet merged into its upstream is silently
>            skipped, so one unmerged topic does not abort the whole sweep.
>        
>            A branch that another, surviving branch tracks as its upstream is
>            also kept, so a branch is never deleted out from under one stacked
>       -    on top of it. Sparing such a base can in turn protect its own
>       -    upstream, so the check repeats until the set stops changing.
>       +    on top of it. Such a kept branch is itself merged, so when its own
>       +    upstream is being deleted, clear its now-stale upstream config.
>        
>            Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
>        
>       @@ Documentation/git-branch.adoc: This option is only applicable in non-verbose mod
>        +silently skipped. Delete it with `git branch -D` if you want to
>        +remove it anyway.
>        ++
>       -+A branch that another, surviving branch still tracks as its upstream
>       -+is kept, so a branch is never deleted out from under one stacked on
>       -+top of it.
>       ++A branch that another, surviving branch tracks as its upstream is
>       ++kept, so a branch is never deleted out from under one stacked on top
>       ++of it. If that kept branch in turn tracks a branch that is being
>       ++deleted, its now-stale upstream configuration is cleared.
>        +
>         `-v`::
>         `-vv`::
>       @@ builtin/branch.c: static int parse_opt_forked(const struct option *opt, const ch
>         	return 0;
>         }
>         
>       -+static int collect_upstream(const struct reference *ref, void *cb_data)
>       -+{
>       -+	struct string_list *upstreams = cb_data;
>       -+	struct branch *branch = branch_get(ref->name);
>       -+	const char *upstream = branch_get_upstream(branch, NULL);
>       ++struct spare_data {
>       ++	struct strset *deletable;
>       ++	struct strset *spared;
>       ++};
>        +
>       -+	string_list_append(upstreams, ref->name)->util =
>       -+		xstrdup_or_null(upstream);
>       ++/*
>       ++ * A surviving branch stacked on a deletion candidate would lose its
>       ++ * upstream, so drop that candidate from the delete set and remember it
>       ++ * in "spared" so its own upstream can be tidied up afterwards.
>       ++ */
>       ++static int spare_stacked_base(const struct reference *ref, void *cb_data)
>       ++{
>       ++	struct spare_data *data = cb_data;
>       ++	struct branch *branch;
>       ++	const char *upstream, *up_short;
>       ++
>       ++	if (strset_contains(data->deletable, ref->name))
>       ++		return 0;
>       ++	branch = branch_get(ref->name);
>       ++	upstream = branch_get_upstream(branch, NULL);
>       ++	if (!upstream || !skip_prefix(upstream, "refs/heads/", &up_short) ||
>       ++	    !strset_contains(data->deletable, up_short))
>       ++		return 0;
>       ++
>       ++	strset_remove(data->deletable, up_short);
>       ++	strset_add(data->spared, up_short);
>        +	return 0;
>        +}
>        +
>        +/*
>       -+ * Keep any branch that another, surviving branch tracks as its
>       -+ * upstream, so we never delete a branch out from under one stacked on
>       -+ * top of it.  Sparing a branch makes it a survivor whose own upstream
>       -+ * then needs the same protection, so repeat until nothing changes.
>       ++ * Keep any branch that a surviving branch tracks as its upstream, so we
>       ++ * never delete a branch out from under one stacked on top of it.  Such a
>       ++ * base is itself merged, so when its own upstream is also going away
>       ++ * (no surviving branch tracks it), clear the base's now-stale upstream.
>        + */
>        +static void spare_stacked_bases(struct ref_store *refs, struct strset *deletable)
>        +{
>       -+	struct string_list upstreams = STRING_LIST_INIT_DUP;
>       -+	struct string_list_item *item;
>       -+	bool spared;
>       -+
>       -+	refs_for_each_branch_ref(refs, collect_upstream, &upstreams);
>       -+	do {
>       -+		spared = false;
>       -+		for_each_string_list_item(item, &upstreams) {
>       -+			const char *up = item->util, *up_short;
>       -+
>       -+			if (!up || strset_contains(deletable, item->string))
>       -+				continue;
>       -+			if (!skip_prefix(up, "refs/heads/", &up_short) ||
>       -+			    !strset_contains(deletable, up_short))
>       -+				continue;
>       -+
>       -+			strset_remove(deletable, up_short);
>       -+			spared = true;
>       -+		}
>       -+	} while (spared);
>       -+
>       -+	string_list_clear(&upstreams, 1);
>       ++	struct strset spared = STRSET_INIT;
>       ++	struct spare_data data = { .deletable = deletable, .spared = &spared };
>       ++	struct strbuf key = STRBUF_INIT;
>       ++	struct hashmap_iter iter;
>       ++	struct strmap_entry *entry;
>       ++
>       ++	refs_for_each_branch_ref(refs, spare_stacked_base, &data);
>       ++
>       ++	strset_for_each_entry(&spared, &iter, entry) {
>       ++		struct branch *branch = branch_get(entry->key);
>       ++		const char *upstream = branch_get_upstream(branch, NULL);
>       ++		const char *up_short;
>       ++
>       ++		if (!upstream || !skip_prefix(upstream, "refs/heads/", &up_short) ||
>       ++		    !strset_contains(deletable, up_short))
>       ++			continue;
>       ++
>       ++		strbuf_reset(&key);
>       ++		strbuf_addf(&key, "branch.%s.merge", branch->name);
>       ++		repo_config_set_gently(the_repository, key.buf, NULL);
>       ++		strbuf_reset(&key);
>       ++		strbuf_addf(&key, "branch.%s.remote", branch->name);
>       ++		repo_config_set_gently(the_repository, key.buf, NULL);
>       ++	}
>       ++
>       ++	strbuf_release(&key);
>       ++	strset_clear(&spared);
>        +}
>        +
>        +static int delete_merged_branches(int argc, const char **argv,
>       @@ builtin/branch.c: static int parse_opt_forked(const struct option *opt, const ch
>        +	struct ref_array candidates = { 0 };
>        +	struct strset deletable = STRSET_INIT;
>        +	struct strvec to_delete = STRVEC_INIT;
>       ++	struct hashmap_iter iter;
>       ++	struct strmap_entry *entry;
>        +	int i, ret = 0;
>        +
>        +	if (!argc)
>       @@ builtin/branch.c: static int parse_opt_forked(const struct option *opt, const ch
>        +
>        +	spare_stacked_bases(refs, &deletable);
>        +
>       -+	for (i = 0; i < candidates.nr; i++) {
>       -+		const char *short_name;
>       -+
>       -+		if (skip_prefix(candidates.items[i]->refname, "refs/heads/",
>       -+				&short_name) &&
>       -+		    strset_contains(&deletable, short_name))
>       -+			strvec_push(&to_delete, short_name);
>       -+	}
>       ++	strset_for_each_entry(&deletable, &iter, entry)
>       ++		strvec_push(&to_delete, entry->key);
>        +
>        +	if (to_delete.nr)
>        +		ret = delete_branches(to_delete.nr, to_delete.v,
>       @@ t/t3200-branch.sh: test_expect_success '--forked narrows a <pattern> argument' '
>        +		git checkout --detach
>        +	) &&
>        +
>       ++	git -C repo branch --dry-run --delete-merged origin/next >out &&
>       ++	test_grep ! "feature" out &&
>       ++
>        +	git -C repo branch --delete-merged origin/next 2>err &&
>        +
>        +	test_must_be_empty err &&
>        +	git -C repo rev-parse --verify refs/heads/feature &&
>       -+	git -C repo rev-parse --verify refs/heads/topic
>       ++	git -C repo rev-parse --verify refs/heads/topic &&
>       ++	echo origin/next >expect &&
>       ++	git -C repo rev-parse --abbrev-ref feature@{upstream} >actual &&
>       ++	test_cmp expect actual &&
>       ++	echo feature >expect &&
>       ++	git -C repo rev-parse --abbrev-ref topic@{upstream} >actual &&
>       ++	test_cmp expect actual
>        +'
>        +
>        +test_expect_success '--delete-merged keeps a chain of upstreams of a kept branch' '
>       @@ t/t3200-branch.sh: test_expect_success '--forked narrows a <pattern> argument' '
>        +	EOF
>        +	test_cmp expect actual
>        +'
>       ++
>       ++test_expect_success '--delete-merged clears the upstream of a kept base whose own base is deleted' '
>       ++	test_when_finished "rm -rf repo" &&
>       ++	setup_repo_for_delete_merged &&
>       ++	(
>       ++		cd repo &&
>       ++		git branch lower origin/next &&
>       ++		git branch --set-upstream-to=origin/next lower &&
>       ++		git branch mid origin/next &&
>       ++		git branch --set-upstream-to=lower mid &&
>       ++		git checkout -b tip mid &&
>       ++		git commit --allow-empty -m "tip work" &&
>       ++		git branch --set-upstream-to=mid tip &&
>       ++		git checkout --detach
>       ++	) &&
>       ++
>       ++	git -C repo branch --delete-merged origin/next lower &&
>       ++
>       ++	test_must_fail git -C repo rev-parse --verify refs/heads/lower &&
>       ++	git -C repo rev-parse --verify refs/heads/mid &&
>       ++	test_must_fail git -C repo rev-parse mid@{upstream} &&
>       ++	echo mid >expect &&
>       ++	git -C repo rev-parse --abbrev-ref tip@{upstream} >actual &&
>       ++	test_cmp expect actual
>       ++'
>        +
>         test_done
>   6:  27903fbb1d ! 6:  d52d717b70 branch: add branch.<name>.deleteMerged opt-out
>       @@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
>         	struct strset deletable = STRSET_INIT;
>         	struct strvec to_delete = STRVEC_INIT;
>        +	struct strbuf key = STRBUF_INIT;
>       + 	struct hashmap_iter iter;
>       + 	struct strmap_entry *entry;
>        +	bool quiet = flags & DELETE_BRANCH_QUIET;
>         	int i, ret = 0;
>         
>       @@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
>         	ref_array_clear(&candidates);
>        
>         ## t/t3200-branch.sh ##
>       -@@ t/t3200-branch.sh: test_expect_success '--delete-merged keeps a chain of upstreams of a kept branch
>       +@@ t/t3200-branch.sh: test_expect_success '--delete-merged clears the upstream of a kept base whose ow
>         	test_cmp expect actual
>         '
>         
>   7:  49c1bcf1fb ! 7:  8d0323f4b3 branch: add --dry-run for --delete-merged
>       @@ Documentation/git-branch.adoc: git branch (-m|-M) [<old-branch>] <new-branch>
>         
>         DESCRIPTION
>         -----------
>       -@@ Documentation/git-branch.adoc: A branch that another, surviving branch still tracks as its upstream
>       - is kept, so a branch is never deleted out from under one stacked on
>       - top of it.
>       +@@ Documentation/git-branch.adoc: kept, so a branch is never deleted out from under one stacked on top
>       + of it. If that kept branch in turn tracks a branch that is being
>       + deleted, its now-stale upstream configuration is cleared.
>         
>        +`--dry-run`::
>        +	With `--delete-merged`, print which branches would be
> 


  parent reply	other threads:[~2026-07-10 15:27 UTC|newest]

Thread overview: 225+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-01 21:35 [PATCH] fetch: add fetch.pruneLocalBranches config Harald Nordgren via GitGitGadget
2026-05-03 22:39 ` Junio C Hamano
2026-05-04 18:28   ` [PATCH] checkout: add --autostash option for branch switching Harald Nordgren
2026-05-10  1:01     ` Junio C Hamano
2026-05-05  7:14   ` [PATCH] fetch: add fetch.pruneLocalBranches config Johannes Sixt
2026-05-04 18:27 ` [PATCH v2 0/6] fetch: add fetch.pruneBranches config Harald Nordgren via GitGitGadget
2026-05-04 18:27   ` [PATCH v2 1/6] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-04 23:25     ` Kristoffer Haugsbakk
2026-05-04 18:27   ` [PATCH v2 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-04 18:27   ` [PATCH v2 3/6] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-04 18:27   ` [PATCH v2 4/6] fetch: add --prune-merged Harald Nordgren via GitGitGadget
2026-05-04 18:27   ` [PATCH v2 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-04 18:27   ` [PATCH v2 6/6] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-05  7:22   ` [PATCH v3 0/6] fetch: add fetch.pruneBranches config Harald Nordgren via GitGitGadget
2026-05-05  7:22     ` [PATCH v3 1/6] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-05  7:22     ` [PATCH v3 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-05  7:22     ` [PATCH v3 3/6] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-05  7:22     ` [PATCH v3 4/6] fetch: add --prune-merged Harald Nordgren via GitGitGadget
2026-05-05  7:22     ` [PATCH v3 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-05  7:22     ` [PATCH v3 6/6] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-05 19:23     ` [PATCH v4 0/6] fetch: add fetch.pruneBranches config Harald Nordgren via GitGitGadget
2026-05-05 19:23       ` [PATCH v4 1/6] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-05 19:23       ` [PATCH v4 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-05 19:23       ` [PATCH v4 3/6] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-05 19:23       ` [PATCH v4 4/6] fetch: add --prune-merged Harald Nordgren via GitGitGadget
2026-05-05 20:48         ` Johannes Sixt
2026-05-05 22:07           ` [PATCH] fetch: add fetch.pruneLocalBranches config Harald Nordgren
2026-05-11  2:59             ` Junio C Hamano
2026-05-11  6:56               ` Harald Nordgren
2026-05-05 19:23       ` [PATCH v4 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-05 19:23       ` [PATCH v4 6/6] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-07 20:14       ` [PATCH v4 0/6] fetch: add fetch.pruneBranches config Harald Nordgren
2026-05-11  6:58       ` [PATCH v5 0/5] branch: prune-merged Harald Nordgren via GitGitGadget
2026-05-11  6:58         ` [PATCH v5 1/5] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-11  6:58         ` [PATCH v5 2/5] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-11  8:18           ` Junio C Hamano
2026-05-11  8:44             ` [PATCH] fetch: add fetch.pruneLocalBranches config Harald Nordgren
2026-05-11  6:58         ` [PATCH v5 3/5] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-11  6:58         ` [PATCH v5 4/5] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-11  6:58         ` [PATCH v5 5/5] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-11  9:44         ` [PATCH v6 0/5] branch: prune-merged Harald Nordgren via GitGitGadget
2026-05-11  9:44           ` [PATCH v6 1/5] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-11  9:44           ` [PATCH v6 2/5] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-11  9:44           ` [PATCH v6 3/5] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-11  9:44           ` [PATCH v6 4/5] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-11  9:44           ` [PATCH v6 5/5] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-11 23:20           ` [PATCH v6 0/5] branch: prune-merged Junio C Hamano
2026-05-12  7:35             ` [PATCH] fetch: add fetch.pruneLocalBranches config Harald Nordgren
2026-05-12  8:23           ` [PATCH v7 0/5] branch: prune-merged Harald Nordgren via GitGitGadget
2026-05-12  8:23             ` [PATCH v7 1/5] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-12  8:23             ` [PATCH v7 2/5] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-12  8:23             ` [PATCH v7 3/5] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-12 13:53               ` Junio C Hamano
2026-05-12 17:00                 ` [PATCH] fetch: add fetch.pruneLocalBranches config Harald Nordgren
2026-05-12  8:23             ` [PATCH v7 4/5] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-12  8:23             ` [PATCH v7 5/5] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-12 17:07             ` [PATCH v8 0/5] branch: prune-merged Harald Nordgren via GitGitGadget
2026-05-12 17:07               ` [PATCH v8 1/5] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-12 17:07               ` [PATCH v8 2/5] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-12 17:07               ` [PATCH v8 3/5] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-12 17:07               ` [PATCH v8 4/5] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-12 17:07               ` [PATCH v8 5/5] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-13 13:46               ` [PATCH v8 0/5] branch: prune-merged Junio C Hamano
2026-05-13 18:57                 ` [PATCH] fetch: add fetch.pruneLocalBranches config Harald Nordgren
2026-05-13 19:34               ` [PATCH v9 0/5] branch: prune-merged Harald Nordgren via GitGitGadget
2026-05-13 19:34                 ` [PATCH v9 1/5] branch: add --forked <remote> Harald Nordgren via GitGitGadget
2026-05-13 19:34                 ` [PATCH v9 2/5] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-13 19:34                 ` [PATCH v9 3/5] branch: add --prune-merged <remote> Harald Nordgren via GitGitGadget
2026-05-18 15:27                   ` Phillip Wood
2026-05-21  9:46                     ` Phillip Wood
2026-05-21 19:16                       ` Harald Nordgren
2026-05-22  9:47                         ` Phillip Wood
2026-05-22 10:51                           ` Harald Nordgren
2026-05-21 12:37                     ` Harald Nordgren
2026-05-21 13:29                     ` Junio C Hamano
2026-05-13 19:34                 ` [PATCH v9 4/5] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-13 19:34                 ` [PATCH v9 5/5] branch: add --all-remotes flag Harald Nordgren via GitGitGadget
2026-05-18 15:27                   ` Phillip Wood
2026-05-18  8:14                 ` [PATCH v9 0/5] branch: prune-merged Harald Nordgren
2026-05-21 22:40                 ` [PATCH v10 0/4] " Harald Nordgren via GitGitGadget
2026-05-21 22:40                   ` [PATCH v10 1/4] branch: add --forked <branch> Harald Nordgren via GitGitGadget
2026-05-22  1:52                     ` Junio C Hamano
2026-05-22  6:18                     ` Johannes Sixt
2026-05-22  6:36                       ` Junio C Hamano
2026-05-22 10:49                         ` Harald Nordgren
2026-05-22 11:25                           ` Johannes Sixt
2026-05-21 22:40                   ` [PATCH v10 2/4] branch: add --prune-merged <branch> Harald Nordgren via GitGitGadget
2026-05-22  1:17                     ` Junio C Hamano
2026-05-22  2:51                     ` Junio C Hamano
2026-05-22  2:53                       ` Junio C Hamano
2026-05-22  7:59                         ` Harald Nordgren
2026-05-22 11:58                           ` Junio C Hamano
2026-05-22  2:52                     ` Junio C Hamano
2026-05-21 22:40                   ` [PATCH v10 3/4] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-21 22:40                   ` [PATCH v10 4/4] branch: add --dry-run for --prune-merged Harald Nordgren via GitGitGadget
2026-05-22 11:31                   ` [PATCH v11 0/6] branch: prune-merged Harald Nordgren via GitGitGadget
2026-05-22 11:31                     ` [PATCH v11 1/6] branch: add --forked <branch> Harald Nordgren via GitGitGadget
2026-05-22 11:31                     ` [PATCH v11 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-05-22 11:31                     ` [PATCH v11 3/6] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-05-22 11:31                     ` [PATCH v11 4/6] branch: add --prune-merged <branch> Harald Nordgren via GitGitGadget
2026-05-22 11:31                     ` [PATCH v11 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-05-22 11:31                     ` [PATCH v11 6/6] branch: add --dry-run for --prune-merged Harald Nordgren via GitGitGadget
2026-06-02 13:05                     ` [PATCH v11 0/6] branch: prune-merged Phillip Wood
2026-06-02 13:41                       ` Harald Nordgren
2026-06-03  9:04                     ` [PATCH v12 " Harald Nordgren via GitGitGadget
2026-06-03  9:04                       ` [PATCH v12 1/6] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-06-05 13:48                         ` Phillip Wood
2026-06-05 17:50                           ` Harald Nordgren
2026-06-03  9:04                       ` [PATCH v12 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-06-05 13:49                         ` Phillip Wood
2026-06-03  9:04                       ` [PATCH v12 3/6] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-05 13:49                         ` Phillip Wood
2026-06-03  9:04                       ` [PATCH v12 4/6] branch: add --prune-merged <branch> Harald Nordgren via GitGitGadget
2026-06-05 13:50                         ` Phillip Wood
2026-06-05 15:04                           ` Phillip Wood
2026-06-03  9:04                       ` [PATCH v12 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-06-03  9:04                       ` [PATCH v12 6/6] branch: add --dry-run for --prune-merged Harald Nordgren via GitGitGadget
2026-06-05 18:35                       ` [PATCH v13 0/6] branch: prune-merged Harald Nordgren via GitGitGadget
2026-06-05 18:35                         ` [PATCH v13 1/6] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-06-05 18:35                         ` [PATCH v13 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-06-08 23:56                           ` Junio C Hamano
2026-06-09  7:52                             ` Harald Nordgren
2026-06-09 12:38                               ` Junio C Hamano
2026-06-09 13:20                                 ` Harald Nordgren
2026-06-05 18:35                         ` [PATCH v13 3/6] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-05 18:35                         ` [PATCH v13 4/6] branch: add --prune-merged <branch> Harald Nordgren via GitGitGadget
2026-06-05 18:35                         ` [PATCH v13 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-06-05 18:35                         ` [PATCH v13 6/6] branch: add --dry-run for --prune-merged Harald Nordgren via GitGitGadget
2026-06-09 10:11                         ` [PATCH v14 0/6] branch: prune-merged Harald Nordgren via GitGitGadget
2026-06-09 10:11                           ` [PATCH v14 1/6] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-06-15  9:46                             ` Phillip Wood
2026-06-09 10:11                           ` [PATCH v14 2/6] branch: let delete_branches warn instead of error on bulk refusal Harald Nordgren via GitGitGadget
2026-06-09 13:21                             ` Phillip Wood
2026-06-09 10:11                           ` [PATCH v14 3/6] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-15  9:47                             ` Phillip Wood
2026-06-09 10:11                           ` [PATCH v14 4/6] branch: add --prune-merged <branch> Harald Nordgren via GitGitGadget
2026-06-15  9:46                             ` Phillip Wood
2026-06-16  9:59                             ` Phillip Wood
2026-06-16 19:15                               ` Harald Nordgren
2026-06-18 13:42                                 ` Phillip Wood
2026-06-18 16:08                                   ` Junio C Hamano
2026-06-19 13:13                                     ` Phillip Wood
2026-06-19 15:42                                       ` Junio C Hamano
2026-06-19 16:01                                         ` Junio C Hamano
2026-06-20  9:04                                           ` Harald Nordgren
2026-06-21 18:46                                             ` Harald Nordgren
2026-06-22  9:09                                               ` Phillip Wood
2026-06-22  9:28                                                 ` Phillip Wood
2026-06-22  9:37                                                   ` Harald Nordgren
2026-06-22  9:57                                                     ` Phillip Wood
2026-06-22 10:52                                                       ` Harald Nordgren
2026-06-22  9:25                                             ` Phillip Wood
2026-06-22  9:07                                           ` Phillip Wood
2026-06-22 12:26                                             ` Junio C Hamano
2026-06-09 10:11                           ` [PATCH v14 5/6] branch: add branch.<name>.pruneMerged opt-out Harald Nordgren via GitGitGadget
2026-06-16  9:57                             ` Phillip Wood
2026-06-09 10:11                           ` [PATCH v14 6/6] branch: add --dry-run for --prune-merged Harald Nordgren via GitGitGadget
2026-06-16  9:57                             ` Phillip Wood
2026-06-16 18:28                               ` Harald Nordgren
2026-06-15 16:47                           ` [PATCH v15 0/7] branch: delete-merged Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 1/7] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 2/7] branch: convert delete_branches() to a flags argument Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 3/7] branch: let delete_branches skip unmerged branches on bulk refusal Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 4/7] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 5/7] branch: add --delete-merged <branch> Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 6/7] branch: add branch.<name>.deleteMerged opt-out Harald Nordgren via GitGitGadget
2026-06-15 16:47                             ` [PATCH v15 7/7] branch: add --dry-run for --delete-merged Harald Nordgren via GitGitGadget
2026-06-17 10:01                             ` [PATCH v15 0/7] branch: delete-merged Phillip Wood
2026-06-17 11:17                               ` Harald Nordgren
2026-06-17 14:21                                 ` Phillip Wood
2026-06-17 19:11                                   ` Harald Nordgren
2026-06-18 13:48                                     ` Phillip Wood
2026-06-18 17:53                                       ` Harald Nordgren
2026-06-18 19:25                             ` [PATCH v16 " Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 1/7] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 2/7] branch: convert delete_branches() to a flags argument Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 3/7] branch: let delete_branches skip unmerged branches on bulk refusal Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 4/7] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 5/7] branch: add --delete-merged <branch> Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 6/7] branch: add branch.<name>.deleteMerged opt-out Harald Nordgren via GitGitGadget
2026-06-18 19:25                               ` [PATCH v16 7/7] branch: add --dry-run for --delete-merged Harald Nordgren via GitGitGadget
2026-06-22  7:29                               ` [PATCH v17 0/7] branch: delete-merged Harald Nordgren via GitGitGadget
2026-06-22  7:29                                 ` [PATCH v17 1/7] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-06-22  7:29                                 ` [PATCH v17 2/7] branch: convert delete_branches() to a flags argument Harald Nordgren via GitGitGadget
2026-06-22  7:29                                 ` [PATCH v17 3/7] branch: let delete_branches skip unmerged branches on bulk refusal Harald Nordgren via GitGitGadget
2026-06-22  7:29                                 ` [PATCH v17 4/7] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-22  7:29                                 ` [PATCH v17 5/7] branch: add --delete-merged <branch> Harald Nordgren via GitGitGadget
2026-06-22 15:36                                   ` Phillip Wood
2026-06-22  7:29                                 ` [PATCH v17 6/7] branch: add branch.<name>.deleteMerged opt-out Harald Nordgren via GitGitGadget
2026-06-22  7:29                                 ` [PATCH v17 7/7] branch: add --dry-run for --delete-merged Harald Nordgren via GitGitGadget
2026-06-24 21:54                                 ` [PATCH v18 0/7] branch: delete-merged Harald Nordgren via GitGitGadget
2026-06-24 21:55                                   ` [PATCH v18 1/7] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-07-10 15:18                                     ` Phillip Wood
2026-07-11 12:30                                       ` Harald Nordgren
2026-06-24 21:55                                   ` [PATCH v18 2/7] branch: convert delete_branches() to a flags argument Harald Nordgren via GitGitGadget
2026-07-10 15:18                                     ` Phillip Wood
2026-07-10 17:25                                       ` Harald Nordgren
2026-07-13 15:28                                         ` Phillip Wood
2026-06-24 21:55                                   ` [PATCH v18 3/7] branch: let delete_branches skip unmerged branches on bulk refusal Harald Nordgren via GitGitGadget
2026-07-10 15:18                                     ` Phillip Wood
2026-06-24 21:55                                   ` [PATCH v18 4/7] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-06-24 21:55                                   ` [PATCH v18 5/7] branch: add --delete-merged <branch> Harald Nordgren via GitGitGadget
2026-07-10 15:24                                     ` Phillip Wood
2026-07-11 13:08                                       ` Harald Nordgren
2026-07-11 19:36                                         ` Harald Nordgren
2026-07-13 15:39                                           ` Phillip Wood
2026-07-13 16:39                                             ` Phillip Wood
2026-07-13 18:17                                               ` Harald Nordgren
2026-07-14 13:01                                                 ` Phillip Wood
2026-07-14 17:00                                                   ` Harald Nordgren
2026-06-24 21:55                                   ` [PATCH v18 6/7] branch: add branch.<name>.deleteMerged opt-out Harald Nordgren via GitGitGadget
2026-07-13 15:27                                     ` Phillip Wood
2026-07-13 16:33                                       ` Harald Nordgren
2026-06-24 21:55                                   ` [PATCH v18 7/7] branch: add --dry-run for --delete-merged Harald Nordgren via GitGitGadget
2026-07-13 15:27                                     ` Phillip Wood
2026-07-13 16:23                                       ` Harald Nordgren
2026-07-10 15:26                                   ` Phillip Wood [this message]
2026-07-14 18:24                                   ` [PATCH v19 0/7] branch: delete-merged Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 1/7] branch: add --forked filter for --list mode Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 2/7] branch: convert delete_branches() to a flags argument Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 3/7] branch: let delete_branches skip unmerged branches on bulk refusal Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 4/7] branch: prepare delete_branches for a bulk caller Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 5/7] branch: add --delete-merged <branch> Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 6/7] branch: add branch.<name>.deleteMerged opt-out Harald Nordgren via GitGitGadget
2026-07-14 18:24                                     ` [PATCH v19 7/7] branch: add --dry-run for --delete-merged Harald Nordgren via GitGitGadget

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c1ff2ca9-5744-490b-8d40-b40fc3100718@gmail.com \
    --to=phillip.wood123@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=haraldnordgren@gmail.com \
    --cc=j6t@kdbg.org \
    --cc=kristofferhaugsbakk@fastmail.com \
    --cc=phillip.wood@dunelm.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox