Skip to content

Commit 7ecbbf8

Browse files
jaysoffiangitster
authored andcommitted
builtin-remote: new show output style
The existing output of "git remote show <remote>" is too verbose for the information it provides. This patch teaches it to provide more information in less space. The output for push refspecs is addressed in the next patch. Before the patch: $ git remote show origin * remote origin URL: git://git.kernel.org/pub/scm/git/git.git HEAD branch: master Remote branch merged with 'git pull' while on branch master master Remote branch merged with 'git pull' while on branch next next Remote branches merged with 'git pull' while on branch octopus foo bar baz frotz New remote branch (next fetch will store in remotes/origin) html Stale tracking branch (use 'git remote prune') bogus Tracked remote branches maint man master next pu todo After this patch: $ git remote show origin * remote origin URL: git://git.kernel.org/pub/scm/git/git.git HEAD branch: master Remote branches: bogus stale (use 'git remote prune' to remove) html new (next fetch will store in remotes/origin) maint tracked man tracked master tracked next tracked pu tracked todo tracked Local branches configured for 'git pull': master rebases onto remote master next rebases onto remote next octopus merges with remote foo and with remote bar and with remote baz and with remote frotz $ git remote show origin -n * remote origin URL: git://git.kernel.org/pub/scm/git/git.git HEAD branch: (not queried) Remote branches: (status not queried) bogus maint man master next pu todo Local branches configured for 'git pull': master rebases onto remote master next rebases onto remote next octopus merges with remote foo and with remote bar and with remote baz and with remote frotz Signed-off-by: Jay Soffian <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fbb074c commit 7ecbbf8

File tree

2 files changed

+159
-61
lines changed

2 files changed

+159
-61
lines changed

builtin-remote.c

Lines changed: 138 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ static int add(int argc, const char **argv)
149149
struct branch_info {
150150
char *remote_name;
151151
struct string_list merge;
152+
int rebase;
152153
};
153154

154155
static struct string_list branch_list;
@@ -165,10 +166,11 @@ static const char *abbrev_ref(const char *name, const char *prefix)
165166
static int config_read_branches(const char *key, const char *value, void *cb)
166167
{
167168
if (!prefixcmp(key, "branch.")) {
169+
const char *orig_key = key;
168170
char *name;
169171
struct string_list_item *item;
170172
struct branch_info *info;
171-
enum { REMOTE, MERGE } type;
173+
enum { REMOTE, MERGE, REBASE } type;
172174

173175
key += 7;
174176
if (!postfixcmp(key, ".remote")) {
@@ -177,6 +179,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)
177179
} else if (!postfixcmp(key, ".merge")) {
178180
name = xstrndup(key, strlen(key) - 6);
179181
type = MERGE;
182+
} else if (!postfixcmp(key, ".rebase")) {
183+
name = xstrndup(key, strlen(key) - 7);
184+
type = REBASE;
180185
} else
181186
return 0;
182187

@@ -187,9 +192,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)
187192
info = item->util;
188193
if (type == REMOTE) {
189194
if (info->remote_name)
190-
warning("more than one branch.%s", key);
195+
warning("more than one %s", orig_key);
191196
info->remote_name = xstrdup(value);
192-
} else {
197+
} else if (type == MERGE) {
193198
char *space = strchr(value, ' ');
194199
value = abbrev_branch(value);
195200
while (space) {
@@ -200,7 +205,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
200205
space = strchr(value, ' ');
201206
}
202207
string_list_append(xstrdup(value), &info->merge);
203-
}
208+
} else
209+
info->rebase = git_config_bool(orig_key, value);
204210
}
205211
return 0;
206212
}
@@ -215,6 +221,7 @@ static void read_branches(void)
215221
struct ref_states {
216222
struct remote *remote;
217223
struct string_list new, stale, tracked, heads;
224+
int queried;
218225
};
219226

220227
static int handle_one_branch(const char *refname,
@@ -637,20 +644,6 @@ static int rm(int argc, const char **argv)
637644
return result;
638645
}
639646

