Git development
 help / color / mirror / Atom feed
From: "Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>,
	Johannes Sixt <j6t@kdbg.org>,
	Phillip Wood <phillip.wood123@gmail.com>,
	Harald Nordgren <haraldnordgren@gmail.com>
Subject: [PATCH v16 0/7] branch: delete-merged
Date: Thu, 18 Jun 2026 19:25:22 +0000	[thread overview]
Message-ID: <pull.2285.v16.git.git.1781810729.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2285.v15.git.git.1781542042.gitgitgadget@gmail.com>

Delete branches that have already been merged on upstream.

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    |  43 ++++-
 builtin/branch.c                 | 186 ++++++++++++++++++----
 ref-filter.c                     |  70 +++++++++
 ref-filter.h                     |  10 ++
 t/t3200-branch.sh                | 262 +++++++++++++++++++++++++++++++
 6 files changed, 550 insertions(+), 28 deletions(-)


base-commit: 4621f8ce5e9b97aa2e8d0d9ffe9d25df2471074d
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2285%2FHaraldNordgren%2Ffetch-prune-local-branches-v16
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2285/HaraldNordgren/fetch-prune-local-branches-v16
Pull-Request: https://github.com/git/git/pull/2285

Range-diff vs v15:

 1:  da741b5ea7 ! 1:  1f6a758265 branch: add --forked filter for --list mode
     @@ t/t3200-branch.sh: test_expect_success 'errors if given a bad branch name' '
       
      +test_expect_success '--forked: setup' '
      +	test_create_repo forked-upstream &&
     -+	test_commit -C forked-upstream base &&
     -+	git -C forked-upstream branch one base &&
     -+	git -C forked-upstream branch two base &&
     ++	(
     ++		cd forked-upstream &&
     ++		test_commit base &&
     ++		git branch one base &&
     ++		git branch two base
     ++	) &&
      +
      +	test_create_repo forked-other &&
     -+	test_commit -C forked-other other-base &&
     -+	git -C forked-other branch foreign other-base &&
     ++	(
     ++		cd forked-other &&
     ++		test_commit other-base &&
     ++		git branch foreign other-base
     ++	) &&
      +
      +	git clone forked-upstream forked &&
     -+	git -C forked remote add -f other ../forked-other &&
     -+	git -C forked remote set-head origin one &&
     -+	git -C forked branch local-base &&
     -+	git -C forked branch --track local-one origin/one &&
     -+	git -C forked branch --track local-two origin/two &&
     -+	git -C forked branch --track local-foreign other/foreign &&
     -+	git -C forked branch --track local-onbase local-base &&
     ++	(
     ++		cd forked &&
     ++		git remote add -f other ../forked-other &&
     ++		git remote set-head origin one &&
     ++		git branch local-base &&
     ++		git branch --track local-one origin/one &&
     ++		git branch --track local-two origin/two &&
     ++		git branch --track local-foreign other/foreign &&
     ++		git branch --track local-onbase local-base &&
      +
     -+	git -C forked checkout local-one &&
     -+	test_commit -C forked --no-tag local-one-work local-one.t &&
     -+	git -C forked checkout local-foreign &&
     -+	test_commit -C forked --no-tag local-foreign-work local-foreign.t &&
     -+	git -C forked checkout --detach
     ++		git checkout local-one &&
     ++		test_commit --no-tag local-one-work local-one.t &&
     ++		git checkout local-foreign &&
     ++		test_commit --no-tag local-foreign-work local-foreign.t &&
     ++		git checkout --detach
     ++	)
      +'
      +
      +test_expect_success '--forked <upstream-tracking-branch> filters by upstream' '
 2:  91c35f10cc = 2:  4f8af602ba branch: convert delete_branches() to a flags argument
 3:  e101dd2886 = 3:  efc891c255 branch: let delete_branches skip unmerged branches on bulk refusal
 4:  6c3534901a = 4:  b1ecd38fe3 branch: prepare delete_branches for a bulk caller
 5:  5899013b8f ! 5:  998fb6a68c branch: add --delete-merged <branch>
     @@ builtin/branch.c: static int parse_opt_forked(const struct option *opt, const ch
       }
       
      +static int delete_merged_branches(int argc, const char **argv,
     -+				 int quiet)
     ++				 unsigned int flags)
      +{
      +	struct ref_store *refs = get_main_ref_store(the_repository);
      +	struct ref_filter filter = REF_FILTER_INIT;
     @@ builtin/branch.c: static int parse_opt_forked(const struct option *opt, const ch
      +				      FILTER_REFS_BRANCHES,
      +				      DELETE_BRANCH_SKIP_UNMERGED |
      +				      DELETE_BRANCH_NO_HEAD_FALLBACK |
     -+				      (quiet ? DELETE_BRANCH_QUIET : 0));
     ++				      flags);
      +
      +	strvec_clear(&deletable);
      +	ref_array_clear(&candidates);
     @@ builtin/branch.c: int cmd_branch(int argc,
       				      (quiet ? DELETE_BRANCH_QUIET : 0));
       		goto out;
      +	} else if (delete_merged) {
     -+		ret = delete_merged_branches(argc, argv, quiet);
     ++		ret = delete_merged_branches(argc, argv,
     ++					     quiet ? DELETE_BRANCH_QUIET : 0);
      +		goto out;
       	} else if (show_current) {
       		print_current_branch_name();
     @@ t/t3200-branch.sh: test_expect_success '--forked narrows a <pattern> argument' '
       '
       
      +test_expect_success '--delete-merged: setup' '
     -+	test_create_repo pm-upstream &&
     -+	test_commit -C pm-upstream base &&
     -+	git -C pm-upstream checkout -b next &&
     -+	test_commit -C pm-upstream one-commit &&
     -+	test_commit -C pm-upstream two-commit &&
     -+	git -C pm-upstream branch one HEAD~ &&
     -+	git -C pm-upstream branch two HEAD &&
     -+	git -C pm-upstream branch wip main &&
     -+	git -C pm-upstream checkout main &&
     -+	test_create_repo pm-fork
     ++	git init -b main upstream &&
     ++	(
     ++		cd upstream &&
     ++		test_commit base &&
     ++		git checkout -b next &&
     ++		test_commit next-work &&
     ++		git checkout main
     ++	) &&
     ++	git init -b main other &&
     ++	test_commit -C other other-base &&
     ++	git init -b main fork
      +'
      +
     -+test_expect_success '--delete-merged deletes branches integrated into upstream' '
     -+	test_when_finished "rm -rf pm-merged" &&
     -+	git clone pm-upstream pm-merged &&
     -+	git -C pm-merged remote add fork ../pm-fork &&
     -+	test_config -C pm-merged remote.pushDefault fork &&
     -+	test_config -C pm-merged push.default current &&
     -+	git -C pm-merged branch one one-commit &&
     -+	git -C pm-merged branch --set-upstream-to=origin/next one &&
     -+	git -C pm-merged branch two two-commit &&
     -+	git -C pm-merged branch --set-upstream-to=origin/next two &&
     -+
     -+	git -C pm-merged branch --delete-merged "origin/*" &&
     -+
     -+	test_must_fail git -C pm-merged rev-parse --verify refs/heads/one &&
     -+	test_must_fail git -C pm-merged rev-parse --verify refs/heads/two
     -+'
     -+
     -+test_expect_success '--delete-merged accepts a literal upstream' '
     -+	test_when_finished "rm -rf pm-literal" &&
     -+	git clone pm-upstream pm-literal &&
     -+	git -C pm-literal remote add fork ../pm-fork &&
     -+	test_config -C pm-literal remote.pushDefault fork &&
     -+	test_config -C pm-literal push.default current &&
     -+	git -C pm-literal branch one one-commit &&
     -+	git -C pm-literal branch --set-upstream-to=origin/next one &&
     -+
     -+	git -C pm-literal branch --delete-merged origin/next &&
     -+
     -+	test_must_fail git -C pm-literal rev-parse --verify refs/heads/one
     -+'
     -+
     -+test_expect_success '--delete-merged unions multiple <branch> arguments' '
     -+	test_when_finished "rm -rf pm-union" &&
     -+	git clone pm-upstream pm-union &&
     -+	git -C pm-union remote add fork ../pm-fork &&
     -+	test_config -C pm-union remote.pushDefault fork &&
     -+	test_config -C pm-union push.default current &&
     -+	git -C pm-union branch one one-commit &&
     -+	git -C pm-union branch --set-upstream-to=origin/next one &&
     -+	git -C pm-union branch two base &&
     -+	git -C pm-union branch --set-upstream-to=origin/main two &&
     -+	git -C pm-union checkout --detach &&
     -+
     -+	git -C pm-union branch --delete-merged origin/next origin/main &&
     -+
     -+	test_must_fail git -C pm-union rev-parse --verify refs/heads/one &&
     -+	test_must_fail git -C pm-union rev-parse --verify refs/heads/two
     -+'
     -+
     -+test_expect_success '--delete-merged accepts a local upstream' '
     -+	test_when_finished "rm -rf pm-local" &&
     -+	git clone pm-upstream pm-local &&
     -+	git -C pm-local remote add fork ../pm-fork &&
     -+	test_config -C pm-local remote.pushDefault fork &&
     -+	test_config -C pm-local push.default current &&
     -+	git -C pm-local checkout -b mainline &&
     -+	git -C pm-local branch one one-commit &&
     -+	git -C pm-local branch --set-upstream-to=mainline one &&
     -+	git -C pm-local merge --ff-only one-commit &&
     -+
     -+	git -C pm-local branch --delete-merged mainline &&
     -+
     -+	test_must_fail git -C pm-local rev-parse --verify refs/heads/one
     -+'
     -+
     -+test_expect_success '--delete-merged silently skips un-integrated commits' '
     -+	test_when_finished "rm -rf pm-unmerged" &&
     -+	git clone pm-upstream pm-unmerged &&
     -+	git -C pm-unmerged remote add fork ../pm-fork &&
     -+	test_config -C pm-unmerged remote.pushDefault fork &&
     -+	test_config -C pm-unmerged push.default current &&
     -+	git -C pm-unmerged checkout -b wip origin/wip &&
     -+	git -C pm-unmerged branch --set-upstream-to=origin/next wip &&
     -+	test_commit -C pm-unmerged local-only &&
     -+	git -C pm-unmerged checkout - &&
     -+
     -+	git -C pm-unmerged branch --delete-merged "origin/*" 2>err &&
     -+	test_grep ! "not fully merged" err &&
     -+	git -C pm-unmerged rev-parse --verify refs/heads/wip
     -+'
     -+
     -+test_expect_success '--delete-merged is silent about not-merged-to-HEAD' '
     -+	test_when_finished "rm -rf pm-nohead" &&
     -+	git clone pm-upstream pm-nohead &&
     -+	git -C pm-nohead remote add fork ../pm-fork &&
     -+	test_config -C pm-nohead remote.pushDefault fork &&
     -+	test_config -C pm-nohead push.default current &&
     -+	git -C pm-nohead branch topic one-commit &&
     -+	git -C pm-nohead branch --set-upstream-to=origin/next topic &&
     -+
     -+	git -C pm-nohead branch --delete-merged "origin/*" 2>err &&
     -+
     -+	test_grep ! "not yet merged to HEAD" err &&
     -+	test_must_fail git -C pm-nohead rev-parse --verify refs/heads/topic
     -+'
     -+
     -+test_expect_success '--delete-merged skips branches whose upstream is gone' '
     -+	test_when_finished "rm -rf pm-upstream-gone" &&
     -+	git clone pm-upstream pm-upstream-gone &&
     -+	git -C pm-upstream-gone remote add fork ../pm-fork &&
     -+	test_config -C pm-upstream-gone remote.pushDefault fork &&
     -+	test_config -C pm-upstream-gone push.default current &&
     -+	git -C pm-upstream-gone branch one one-commit &&
     -+	git -C pm-upstream-gone branch --set-upstream-to=origin/next one &&
     -+
     -+	git -C pm-upstream-gone update-ref -d refs/remotes/origin/next &&
     -+	git -C pm-upstream-gone branch --delete-merged "origin/*" &&
     -+
     -+	git -C pm-upstream-gone rev-parse --verify refs/heads/one
     -+'
     -+
     -+test_expect_success '--delete-merged never deletes the checked-out branch' '
     -+	test_when_finished "rm -rf pm-head" &&
     -+	git clone pm-upstream pm-head &&
     -+	git -C pm-head remote add fork ../pm-fork &&
     -+	test_config -C pm-head remote.pushDefault fork &&
     -+	test_config -C pm-head push.default current &&
     -+	git -C pm-head checkout -b one one-commit &&
     -+	git -C pm-head branch --set-upstream-to=origin/next one &&
     -+
     -+	git -C pm-head branch --delete-merged "origin/*" &&
     -+
     -+	git -C pm-head rev-parse --verify refs/heads/one
     -+'
     -+
     -+test_expect_success '--delete-merged spares branches that push back to their upstream' '
     -+	test_when_finished "rm -rf pm-push-eq" &&
     -+	git clone pm-upstream pm-push-eq &&
     -+	git -C pm-push-eq checkout --detach &&
     -+
     -+	git -C pm-push-eq branch --delete-merged "origin/*" &&
     -+
     -+	git -C pm-push-eq rev-parse --verify refs/heads/main
     -+'
     -+
     -+test_expect_success '--delete-merged spares a per-branch pushRemote==upstream remote' '
     -+	test_when_finished "rm -rf pm-push-branch" &&
     -+	git clone pm-upstream pm-push-branch &&
     -+	git -C pm-push-branch remote add fork ../pm-fork &&
     -+	test_config -C pm-push-branch remote.pushDefault fork &&
     -+	test_config -C pm-push-branch push.default current &&
     -+	test_config -C pm-push-branch branch.main.pushRemote origin &&
     -+	git -C pm-push-branch checkout --detach &&
     ++setup_repo_for_delete_merged () {
     ++	rm -rf repo &&
     ++	git clone upstream repo &&
     ++	(
     ++		cd repo &&
     ++		git remote add fork ../fork &&
     ++		git remote add other ../other &&
     ++		git config remote.pushDefault fork &&
     ++		git config push.default current &&
     ++		git fetch other
     ++	)
     ++}
      +
     -+	git -C pm-push-branch branch --delete-merged "origin/*" &&
     ++merged_branch () {
     ++	(
     ++		cd repo &&
     ++		git checkout -b "$1" "$2" &&
     ++		git commit --allow-empty -m "$1 work" &&
     ++		git push origin "$1:next" &&
     ++		git fetch origin &&
     ++		git branch --set-upstream-to="$2" "$1"
     ++	)
     ++}
      +
     -+	git -C pm-push-branch rev-parse --verify refs/heads/main
     ++test_expect_success '--delete-merged deletes merged branches and spares the rest' '
     ++	test_when_finished "rm -rf repo" &&
     ++	setup_repo_for_delete_merged &&
     ++	merged_branch merged origin/next &&
     ++	(
     ++		cd repo &&
     ++		git checkout -b unmerged origin/next &&
     ++		git commit --allow-empty -m "unmerged work" &&
     ++		git branch --set-upstream-to=origin/next unmerged &&
     ++		git checkout -b tracks-other other/main &&
     ++		git branch --set-upstream-to=other/main tracks-other &&
     ++		git checkout --detach
     ++	) &&
     ++	sha=$(git -C repo rev-parse --short merged) &&
     ++
     ++	git -C repo branch --delete-merged origin/next >actual 2>&1 &&
     ++
     ++	echo "Deleted branch merged (was $sha)." >expect &&
     ++	test_cmp expect actual &&
     ++	git -C repo for-each-ref --format="%(refname:short)" refs/heads/ >actual &&
     ++	cat >expect <<-\EOF &&
     ++	main
     ++	tracks-other
     ++	unmerged
     ++	EOF
     ++	test_cmp expect actual
      +'
      +
     -+test_expect_success '--delete-merged prunes when @{push} differs from @{upstream}' '
     -+	test_when_finished "rm -rf pm-push-diff" &&
     -+	git clone pm-upstream pm-push-diff &&
     -+	git -C pm-push-diff remote add fork ../pm-fork &&
     -+	test_config -C pm-push-diff remote.pushDefault fork &&
     -+	test_config -C pm-push-diff push.default current &&
     -+	git -C pm-push-diff branch topic one-commit &&
     -+	git -C pm-push-diff branch --set-upstream-to=origin/next topic &&
     -+	git -C pm-push-diff checkout --detach &&
     -+
     -+	git -C pm-push-diff branch --delete-merged "origin/*" &&
     -+
     -+	test_must_fail git -C pm-push-diff rev-parse --verify refs/heads/topic
     ++test_expect_success '--delete-merged deletes merged branches and spares protected ones' '
     ++	test_when_finished "rm -rf repo" &&
     ++	setup_repo_for_delete_merged &&
     ++	merged_branch on-next origin/next &&
     ++	merged_branch checked-out origin/next &&
     ++	merged_branch upstream-gone origin/next &&
     ++	(
     ++		cd repo &&
     ++		git checkout -b mainline main &&
     ++		git checkout -b on-local mainline &&
     ++		git branch --set-upstream-to=mainline on-local &&
     ++		git update-ref refs/remotes/origin/topic refs/remotes/origin/next &&
     ++		git branch --set-upstream-to=origin/topic upstream-gone &&
     ++		git update-ref -d refs/remotes/origin/topic &&
     ++		git branch --set-upstream-to=origin/main main &&
     ++		git config branch.main.pushRemote origin &&
     ++		git checkout -b tracks-other other/main &&
     ++		git branch --set-upstream-to=other/main tracks-other &&
     ++		git checkout checked-out
     ++	) &&
     ++
     ++	git -C repo branch --delete-merged origin/next mainline &&
     ++
     ++	git -C repo for-each-ref --format="%(refname:short)" refs/heads/ >actual &&
     ++	cat >expect <<-\EOF &&
     ++	checked-out
     ++	main
     ++	mainline
     ++	tracks-other
     ++	upstream-gone
     ++	EOF
     ++	test_cmp expect actual
      +'
      +
      +test_expect_success '--delete-merged requires at least one <branch>' '
      +	test_must_fail git -C forked branch --delete-merged 2>err &&
      +	test_grep "requires at least one <branch>" err
      +'
     -+
     -+test_expect_success '--delete-merged takes positional <branch> arguments' '
     -+	test_when_finished "rm -rf pm-positional" &&
     -+	git clone pm-upstream pm-positional &&
     -+	git -C pm-positional remote add fork ../pm-fork &&
     -+	test_config -C pm-positional remote.pushDefault fork &&
     -+	test_config -C pm-positional push.default current &&
     -+	git -C pm-positional branch one one-commit &&
     -+	git -C pm-positional branch --set-upstream-to=origin/next one &&
     -+	git -C pm-positional branch two base &&
     -+	git -C pm-positional branch --set-upstream-to=origin/main two &&
     -+	git -C pm-positional checkout --detach &&
     -+
     -+	git -C pm-positional branch --delete-merged origin/next origin/main &&
     -+
     -+	test_must_fail git -C pm-positional rev-parse --verify refs/heads/one &&
     -+	test_must_fail git -C pm-positional rev-parse --verify refs/heads/two
     -+'
      +
       test_done
 6:  72aaca0666 ! 6:  a27d2724a2 branch: add branch.<name>.deleteMerged opt-out
     @@ Documentation/git-branch.adoc: A branch is not deleted when:
       A branch whose work has not yet been merged into its upstream is
      
       ## builtin/branch.c ##
     +@@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
     + 	struct ref_filter filter = REF_FILTER_INIT;
     + 	struct ref_array candidates = { 0 };
     + 	struct strvec deletable = STRVEC_INIT;
     ++	struct strbuf key = STRBUF_INIT;
     ++	bool quiet = flags & DELETE_BRANCH_QUIET;
     + 	int i, ret = 0;
     + 
     + 	if (!argc)
      @@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
       		const char *short_name;
       		struct branch *branch;
       		const char *upstream, *push;
     -+		struct strbuf key = STRBUF_INIT;
      +		int opt_out;
       
       		if (!skip_prefix(full_name, "refs/heads/", &short_name))
     @@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
       		if (!push || !strcmp(push, upstream))
       			continue;
       
     ++		strbuf_reset(&key);
      +		strbuf_addf(&key, "branch.%s.deletemerged", short_name);
      +		if (!repo_config_get_bool(the_repository, key.buf, &opt_out) &&
      +		    !opt_out) {
     @@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
      +				fprintf(stderr,
      +					_("Skipping '%s' (branch.%s.deleteMerged is false)\n"),
      +					short_name, short_name);
     -+			strbuf_release(&key);
      +			continue;
      +		}
     -+		strbuf_release(&key);
      +
       		strvec_push(&deletable, short_name);
       	}
       
     +@@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
     + 				      DELETE_BRANCH_NO_HEAD_FALLBACK |
     + 				      flags);
     + 
     ++	strbuf_release(&key);
     + 	strvec_clear(&deletable);
     + 	ref_array_clear(&candidates);
     + 	ref_filter_clear(&filter);
      
       ## t/t3200-branch.sh ##
     -@@ t/t3200-branch.sh: test_expect_success '--delete-merged takes positional <branch> arguments' '
     - 	test_must_fail git -C pm-positional rev-parse --verify refs/heads/two
     +@@ t/t3200-branch.sh: test_expect_success '--delete-merged requires at least one <branch>' '
     + 	test_grep "requires at least one <branch>" err
       '
       
      +test_expect_success '--delete-merged honours branch.<name>.deleteMerged=false' '
     -+	test_when_finished "rm -rf pm-optout" &&
     -+	git clone pm-upstream pm-optout &&
     -+	git -C pm-optout remote add fork ../pm-fork &&
     -+	test_config -C pm-optout remote.pushDefault fork &&
     -+	test_config -C pm-optout push.default current &&
     -+	git -C pm-optout branch one one-commit &&
     -+	git -C pm-optout branch --set-upstream-to=origin/next one &&
     -+	git -C pm-optout branch two two-commit &&
     -+	git -C pm-optout branch --set-upstream-to=origin/next two &&
     -+	test_config -C pm-optout branch.one.deleteMerged false &&
     ++	test_when_finished "rm -rf repo" &&
     ++	setup_repo_for_delete_merged &&
     ++	merged_branch deleted origin/next &&
     ++	merged_branch kept origin/next &&
     ++	git -C repo config branch.kept.deleteMerged false &&
     ++	git -C repo checkout --detach &&
      +
     -+	git -C pm-optout branch --delete-merged "origin/*" 2>err &&
     ++	git -C repo branch --delete-merged origin/next 2>err &&
      +
     -+	git -C pm-optout rev-parse --verify refs/heads/one &&
     -+	test_must_fail git -C pm-optout rev-parse --verify refs/heads/two &&
     -+	test_grep "Skipping .one." err
     ++	test_grep "Skipping .kept." err &&
     ++	test_must_fail git -C repo rev-parse --verify refs/heads/deleted &&
     ++	git -C repo rev-parse --verify refs/heads/kept
      +'
      +
     -+test_expect_success 'branch -d still deletes a deleteMerged=false branch' '
     -+	test_when_finished "rm -rf pm-optout-d" &&
     -+	git clone pm-upstream pm-optout-d &&
     -+	git -C pm-optout-d branch one one-commit &&
     -+	git -C pm-optout-d branch --set-upstream-to=origin/next one &&
     -+	test_config -C pm-optout-d branch.one.deleteMerged false &&
     ++test_expect_success "branch -d still deletes a deleteMerged=false branch" '
     ++	test_when_finished "rm -rf repo" &&
     ++	setup_repo_for_delete_merged &&
     ++	merged_branch kept origin/next &&
     ++	git -C repo config branch.kept.deleteMerged false &&
     ++	git -C repo checkout --detach &&
      +
     -+	git -C pm-optout-d branch -d one &&
     -+	test_must_fail git -C pm-optout-d rev-parse --verify refs/heads/one
     ++	git -C repo branch -d kept &&
     ++	test_must_fail git -C repo rev-parse --verify refs/heads/kept
      +'
      +
       test_done
 7:  7b2b01b988 ! 7:  6d5c52353e branch: add --dry-run for --delete-merged
     @@ Documentation/git-branch.adoc: A branch whose work has not yet been merged into
       `--verbose`::
      
       ## builtin/branch.c ##
     -@@ builtin/branch.c: static int parse_opt_forked(const struct option *opt, const char *arg, int unset
     - }
     - 
     - static int delete_merged_branches(int argc, const char **argv,
     --				 int quiet)
     -+				 int quiet, int dry_run)
     - {
     - 	struct ref_store *refs = get_main_ref_store(the_repository);
     - 	struct ref_filter filter = REF_FILTER_INIT;
     -@@ builtin/branch.c: static int delete_merged_branches(int argc, const char **argv,
     - 				      FILTER_REFS_BRANCHES,
     - 				      DELETE_BRANCH_SKIP_UNMERGED |
     - 				      DELETE_BRANCH_NO_HEAD_FALLBACK |
     --				      (quiet ? DELETE_BRANCH_QUIET : 0));
     -+				      (quiet ? DELETE_BRANCH_QUIET : 0) |
     -+				      (dry_run ? DELETE_BRANCH_DRY_RUN : 0));
     - 
     - 	strvec_clear(&deletable);
     - 	ref_array_clear(&candidates);
      @@ builtin/branch.c: int cmd_branch(int argc,
       	int delete = 0, rename = 0, copy = 0, list = 0,
       	    unset_upstream = 0, show_current = 0, edit_description = 0;
     @@ builtin/branch.c: int cmd_branch(int argc,
       		if (!submodule_propagate_branches)
       			die(_("branch with --recurse-submodules can only be used if submodule.propagateBranches is enabled"));
      @@ builtin/branch.c: int cmd_branch(int argc,
     - 				      (quiet ? DELETE_BRANCH_QUIET : 0));
       		goto out;
       	} else if (delete_merged) {
     --		ret = delete_merged_branches(argc, argv, quiet);
     -+		ret = delete_merged_branches(argc, argv, quiet, dry_run);
     + 		ret = delete_merged_branches(argc, argv,
     +-					     quiet ? DELETE_BRANCH_QUIET : 0);
     ++					     (quiet ? DELETE_BRANCH_QUIET : 0) |
     ++					     (dry_run ? DELETE_BRANCH_DRY_RUN : 0));
       		goto out;
       	} else if (show_current) {
       		print_current_branch_name();
      
       ## t/t3200-branch.sh ##
     -@@ t/t3200-branch.sh: test_expect_success 'branch -d still deletes a deleteMerged=false branch' '
     - 	test_must_fail git -C pm-optout-d rev-parse --verify refs/heads/one
     +@@ t/t3200-branch.sh: test_expect_success '--delete-merged deletes merged branches and spares the rest
     + 	) &&
     + 	sha=$(git -C repo rev-parse --short merged) &&
     + 
     +-	git -C repo branch --delete-merged origin/next >actual 2>&1 &&
     ++	git -C repo branch --dry-run --delete-merged origin/next >actual 2>&1 &&
     ++	echo "Would delete branch merged (was $sha)." >expect &&
     ++	test_cmp expect actual &&
     ++	git -C repo rev-parse --verify refs/heads/merged &&
     + 
     ++	git -C repo branch --delete-merged origin/next >actual 2>&1 &&
     + 	echo "Deleted branch merged (was $sha)." >expect &&
     + 	test_cmp expect actual &&
     + 	git -C repo for-each-ref --format="%(refname:short)" refs/heads/ >actual &&
     +@@ t/t3200-branch.sh: test_expect_success "branch -d still deletes a deleteMerged=false branch" '
     + 	test_must_fail git -C repo rev-parse --verify refs/heads/kept
       '
       
     -+test_expect_success '--delete-merged --dry-run lists but does not delete' '
     -+	test_when_finished "rm -rf pm-dry" &&
     -+	git clone pm-upstream pm-dry &&
     -+	git -C pm-dry remote add fork ../pm-fork &&
     -+	test_config -C pm-dry remote.pushDefault fork &&
     -+	test_config -C pm-dry push.default current &&
     -+	git -C pm-dry branch one one-commit &&
     -+	git -C pm-dry branch --set-upstream-to=origin/next one &&
     -+	git -C pm-dry branch two two-commit &&
     -+	git -C pm-dry branch --set-upstream-to=origin/next two &&
     -+
     -+	git -C pm-dry branch --dry-run --delete-merged "origin/*" >actual &&
     -+	test_grep "Would delete branch one " actual &&
     -+	test_grep "Would delete branch two " actual &&
     -+
     -+	git -C pm-dry rev-parse --verify refs/heads/one &&
     -+	git -C pm-dry rev-parse --verify refs/heads/two
     -+'
     -+
     -+test_expect_success '--delete-merged --dry-run only lists branches the live run would delete' '
     -+	test_when_finished "rm -rf pm-dry-mixed" &&
     -+	git clone pm-upstream pm-dry-mixed &&
     -+	git -C pm-dry-mixed remote add fork ../pm-fork &&
     -+	test_config -C pm-dry-mixed remote.pushDefault fork &&
     -+	test_config -C pm-dry-mixed push.default current &&
     -+	git -C pm-dry-mixed checkout -b wip origin/next &&
     -+	git -C pm-dry-mixed branch --set-upstream-to=origin/next wip &&
     -+	test_commit -C pm-dry-mixed local-only &&
     -+	git -C pm-dry-mixed checkout - &&
     -+	git -C pm-dry-mixed branch merged one-commit &&
     -+	git -C pm-dry-mixed branch --set-upstream-to=origin/next merged &&
     -+
     -+	git -C pm-dry-mixed branch --dry-run --delete-merged "origin/*" >out &&
     -+	test_grep "Would delete branch merged" out &&
     -+	test_grep ! "Would delete branch wip" out &&
     -+	git -C pm-dry-mixed rev-parse --verify refs/heads/wip &&
     -+	git -C pm-dry-mixed rev-parse --verify refs/heads/merged
     -+'
     -+
      +test_expect_success '--dry-run without --delete-merged is rejected' '
      +	test_must_fail git -C forked branch --dry-run 2>err &&
      +	test_grep "requires --delete-merged" err

-- 
gitgitgadget

  parent reply	other threads:[~2026-06-18 19:25 UTC|newest]

Thread overview: 168+ 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-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                             ` Harald Nordgren via GitGitGadget [this message]
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

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=pull.2285.v16.git.git.1781810729.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=haraldnordgren@gmail.com \
    --cc=j6t@kdbg.org \
    --cc=kristofferhaugsbakk@fastmail.com \
    --cc=phillip.wood123@gmail.com \
    /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