REQ_(TOGGLE_LINENO, "Toggle line numbers"), \
REQ_(TOGGLE_REV_GRAPH, "Toggle revision graph visualization"), \
REQ_(STATUS_UPDATE, "Update file status"), \
+ REQ_(STATUS_MERGE, "Merge file using external tool"), \
REQ_(EDIT, "Open in editor"), \
REQ_(CHERRY_PICK, "Cherry-pick commit to current branch")
{ 'g', REQ_TOGGLE_REV_GRAPH },
{ ':', REQ_PROMPT },
{ 'u', REQ_STATUS_UPDATE },
+ { 'M', REQ_STATUS_MERGE },
{ 'e', REQ_EDIT },
{ 'C', REQ_CHERRY_PICK },
}
static void
-open_editor(bool from_root, char *file)
+open_external_viewer(const char *cmd)
+{
+ def_prog_mode(); /* save current tty modes */
+ endwin(); /* restore original tty modes */
+ system(cmd);
+ fprintf(stderr, "Press Enter to continue");
+ getc(stdin);
+ reset_prog_mode();
+ redraw_display();
+}
+
+static void
+open_mergetool(const char *file)
+{
+ char cmd[SIZEOF_STR];
+ char file_sq[SIZEOF_STR];
+
+ if (sq_quote(file_sq, 0, file) < sizeof(file_sq) &&
+ string_format(cmd, "git mergetool %s", file_sq)) {
+ open_external_viewer(cmd);
+ }
+}
+
+static void
+open_editor(bool from_root, const char *file)
{
char cmd[SIZEOF_STR];
char file_sq[SIZEOF_STR];
if (sq_quote(file_sq, 0, file) < sizeof(file_sq) &&
string_format(cmd, "%s %s%s", editor, prefix, file_sq)) {
- def_prog_mode(); /* save current tty modes */
- endwin(); /* restore original tty modes */
- system(cmd);
- reset_prog_mode();
- redraw_display();
+ open_external_viewer(cmd);
}
}
status_run(struct view *view, const char cmd[], bool diff, enum line_type type)
{
struct status *file = NULL;
+ struct status *unmerged = NULL;
char buf[SIZEOF_STR * 4];
size_t bufsize = 0;
FILE *pipe;
if (!sep)
break;
sepsize = sep - buf + 1;
+
+ /* Collapse all 'M'odified entries that
+ * follow a associated 'U'nmerged entry.
+ */
+ if (file->status == 'U') {
+ unmerged = file;
+
+ } else if (unmerged) {
+ int collapse = !strcmp(buf, unmerged->name);
+
+ unmerged = NULL;
+ if (collapse) {
+ free(file);
+ view->lines--;
+ continue;
+ }
+ }
}
/* git-ls-files just delivers a NUL separated
return TRUE;
}
-#define STATUS_DIFF_INDEX_CMD "git diff-index -z --cached HEAD"
+/* Don't show unmerged entries in the staged section. */
+#define STATUS_DIFF_INDEX_CMD "git diff-index -z --diff-filter=ACDMRTXB --cached HEAD"
#define STATUS_DIFF_FILES_CMD "git diff-files -z"
#define STATUS_LIST_OTHER_CMD \
"git ls-files -z --others --exclude-per-directory=.gitignore"
} else if (!status_update_file(view, line->data, line->type)) {
report("Failed to update file status");
}
-
- open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
}
static enum request
status_update(view);
break;
+ case REQ_STATUS_MERGE:
+ open_mergetool(status->name);
+ break;
+
case REQ_EDIT:
if (!status)
return request;
open_editor(status->status != '?', status->name);
- open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
break;
case REQ_ENTER:
+ /* After returning the status view has been split to
+ * show the stage view. No further reloading is
+ * necessary. */
status_enter(view, line);
- break;
+ return REQ_NONE;
case REQ_REFRESH:
- open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
+ /* Simply reload the view. */
break;
default:
return request;
}
+ open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
+
return REQ_NONE;
}
struct status *status = line->data;
char file[SIZEOF_STR] = "all files";
char *text;
+ char *key;
if (status && !string_format(file, "'%s'", status->name))
return;
die("w00t");
}
- string_format(view->ref, text, get_key(REQ_STATUS_UPDATE), file);
+ if (status && status->status == 'U') {
+ text = "Press %s to resolve conflict in %s";
+ key = get_key(REQ_STATUS_MERGE);
+
+ } else {
+ key = get_key(REQ_STATUS_UPDATE);
+ }
+
+ string_format(view->ref, text, key, file);
}
static bool
cherry_pick = "git cherry-pick";
if (string_format(cmd, "%s %s", cherry_pick, commit->id)) {
- def_prog_mode(); /* save current tty modes */
- endwin(); /* restore original tty modes */
- system(cmd);
- fprintf(stderr, "Press Enter to continue");
- getc(stdin);
- reset_prog_mode();
- redraw_display();
+ open_external_viewer(cmd);
}
}