Skip to content

Commit 5150646

Browse files
HaraldNordgrengitster
authored andcommitted
branch: add --all-remotes flag
Combined with --forked or --prune-merged, --all-remotes acts on every configured remote, in addition to any explicit <remote> arguments. Used alone, it errors out. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent fa1f781 commit 5150646

3 files changed

Lines changed: 75 additions & 14 deletions

File tree

Documentation/git-branch.adoc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ git branch (-m|-M) [<old-branch>] <new-branch>
2424
git branch (-c|-C) [<old-branch>] <new-branch>
2525
git branch (-d|-D) [-r] <branch-name>...
2626
git branch --edit-description [<branch-name>]
27-
git branch --forked <remote>...
28-
git branch [-f] --prune-merged <remote>...
27+
git branch --forked (<remote>... | --all-remotes)
28+
git branch [-f] --prune-merged (<remote>... | --all-remotes)
2929

3030
DESCRIPTION
3131
-----------
@@ -226,6 +226,11 @@ With `--force` (or `-f`), delete them regardless. The currently
226226
checked-out branch in any worktree is always preserved, as is
227227
any branch with `branch.<name>.pruneMerged` set to `false`.
228228

229+
`--all-remotes`::
230+
With `--forked` or `--prune-merged`, act on every
231+
configured remote in addition to any explicit _<remote>_
232+
arguments.
233+
229234
`-v`::
230235
`-vv`::
231236
`--verbose`::

builtin/branch.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,13 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
685685
free_worktrees(worktrees);
686686
}
687687

688+
static int collect_remote_name(struct remote *remote, void *cb_data)
689+
{
690+
struct string_list *remote_names = cb_data;
691+
string_list_insert(remote_names, remote->name);
692+
return 0;
693+
}
694+
688695
static void parse_forked_args(int argc, const char **argv,
689696
struct string_list *remote_names,
690697
struct string_list *tracking_refs)
@@ -754,7 +761,7 @@ static int collect_forked_branch(const struct reference *ref, void *cb_data)
754761
return 0;
755762
}
756763