640-
static void show_list(const char *title, struct string_list *list,
641-
const char *extra_arg)
642-
{
643-
int i;
644-
645-
if (!list->nr)
646-
return;
647-
648-
printf(title, list->nr > 1 ? "es" : "", extra_arg);
649-
printf("\n");
650-
for (i = 0; i < list->nr; i++)
651-
printf(" %s\n", list->items[i].string);
652-
}
653-
654647
static void free_remote_ref_states(struct ref_states *states)
655648
{
656649
string_list_clear(&states->new, 0);
@@ -695,6 +688,7 @@ static int get_remote_ref_states(const char *name,
695688
remote_refs = transport_get_remote_refs(transport);
696689
transport_disconnect(transport);
697690

691+
states->queried = 1;
698692
if (query & GET_REF_STATES)
699693
get_ref_states(remote_refs, states);
700694
if (query & GET_HEAD_NAMES)
@@ -707,6 +701,104 @@ static int get_remote_ref_states(const char *name,
707701
return 0;
708702
}
709703

704+
struct show_info {
705+
struct string_list *list;
706+
struct ref_states *states;
707+
int width;
708+
int any_rebase;
709+
};
710+
711+
int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
712+
{
713+
struct show_info *info = cb_data;
714+
int n = strlen(item->string);
715+
if (n > info->width)
716+
info->width = n;
717+
string_list_insert(item->string, info->list);
718+
return 0;
719+
}
720+
721+
int show_remote_info_item(struct string_list_item *item, void *cb_data)
722+
{
723+
struct show_info *info = cb_data;
724+
struct ref_states *states = info->states;
725+
const char *name = item->string;
726+
727+
if (states->queried) {
728+
const char *fmt = "%s";
729+
const char *arg = "";
730+
if (string_list_has_string(&states->new, name)) {
731+
fmt = " new (next fetch will store in remotes/%s)";
732+
arg = states->remote->name;
733+
} else if (string_list_has_string(&states->tracked, name))
734+
arg = " tracked";
735+
else if (string_list_has_string(&states->stale, name))
736+
arg = " stale (use 'git remote prune' to remove)";
737+
else
738+
arg = " ???";
739+
printf(" %-*s", info->width, name);
740+
printf(fmt, arg);
741+
printf("\n");
742+
} else
743+
printf(" %s\n", name);
744+
745+
return 0;
746+
}
747+
748+
int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
749+
{
750+
struct show_info *show_info = cb_data;
751+
struct ref_states *states = show_info->states;
752+
struct branch_info *branch_info = branch_item->util;
753+
struct string_list_item *item;
754+
int n;
755+
756+
if (!branch_info->merge.nr || !branch_info->remote_name ||
757+
strcmp(states->remote->name, branch_info->remote_name))
758+
return 0;
759+
if ((n = strlen(branch_item->string)) > show_info->width)
760+
show_info->width = n;
761+
if (branch_info->rebase)
762+
show_info->any_rebase = 1;
763+
764+
item = string_list_insert(branch_item->string, show_info->list);
765+
item->util = branch_info;
766+
767+
return 0;
768+
}
769+
770+
int show_local_info_item(struct string_list_item *item, void *cb_data)
771+
{
772+
struct show_info *show_info = cb_data;
773+
struct branch_info *branch_info = item->util;
774+
struct string_list *merge = &branch_info->merge;
775+
const char *also;
776+
int i;
777+
778+
if (branch_info->rebase && branch_info->merge.nr > 1) {
779+
error("invalid branch.%s.merge; cannot rebase onto > 1 branch",
780+
item->string);
781+
return 0;
782+
}
783+
784+
printf(" %-*s ", show_info->width, item->string);
785+
if (branch_info->rebase) {
786+
printf("rebases onto remote %s\n", merge->items[0].string);
787+
return 0;
788+
} else if (show_info->any_rebase) {
789+
printf(" merges with remote %s\n", merge->items[0].string);
790+
also = " and with remote";
791+
} else {
792+
printf("merges with remote %s\n", merge->items[0].string);
793+
also = " and with remote";
794+
}
795+
for (i = 1; i < merge->nr; i++)
796+
printf(" %-*s %s %s\n", show_info->width, "", also,
797+
merge->items[i].string);
798+
799+
return 0;
800+
}
801+
710802
static int show(int argc, const char **argv)
711803
{
712804
int no_query = 0, result = 0, query_flag = 0;
@@ -716,6 +808,8 @@ static int show(int argc, const char **argv)
716808
OPT_END()
717809
};
718810
struct ref_states states;
811+
struct string_list info_list = { NULL, 0, 0, 0 };
812+
struct show_info info;
719813

720814
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
721815

@@ -726,6 +820,9 @@ static int show(int argc, const char **argv)
726820
query_flag = (GET_REF_STATES | GET_HEAD_NAMES);
727821

728822
memset(&states, 0, sizeof(states));
823+
memset(&info, 0, sizeof(info));
824+
info.states = &states;
825+
info.list = &info_list;
729826
for (; argc; argc--, argv++) {
730827
int i;
731828

@@ -747,32 +844,29 @@ static int show(int argc, const char **argv)
747844
printf(" %s\n", states.heads.items[i].string);
748845
}
749846

750-
for (i = 0; i < branch_list.nr; i++) {
751-
struct string_list_item *branch = branch_list.items + i;
752-
struct branch_info *info = branch->util;
753-
int j;
754-
755-
if (!info->merge.nr || strcmp(*argv, info->remote_name))
756-
continue;
757-
printf(" Remote branch%s merged with 'git pull' "
758-
"while on branch %s\n ",
759-
info->merge.nr > 1 ? "es" : "",
760-
branch->string);
761-
for (j = 0; j < info->merge.nr; j++)
762-
printf(" %s", info->merge.items[j].string);
763-
printf("\n");
764-
}
765-
766-
if (!no_query) {
767-
show_list(" New remote branch%s (next fetch "
768-
"will store in remotes/%s)",
769-
&states.new, states.remote->name);
770-
show_list(" Stale tracking branch%s (use 'git remote "
771-
"prune')", &states.stale, "");
772-
}
773-
774-
show_list(" Tracked remote branch%s", &states.tracked, "");
775-
847+
/* remote branch info */
848+
info.width = 0;
849+
for_each_string_list(add_remote_to_show_info, &states.new, &info);
850+
for_each_string_list(add_remote_to_show_info, &states.tracked, &info);
851+
for_each_string_list(add_remote_to_show_info, &states.stale, &info);
852+
if (info.list->nr)
853+
printf(" Remote branch%s:%s\n",
854+
info.list->nr > 1 ? "es" : "",
855+
no_query ? " (status not queried)" : "");
856+
for_each_string_list(show_remote_info_item, info.list, &info);
857+
string_list_clear(info.list, 0);
858+
859+
/* git pull info */
860+
info.width = 0;
861+
info.any_rebase = 0;
862+
for_each_string_list(add_local_to_show_info, &branch_list, &info);
863+
if (info.list->nr)
864+
printf(" Local branch%s configured for 'git pull':\n",
865+
info.list->nr > 1 ? "es" : "");
866+
for_each_string_list(show_local_info_item, info.list, &info);
867+
string_list_clear(info.list, 0);
868+
869+
/* git push info */
776870
if (states.remote->push_refspec_nr) {
777871
printf(" Local branch%s pushed with 'git push'\n",
778872
states.remote->push_refspec_nr > 1 ?

t/t5505-remote.sh

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ tokens_match () {
2828
}
2929

3030
check_remote_track () {
31-
actual=$(git remote show "$1" | sed -e '1,/Tracked/d') &&
31+
actual=$(git remote show "$1" | sed -ne 's|^ \(.*\) tracked$|\1|p')
3232
shift &&
3333
tokens_match "$*" "$actual"
3434
}
@@ -137,13 +137,15 @@ cat > test/expect << EOF
137137
* remote origin
138138
URL: $(pwd)/one
139139
HEAD branch: master
140-
Remote branch merged with 'git pull' while on branch master
141-
master
142-
New remote branch (next fetch will store in remotes/origin)
143-
master
144-
Tracked remote branches
145-
master
146-
side
140+
Remote branches:
141+
master new (next fetch will store in remotes/origin)
142+
side tracked
143+
Local branches configured for 'git pull':
144+
master merges with remote master
145+
octopus merges with remote topic-a
146+
and with remote topic-b
147+
and with remote topic-c
148+
rebase rebases onto remote master
147149
Local branches pushed with 'git push'
148150
master:upstream
149151
+refs/tags/lastbackup
@@ -156,32 +158,34 @@ EOF
156158

157159
test_expect_success 'show' '
158160
(cd test &&
159-
git config --add remote.origin.fetch \
160-
refs/heads/master:refs/heads/upstream &&
161+
git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
161162
git fetch &&
163+
git branch --track octopus origin/master &&
164+
git branch --track rebase origin/master &&
162165
git branch -d -r origin/master &&
163166
git config --add remote.two.url ../two &&
167+
git config branch.rebase.rebase true &&
168+
git config branch.octopus.merge "topic-a topic-b topic-c" &&
164169
(cd ../one &&
165170
echo 1 > file &&
166171
test_tick &&
167172
git commit -m update file) &&
168-
git config remote.origin.push \
169-
refs/heads/master:refs/heads/upstream &&
170-
git config --add remote.origin.push \
171-
+refs/tags/lastbackup &&
173+
git config remote.origin.push refs/heads/master:refs/heads/upstream &&
174+
git config --add remote.origin.push +refs/tags/lastbackup &&
172175
git remote show origin two > output &&
176+
git branch -d rebase octopus &&
173177
test_cmp expect output)
174178
'
175179

176180
cat > test/expect << EOF
177181
* remote origin
178182
URL: $(pwd)/one
179183
HEAD branch: (not queried)
180-
Remote branch merged with 'git pull' while on branch master
181-
master
182-
Tracked remote branches
184+
Remote branches: (status not queried)
183185
master
184186
side
187+
Local branch configured for 'git pull':
188+
master merges with remote master
185189
Local branches pushed with 'git push'
186190
master:upstream
187191
+refs/tags/lastbackup

0 commit comments

Comments
 (0)