701
777
for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
702
778
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
703
"# %.*s", (int)(ep - cp), cp);
704
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
779
"%c %.*s", comment_line_char,
781
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
785
static int has_unmerged(struct wt_status *s)
789
for (i = 0; i < s->change.nr; i++) {
790
struct wt_status_change_data *d;
791
d = s->change.items[i].util;
798
static void show_merge_in_progress(struct wt_status *s,
799
struct wt_status_state *state,
802
if (has_unmerged(s)) {
803
status_printf_ln(s, color, _("You have unmerged paths."));
804
if (advice_status_hints)
805
status_printf_ln(s, color,
806
_(" (fix conflicts and run \"git commit\")"));
808
status_printf_ln(s, color,
809
_("All conflicts fixed but you are still merging."));
810
if (advice_status_hints)
811
status_printf_ln(s, color,
812
_(" (use \"git commit\" to conclude merge)"));
814
wt_status_print_trailer(s);
817
static void show_am_in_progress(struct wt_status *s,
818
struct wt_status_state *state,
821
status_printf_ln(s, color,
822
_("You are in the middle of an am session."));
823
if (state->am_empty_patch)
824
status_printf_ln(s, color,
825
_("The current patch is empty."));
826
if (advice_status_hints) {
827
if (!state->am_empty_patch)
828
status_printf_ln(s, color,
829
_(" (fix conflicts and then run \"git am --resolved\")"));
830
status_printf_ln(s, color,
831
_(" (use \"git am --skip\" to skip this patch)"));
832
status_printf_ln(s, color,
833
_(" (use \"git am --abort\" to restore the original branch)"));
835
wt_status_print_trailer(s);
838
static char *read_line_from_git_path(const char *filename)
840
struct strbuf buf = STRBUF_INIT;
841
FILE *fp = fopen(git_path("%s", filename), "r");
843
strbuf_release(&buf);
846
strbuf_getline(&buf, fp, '\n');
848
return strbuf_detach(&buf, NULL);
850
strbuf_release(&buf);
855
static int split_commit_in_progress(struct wt_status *s)
857
int split_in_progress = 0;
858
char *head = read_line_from_git_path("HEAD");
859
char *orig_head = read_line_from_git_path("ORIG_HEAD");
860
char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
861
char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
863
if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
864
!s->branch || strcmp(s->branch, "HEAD"))
865
return split_in_progress;
867
if (!strcmp(rebase_amend, rebase_orig_head)) {
868
if (strcmp(head, rebase_amend))
869
split_in_progress = 1;
870
} else if (strcmp(orig_head, rebase_orig_head)) {
871
split_in_progress = 1;
874
if (!s->amend && !s->nowarn && !s->workdir_dirty)
875
split_in_progress = 0;
880
free(rebase_orig_head);
881
return split_in_progress;
884
static void show_rebase_in_progress(struct wt_status *s,
885
struct wt_status_state *state,
890
if (has_unmerged(s)) {
892
status_printf_ln(s, color,
893
_("You are currently rebasing branch '%s' on '%s'."),
897
status_printf_ln(s, color,
898
_("You are currently rebasing."));
899
if (advice_status_hints) {
900
status_printf_ln(s, color,
901
_(" (fix conflicts and then run \"git rebase --continue\")"));
902
status_printf_ln(s, color,
903
_(" (use \"git rebase --skip\" to skip this patch)"));
904
status_printf_ln(s, color,
905
_(" (use \"git rebase --abort\" to check out the original branch)"));
907
} else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
909
status_printf_ln(s, color,
910
_("You are currently rebasing branch '%s' on '%s'."),
914
status_printf_ln(s, color,
915
_("You are currently rebasing."));
916
if (advice_status_hints)
917
status_printf_ln(s, color,
918
_(" (all conflicts fixed: run \"git rebase --continue\")"));
919
} else if (split_commit_in_progress(s)) {
921
status_printf_ln(s, color,
922
_("You are currently splitting a commit while rebasing branch '%s' on '%s'."),
926
status_printf_ln(s, color,
927
_("You are currently splitting a commit during a rebase."));
928
if (advice_status_hints)
929
status_printf_ln(s, color,
930
_(" (Once your working directory is clean, run \"git rebase --continue\")"));
933
status_printf_ln(s, color,
934
_("You are currently editing a commit while rebasing branch '%s' on '%s'."),
938
status_printf_ln(s, color,
939
_("You are currently editing a commit during a rebase."));
940
if (advice_status_hints && !s->amend) {
941
status_printf_ln(s, color,
942
_(" (use \"git commit --amend\" to amend the current commit)"));
943
status_printf_ln(s, color,
944
_(" (use \"git rebase --continue\" once you are satisfied with your changes)"));
947
wt_status_print_trailer(s);
950
static void show_cherry_pick_in_progress(struct wt_status *s,
951
struct wt_status_state *state,
954
status_printf_ln(s, color, _("You are currently cherry-picking."));
955
if (advice_status_hints) {
957
status_printf_ln(s, color,
958
_(" (fix conflicts and run \"git commit\")"));
960
status_printf_ln(s, color,
961
_(" (all conflicts fixed: run \"git commit\")"));
963
wt_status_print_trailer(s);
966
static void show_revert_in_progress(struct wt_status *s,
967
struct wt_status_state *state,
970
status_printf_ln(s, color, _("You are currently reverting commit %s."),
971
find_unique_abbrev(state->revert_head_sha1, DEFAULT_ABBREV));
972
if (advice_status_hints) {
974
status_printf_ln(s, color,
975
_(" (fix conflicts and run \"git revert --continue\")"));
977
status_printf_ln(s, color,
978
_(" (all conflicts fixed: run \"git revert --continue\")"));
979
status_printf_ln(s, color,
980
_(" (use \"git revert --abort\" to cancel the revert operation)"));
982
wt_status_print_trailer(s);
985
static void show_bisect_in_progress(struct wt_status *s,
986
struct wt_status_state *state,
990
status_printf_ln(s, color,
991
_("You are currently bisecting, started from branch '%s'."),
994
status_printf_ln(s, color,
995
_("You are currently bisecting."));
996
if (advice_status_hints)
997
status_printf_ln(s, color,
998
_(" (use \"git bisect reset\" to get back to the original branch)"));
999
wt_status_print_trailer(s);
1003
* Extract branch information from rebase/bisect
1005
static char *read_and_strip_branch(const char *path)
1007
struct strbuf sb = STRBUF_INIT;
1008
unsigned char sha1[20];
1010
if (strbuf_read_file(&sb, git_path("%s", path), 0) <= 0)
1013
while (&sb.len && sb.buf[sb.len - 1] == '\n')
1014
strbuf_setlen(&sb, sb.len - 1);
1017
if (!prefixcmp(sb.buf, "refs/heads/"))
1018
strbuf_remove(&sb,0, strlen("refs/heads/"));
1019
else if (!prefixcmp(sb.buf, "refs/"))
1021
else if (!get_sha1_hex(sb.buf, sha1)) {
1023
abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
1025
strbuf_addstr(&sb, abbrev);
1026
} else if (!strcmp(sb.buf, "detached HEAD")) /* rebase */
1030
return strbuf_detach(&sb, NULL);
1033
strbuf_release(&sb);
1037
struct grab_1st_switch_cbdata {
1040
unsigned char nsha1[20];
1043
static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,
1044
const char *email, unsigned long timestamp, int tz,
1045
const char *message, void *cb_data)
1047
struct grab_1st_switch_cbdata *cb = cb_data;
1048
const char *target = NULL, *end;
1050
if (prefixcmp(message, "checkout: moving from "))
1052
message += strlen("checkout: moving from ");
1053
target = strstr(message, " to ");
1056
target += strlen(" to ");
1057
strbuf_reset(&cb->buf);
1058
hashcpy(cb->nsha1, nsha1);
1059
for (end = target; *end && *end != '\n'; end++)
1061
strbuf_add(&cb->buf, target, end - target);
1066
static void wt_status_get_detached_from(struct wt_status_state *state)
1068
struct grab_1st_switch_cbdata cb;
1069
struct commit *commit;
1070
unsigned char sha1[20];
1073
strbuf_init(&cb.buf, 0);
1074
if (for_each_reflog_ent_reverse("HEAD", grab_1st_switch, &cb) <= 0) {
1075
strbuf_release(&cb.buf);
1079
if (dwim_ref(cb.buf.buf, cb.buf.len, sha1, &ref) == 1 &&
1080
/* sha1 is a commit? match without further lookup */
1081
(!hashcmp(cb.nsha1, sha1) ||
1082
/* perhaps sha1 is a tag, try to dereference to a commit */
1083
((commit = lookup_commit_reference_gently(sha1, 1)) != NULL &&
1084
!hashcmp(cb.nsha1, commit->object.sha1)))) {
1086
if (!prefixcmp(ref, "refs/tags/"))
1087
ofs = strlen("refs/tags/");
1088
else if (!prefixcmp(ref, "refs/remotes/"))
1089
ofs = strlen("refs/remotes/");
1092
state->detached_from = xstrdup(ref + ofs);
1094
state->detached_from =
1095
xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV));
1096
hashcpy(state->detached_sha1, cb.nsha1);
1099
strbuf_release(&cb.buf);
1102
void wt_status_get_state(struct wt_status_state *state,
1103
int get_detached_from)
1106
unsigned char sha1[20];
1108
if (!stat(git_path("MERGE_HEAD"), &st)) {
1109
state->merge_in_progress = 1;
1110
} else if (!stat(git_path("rebase-apply"), &st)) {
1111
if (!stat(git_path("rebase-apply/applying"), &st)) {
1112
state->am_in_progress = 1;
1113
if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
1114
state->am_empty_patch = 1;
1116
state->rebase_in_progress = 1;
1117
state->branch = read_and_strip_branch("rebase-apply/head-name");
1118
state->onto = read_and_strip_branch("rebase-apply/onto");
1120
} else if (!stat(git_path("rebase-merge"), &st)) {
1121
if (!stat(git_path("rebase-merge/interactive"), &st))
1122
state->rebase_interactive_in_progress = 1;
1124
state->rebase_in_progress = 1;
1125
state->branch = read_and_strip_branch("rebase-merge/head-name");
1126
state->onto = read_and_strip_branch("rebase-merge/onto");
1127
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
1128
state->cherry_pick_in_progress = 1;
1130
if (!stat(git_path("BISECT_LOG"), &st)) {
1131
state->bisect_in_progress = 1;
1132
state->branch = read_and_strip_branch("BISECT_START");
1134
if (!stat(git_path("REVERT_HEAD"), &st) &&
1135
!get_sha1("REVERT_HEAD", sha1)) {
1136
state->revert_in_progress = 1;
1137
hashcpy(state->revert_head_sha1, sha1);
1140
if (get_detached_from)
1141
wt_status_get_detached_from(state);
1144
static void wt_status_print_state(struct wt_status *s,
1145
struct wt_status_state *state)
1147
const char *state_color = color(WT_STATUS_HEADER, s);
1148
if (state->merge_in_progress)
1149
show_merge_in_progress(s, state, state_color);
1150
else if (state->am_in_progress)
1151
show_am_in_progress(s, state, state_color);
1152
else if (state->rebase_in_progress || state->rebase_interactive_in_progress)
1153
show_rebase_in_progress(s, state, state_color);
1154
else if (state->cherry_pick_in_progress)
1155
show_cherry_pick_in_progress(s, state, state_color);
1156
else if (state->revert_in_progress)
1157
show_revert_in_progress(s, state, state_color);
1158
if (state->bisect_in_progress)
1159
show_bisect_in_progress(s, state, state_color);
707
1162
void wt_status_print(struct wt_status *s)
709
1164
const char *branch_color = color(WT_STATUS_ONBRANCH, s);
710
1165
const char *branch_status_color = color(WT_STATUS_HEADER, s);
1166
struct wt_status_state state;
1168
memset(&state, 0, sizeof(state));
1169
wt_status_get_state(&state,
1170
s->branch && !strcmp(s->branch, "HEAD"));
712
1172
if (s->branch) {
713
1173
const char *on_what = _("On branch ");