757-
static void collect_forked_set(int argc, const char **argv,
764+
static void collect_forked_set(int argc, const char **argv, int all_remotes,
758765
struct string_list *out)
759766
{
760767
struct string_list remote_names = STRING_LIST_INIT_NODUP;
@@ -766,6 +773,8 @@ static void collect_forked_set(int argc, const char **argv,
766773
};
767774

768775
parse_forked_args(argc, argv, &remote_names, &tracking_refs);
776+
if (all_remotes)
777+
for_each_remote(collect_remote_name, &remote_names);
769778

770779
refs_for_each_branch_ref(get_main_ref_store(the_repository),
771780
collect_forked_branch, &cb);
@@ -776,35 +785,35 @@ static void collect_forked_set(int argc, const char **argv,
776785
string_list_clear(&tracking_refs, 0);
777786
}
778787

779-
static int list_forked_branches(int argc, const char **argv)
788+
static int list_forked_branches(int argc, const char **argv, int all_remotes)
780789
{
781790
struct string_list out = STRING_LIST_INIT_DUP;
782791
struct string_list_item *item;
783792

784-
if (!argc)
785-
die(_("--forked requires at least one <remote>"));
793+
if (!argc && !all_remotes)
794+
die(_("--forked requires at least one <remote> or --all-remotes"));
786795

787-
collect_forked_set(argc, argv, &out);
796+
collect_forked_set(argc, argv, all_remotes, &out);
788797
for_each_string_list_item(item, &out)
789798
puts(item->string);
790799

791800
string_list_clear(&out, 0);
792801
return 0;
793802
}
794803

795-
static int prune_merged_branches(int argc, const char **argv, int force,
796-
int quiet)
804+
static int prune_merged_branches(int argc, const char **argv,
805+
int all_remotes, int force, int quiet)
797806
{
798807
struct string_list candidates = STRING_LIST_INIT_DUP;
799808
struct strvec deletable = STRVEC_INIT;
800809
struct string_list_item *item;
801810
int n_not_merged = 0;
802811
int ret = 0;
803812

804-
if (!argc)
805-
die(_("--prune-merged requires at least one <remote>"));
813+
if (!argc && !all_remotes)
814+
die(_("--prune-merged requires at least one <remote> or --all-remotes"));
806815

807-
collect_forked_set(argc, argv, &candidates);
816+
collect_forked_set(argc, argv, all_remotes, &candidates);
808817

809818
for_each_string_list_item(item, &candidates) {
810819
const char *short_name = item->string;
@@ -911,6 +920,7 @@ int cmd_branch(int argc,
911920
unset_upstream = 0, show_current = 0, edit_description = 0;
912921
int forked = 0;
913922
int prune_merged = 0;
923+
int all_remotes = 0;
914924
const char *new_upstream = NULL;
915925
int noncreate_actions = 0;
916926
/* possible options */
@@ -968,6 +978,9 @@ int cmd_branch(int argc,
968978
N_("list local branches forked from the given <remote>s")),
969979
OPT_BOOL(0, "prune-merged", &prune_merged,
970980
N_("delete local branches forked from the given <remote>s that are merged into their upstream")),
981+
OPT_BOOL_F(0, "all-remotes", &all_remotes,
982+
N_("with --forked or --prune-merged, act on every configured remote"),
983+
PARSE_OPT_NONEG),
971984
OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE),
972985
OPT_MERGED(&filter, N_("print only branches that are merged")),
973986
OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
@@ -1011,6 +1024,9 @@ int cmd_branch(int argc,
10111024
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
10121025
0);
10131026

1027+
if (all_remotes && !forked && !prune_merged)
1028+
die(_("--all-remotes requires --forked or --prune-merged"));
1029+
10141030
if (!delete && !rename && !copy && !edit_description && !new_upstream &&
10151031
!show_current && !unset_upstream && !forked && !prune_merged &&
10161032
argc == 0)
@@ -1064,10 +1080,10 @@ int cmd_branch(int argc,
10641080
quiet, 0, NULL);
10651081
goto out;
10661082
} else if (forked) {
1067-
ret = list_forked_branches(argc, argv);
1083+
ret = list_forked_branches(argc, argv, all_remotes);
10681084
goto out;
10691085
} else if (prune_merged) {
1070-
ret = prune_merged_branches(argc, argv, force, quiet);
1086+
ret = prune_merged_branches(argc, argv, all_remotes, force, quiet);
10711087
goto out;
10721088
} else if (show_current) {
10731089
print_current_branch_name();

t/t3200-branch.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,27 @@ test_expect_success '--forked requires at least one <remote>' '
17711771
test_grep "at least one <remote>" err
17721772
'
17731773

1774+
test_expect_success '--forked --all-remotes covers every configured remote' '
1775+
git -C forked branch --forked --all-remotes >actual &&
1776+
cat >expect <<-\EOF &&
1777+
local-foreign
1778+
local-one
1779+
local-two
1780+
main
1781+
EOF
1782+
test_cmp expect actual
1783+
'
1784+
1785+
test_expect_success '--forked --all-remotes still validates explicit <remote>' '
1786+
test_must_fail git -C forked branch --forked nope --all-remotes 2>err &&
1787+
test_grep "neither a configured remote nor a remote-tracking branch" err
1788+
'
1789+
1790+
test_expect_success '--all-remotes alone is rejected' '
1791+
test_must_fail git -C forked branch --all-remotes 2>err &&
1792+
test_grep "requires --forked or --prune-merged" err
1793+
'
1794+
17741795
test_expect_success '--prune-merged: setup' '
17751796
test_create_repo pm-upstream &&
17761797
test_commit -C pm-upstream base &&
@@ -1892,4 +1913,23 @@ test_expect_success 'branch -d still deletes a pruneMerged=false branch' '
18921913
test_must_fail git -C pm-optout-d rev-parse --verify refs/heads/one
18931914
'
18941915

1916+
test_expect_success '--prune-merged --all-remotes covers every configured remote' '
1917+
test_when_finished "rm -rf pm-allremotes" &&
1918+
git clone pm-upstream pm-allremotes &&
1919+
test_create_repo pm-other &&
1920+
test_commit -C pm-other other-base &&
1921+
git -C pm-other branch foreign other-base &&
1922+
git -C pm-allremotes remote add other ../pm-other &&
1923+
git -C pm-allremotes fetch other &&
1924+
git -C pm-allremotes branch one --track origin/one &&
1925+
git -C pm-allremotes branch foreign --track other/foreign &&
1926+
1927+
git -C pm-allremotes update-ref -d refs/remotes/origin/one &&
1928+
git -C pm-allremotes update-ref -d refs/remotes/other/foreign &&
1929+
git -C pm-allremotes branch --force --prune-merged --all-remotes &&
1930+
1931+
test_must_fail git -C pm-allremotes rev-parse --verify refs/heads/one &&
1932+
test_must_fail git -C pm-allremotes rev-parse --verify refs/heads/foreign
1933+
'
1934+
18951935
test_done

0 commit comments

Comments
 (0)