149
struct branch_info {
150
char *remote_name;
151
struct string_list merge;
152
+ int rebase;
153
};
154
155
static struct string_list branch_list;
166
static int config_read_branches(const char *key, const char *value, void *cb)
167
{
168
if (!prefixcmp(key, "branch.")) {
169
+ const char *orig_key = key;
170
char *name;
171
struct string_list_item *item;
172
struct branch_info *info;
171
- enum { REMOTE, MERGE } type;
173
+ enum { REMOTE, MERGE, REBASE } type;
174
175
key += 7;
176
if (!postfixcmp(key, ".remote")) {
179
} else if (!postfixcmp(key, ".merge")) {
180
name = xstrndup(key, strlen(key) - 6);
181
type = MERGE;
182
+ } else if (!postfixcmp(key, ".rebase")) {
183
+ name = xstrndup(key, strlen(key) - 7);
184
+ type = REBASE;
185
} else
186
return 0;
187
192
info = item->util;
193
if (type == REMOTE) {
194
if (info->remote_name)
190
- warning("more than one branch.%s", key);
195
+ warning("more than one %s", orig_key);
196
info->remote_name = xstrdup(value);
192
- } else {
197
+ } else if (type == MERGE) {
198
char *space = strchr(value, ' ');
199
value = abbrev_branch(value);
200
while (space) {
205
space = strchr(value, ' ');
206
}
207
string_list_append(xstrdup(value), &info->merge);
203
- }
208
+ } else
209
+ info->rebase = git_config_bool(orig_key, value);
210
}
211
return 0;
212
}
221
struct ref_states {
222
struct remote *remote;
223
struct string_list new, stale, tracked, heads;
224
+ int queried;
225
};
226
227
static int handle_one_branch(const char *refname,
644
return result;
645
}
646
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
-
647
static void free_remote_ref_states(struct ref_states *states)
648
{
649
string_list_clear(&states->new, 0);
688
remote_refs = transport_get_remote_refs(transport);
689
transport_disconnect(transport);
690
691
+ states->queried = 1;
692
if (query & GET_REF_STATES)
693
get_ref_states(remote_refs, states);
694
if (query & GET_HEAD_NAMES)
701
return 0;
702
}
703
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
+
802
static int show(int argc, const char **argv)
803
{
804
int no_query = 0, result = 0, query_flag = 0;
808
OPT_END()
809
};
810
struct ref_states states;
811
+ struct string_list info_list = { NULL, 0, 0, 0 };
812
+ struct show_info info;
813
814
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
815
820
query_flag = (GET_REF_STATES | GET_HEAD_NAMES);
821
822
memset(&states, 0, sizeof(states));
823
+ memset(&info, 0, sizeof(info));
824
+ info.states = &states;
825
+ info.list = &info_list;
826
for (; argc; argc--, argv++) {
827
int i;
828
844
printf(" %s\n", states.heads.items[i].string);
845
}
846
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 */
870
if (states.remote->push_refspec_nr) {
871
printf(" Local branch%s pushed with 'git push'\n",
872
states.remote->push_refspec_nr > 1 ?