Merge branch 'jc/shortstatus'
* jc/shortstatus: git commit --dry-run -v: show diff in color when asked Documentation/git-commit.txt: describe --dry-run wt-status: collect untracked files in a separate "collect" phase Make git_status_config() file scope static to builtin-commit.c wt-status: move wt_status_colors[] into wt_status structure wt-status: move many global settings to wt_status structure commit: --dry-run status: show worktree status of conflicted paths separately wt-status.c: rework the way changes to the index and work tree are summarized diff-index: keep the original index intact diff-index: report unmerged new entries
This commit is contained in:
commit
433233e0b6
@ -8,8 +8,8 @@ git-commit - Record changes to the repository
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend]
|
||||
[(-c | -C) <commit>] [-F <file> | -m <msg>]
|
||||
'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]
|
||||
[(-c | -C) <commit>] [-F <file> | -m <msg>] [--dry-run]
|
||||
[--allow-empty] [--no-verify] [-e] [--author=<author>]
|
||||
[--cleanup=<mode>] [--] [[-i | -o ]<file>...]
|
||||
|
||||
@ -42,10 +42,9 @@ The content to be added can be specified in several ways:
|
||||
by one which files should be part of the commit, before finalizing the
|
||||
operation. Currently, this is done by invoking 'git-add --interactive'.
|
||||
|
||||
The 'git-status' command can be used to obtain a
|
||||
The `--dry-run` option can be used to obtain a
|
||||
summary of what is included by any of the above for the next
|
||||
commit by giving the same set of parameters you would give to
|
||||
this command.
|
||||
commit by giving the same set of parameters (options and paths).
|
||||
|
||||
If you make a commit and then find a mistake immediately after
|
||||
that, you can recover from it with 'git-reset'.
|
||||
@ -70,6 +69,12 @@ OPTIONS
|
||||
Like '-C', but with '-c' the editor is invoked, so that
|
||||
the user can further edit the commit message.
|
||||
|
||||
--dry-run::
|
||||
Do not actually make a commit, but show the list of paths
|
||||
with updates in the index, paths with changes in the work tree,
|
||||
and paths that are untracked, similar to the one that is given
|
||||
in the commit log editor.
|
||||
|
||||
-F <file>::
|
||||
--file=<file>::
|
||||
Take the commit message from the given file. Use '-' to
|
||||
@ -198,6 +203,11 @@ specified.
|
||||
--quiet::
|
||||
Suppress commit summary message.
|
||||
|
||||
--dry-run::
|
||||
Do not create a commit, but show a list of paths that are
|
||||
to be committed, paths with local changes that will be left
|
||||
uncommitted and paths that are untracked.
|
||||
|
||||
\--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
|
183
builtin-commit.c
183
builtin-commit.c
@ -51,7 +51,7 @@ static const char *template_file;
|
||||
static char *edit_message, *use_message;
|
||||
static char *author_name, *author_email, *author_date;
|
||||
static int all, edit_flag, also, interactive, only, amend, signoff;
|
||||
static int quiet, verbose, no_verify, allow_empty;
|
||||
static int quiet, verbose, no_verify, allow_empty, dry_run;
|
||||
static char *untracked_files_arg;
|
||||
/*
|
||||
* The default commit message cleanup mode will remove the lines
|
||||
@ -103,6 +103,7 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
|
||||
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
|
||||
OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
|
||||
OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
|
||||
OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
|
||||
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
|
||||
OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
|
||||
@ -217,12 +218,15 @@ static void create_base_index(void)
|
||||
exit(128); /* We've already reported the error, finish dying */
|
||||
}
|
||||
|
||||
static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
|
||||
{
|
||||
int fd;
|
||||
struct string_list partial;
|
||||
const char **pathspec = NULL;
|
||||
int refresh_flags = REFRESH_QUIET;
|
||||
|
||||
if (is_status)
|
||||
refresh_flags |= REFRESH_UNMERGED;
|
||||
if (interactive) {
|
||||
if (interactive_add(argc, argv, prefix) != 0)
|
||||
die("interactive add failed");
|
||||
@ -253,7 +257,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
if (all || (also && pathspec && *pathspec)) {
|
||||
int fd = hold_locked_index(&index_lock, 1);
|
||||
add_files_to_cache(also ? prefix : NULL, pathspec, 0);
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
refresh_cache(refresh_flags);
|
||||
if (write_cache(fd, active_cache, active_nr) ||
|
||||
close_lock_file(&index_lock))
|
||||
die("unable to write new_index file");
|
||||
@ -272,7 +276,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
if (!pathspec || !*pathspec) {
|
||||
fd = hold_locked_index(&index_lock, 1);
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
refresh_cache(refresh_flags);
|
||||
if (write_cache(fd, active_cache, active_nr) ||
|
||||
commit_locked_index(&index_lock))
|
||||
die("unable to write new_index file");
|
||||
@ -339,27 +343,24 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||
return false_lock.filename;
|
||||
}
|
||||
|
||||
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn)
|
||||
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
|
||||
struct wt_status *s)
|
||||
{
|
||||
struct wt_status s;
|
||||
|
||||
wt_status_prepare(&s);
|
||||
if (wt_status_relative_paths)
|
||||
s.prefix = prefix;
|
||||
if (s->relative_paths)
|
||||
s->prefix = prefix;
|
||||
|
||||
if (amend) {
|
||||
s.amend = 1;
|
||||
s.reference = "HEAD^1";
|
||||
s->amend = 1;
|
||||
s->reference = "HEAD^1";
|
||||
}
|
||||
s.verbose = verbose;
|
||||
s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES);
|
||||
s.index_file = index_file;
|
||||
s.fp = fp;
|
||||
s.nowarn = nowarn;
|
||||
s->verbose = verbose;
|
||||
s->index_file = index_file;
|
||||
s->fp = fp;
|
||||
s->nowarn = nowarn;
|
||||
|
||||
wt_status_print(&s);
|
||||
wt_status_print(s);
|
||||
|
||||
return s.commitable;
|
||||
return s->commitable;
|
||||
}
|
||||
|
||||
static int is_a_merge(const unsigned char *sha1)
|
||||
@ -413,7 +414,8 @@ static void determine_author_info(void)
|
||||
author_date = date;
|
||||
}
|
||||
|
||||
static int prepare_to_commit(const char *index_file, const char *prefix)
|
||||
static int prepare_to_commit(const char *index_file, const char *prefix,
|
||||
struct wt_status *s)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int commitable, saved_color_setting;
|
||||
@ -555,10 +557,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
|
||||
if (ident_shown)
|
||||
fprintf(fp, "#\n");
|
||||
|
||||
saved_color_setting = wt_status_use_color;
|
||||
wt_status_use_color = 0;
|
||||
commitable = run_status(fp, index_file, prefix, 1);
|
||||
wt_status_use_color = saved_color_setting;
|
||||
saved_color_setting = s->use_color;
|
||||
s->use_color = 0;
|
||||
commitable = run_status(fp, index_file, prefix, 1, s);
|
||||
s->use_color = saved_color_setting;
|
||||
} else {
|
||||
unsigned char sha1[20];
|
||||
const char *parent = "HEAD";
|
||||
@ -579,7 +581,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
|
||||
|
||||
if (!commitable && !in_merge && !allow_empty &&
|
||||
!(amend && is_a_merge(head_sha1))) {
|
||||
run_status(stdout, index_file, prefix, 0);
|
||||
run_status(stdout, index_file, prefix, 0, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -691,7 +693,8 @@ static const char *find_author_by_nickname(const char *name)
|
||||
|
||||
static int parse_and_validate_options(int argc, const char *argv[],
|
||||
const char * const usage[],
|
||||
const char *prefix)
|
||||
const char *prefix,
|
||||
struct wt_status *s)
|
||||
{
|
||||
int f = 0;
|
||||
|
||||
@ -794,11 +797,11 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
if (!untracked_files_arg)
|
||||
; /* default already initialized */
|
||||
else if (!strcmp(untracked_files_arg, "no"))
|
||||
show_untracked_files = SHOW_NO_UNTRACKED_FILES;
|
||||
s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
|
||||
else if (!strcmp(untracked_files_arg, "normal"))
|
||||
show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
else if (!strcmp(untracked_files_arg, "all"))
|
||||
show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
|
||||
s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
|
||||
else
|
||||
die("Invalid untracked files mode '%s'", untracked_files_arg);
|
||||
|
||||
@ -810,30 +813,95 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||
return argc;
|
||||
}
|
||||
|
||||
int cmd_status(int argc, const char **argv, const char *prefix)
|
||||
static int dry_run_commit(int argc, const char **argv, const char *prefix,
|
||||
struct wt_status *s)
|
||||
{
|
||||
const char *index_file;
|
||||
int commitable;
|
||||
const char *index_file;
|
||||
|
||||
git_config(git_status_config, NULL);
|
||||
|
||||
if (wt_status_use_color == -1)
|
||||
wt_status_use_color = git_use_color_default;
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
|
||||
|
||||
index_file = prepare_index(argc, argv, prefix);
|
||||
|
||||
commitable = run_status(stdout, index_file, prefix, 0);
|
||||
|
||||
index_file = prepare_index(argc, argv, prefix, 1);
|
||||
commitable = run_status(stdout, index_file, prefix, 0, s);
|
||||
rollback_index_files();
|
||||
|
||||
return commitable ? 0 : 1;
|
||||
}
|
||||
|
||||
static int parse_status_slot(const char *var, int offset)
|
||||
{
|
||||
if (!strcasecmp(var+offset, "header"))
|
||||
return WT_STATUS_HEADER;
|
||||
if (!strcasecmp(var+offset, "updated")
|
||||
|| !strcasecmp(var+offset, "added"))
|
||||
return WT_STATUS_UPDATED;
|
||||
if (!strcasecmp(var+offset, "changed"))
|
||||
return WT_STATUS_CHANGED;
|
||||
if (!strcasecmp(var+offset, "untracked"))
|
||||
return WT_STATUS_UNTRACKED;
|
||||
if (!strcasecmp(var+offset, "nobranch"))
|
||||
return WT_STATUS_NOBRANCH;
|
||||
if (!strcasecmp(var+offset, "unmerged"))
|
||||
return WT_STATUS_UNMERGED;
|
||||
die("bad config variable '%s'", var);
|
||||
}
|
||||
|
||||
static int git_status_config(const char *k, const char *v, void *cb)
|
||||
{
|
||||
struct wt_status *s = cb;
|
||||
|
||||
if (!strcmp(k, "status.submodulesummary")) {
|
||||
int is_bool;
|
||||
s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
|
||||
if (is_bool && s->submodule_summary)
|
||||
s->submodule_summary = -1;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
|
||||
s->use_color = git_config_colorbool(k, v, -1);
|
||||
return 0;
|
||||
}
|
||||
if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
|
||||
int slot = parse_status_slot(k, 13);
|
||||
if (!v)
|
||||
return config_error_nonbool(k);
|
||||
color_parse(v, k, s->color_palette[slot]);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.relativepaths")) {
|
||||
s->relative_paths = git_config_bool(k, v);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.showuntrackedfiles")) {
|
||||
if (!v)
|
||||
return config_error_nonbool(k);
|
||||
else if (!strcmp(v, "no"))
|
||||
s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
|
||||
else if (!strcmp(v, "normal"))
|
||||
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
else if (!strcmp(v, "all"))
|
||||
s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
|
||||
else
|
||||
return error("Invalid untracked files mode '%s'", v);
|
||||
return 0;
|
||||
}
|
||||
return git_diff_ui_config(k, v, NULL);
|
||||
}
|
||||
|
||||
int cmd_status(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct wt_status s;
|
||||
|
||||
wt_status_prepare(&s);
|
||||
git_config(git_status_config, &s);
|
||||
if (s.use_color == -1)
|
||||
s.use_color = git_use_color_default;
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_status_usage,
|
||||
prefix, &s);
|
||||
return dry_run_commit(argc, argv, prefix, &s);
|
||||
}
|
||||
|
||||
static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
{
|
||||
struct rev_info rev;
|
||||
@ -883,10 +951,12 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
|
||||
static int git_commit_config(const char *k, const char *v, void *cb)
|
||||
{
|
||||
struct wt_status *s = cb;
|
||||
|
||||
if (!strcmp(k, "commit.template"))
|
||||
return git_config_string(&template_file, k, v);
|
||||
|
||||
return git_status_config(k, v, cb);
|
||||
return git_status_config(k, v, s);
|
||||
}
|
||||
|
||||
int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
@ -899,19 +969,26 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
struct commit_list *parents = NULL, **pptr = &parents;
|
||||
struct stat statbuf;
|
||||
int allow_fast_forward = 1;
|
||||
struct wt_status s;
|
||||
|
||||
git_config(git_commit_config, NULL);
|
||||
wt_status_prepare(&s);
|
||||
git_config(git_commit_config, &s);
|
||||
|
||||
if (wt_status_use_color == -1)
|
||||
wt_status_use_color = git_use_color_default;
|
||||
if (s.use_color == -1)
|
||||
s.use_color = git_use_color_default;
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
|
||||
|
||||
index_file = prepare_index(argc, argv, prefix);
|
||||
argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
|
||||
prefix, &s);
|
||||
if (dry_run) {
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
return dry_run_commit(argc, argv, prefix, &s);
|
||||
}
|
||||
index_file = prepare_index(argc, argv, prefix, 0);
|
||||
|
||||
/* Set up everything for writing the commit object. This includes
|
||||
running hooks, writing the trees, and interacting with the user. */
|
||||
if (!prepare_to_commit(index_file, prefix)) {
|
||||
if (!prepare_to_commit(index_file, prefix, &s)) {
|
||||
rollback_index_files();
|
||||
return 1;
|
||||
}
|
||||
|
22
diff-lib.c
22
diff-lib.c
@ -309,22 +309,6 @@ static int show_modified(struct rev_info *revs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This turns all merge entries into "stage 3". That guarantees that
|
||||
* when we read in the new tree (into "stage 1"), we won't lose sight
|
||||
* of the fact that we had unmerged entries.
|
||||
*/
|
||||
static void mark_merge_entries(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (!ce_stage(ce))
|
||||
continue;
|
||||
ce->ce_flags |= CE_STAGEMASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets a mix of an existing index and a tree, one pathname entry
|
||||
* at a time. The index entry may be a single stage-0 one, but it could
|
||||
@ -350,8 +334,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
|
||||
match_missing = !revs->ignore_merges;
|
||||
|
||||
if (cached && idx && ce_stage(idx)) {
|
||||
if (tree)
|
||||
diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
|
||||
diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode,
|
||||
idx->sha1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -437,8 +421,6 @@ int run_diff_index(struct rev_info *revs, int cached)
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc t;
|
||||
|
||||
mark_merge_entries();
|
||||
|
||||
ent = revs->pending.objects[0].item;
|
||||
tree_name = revs->pending.objects[0].name;
|
||||
tree = parse_tree_indirect(ent->sha1);
|
||||
|
58
t/t7060-wtstatus.sh
Executable file
58
t/t7060-wtstatus.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='basic work tree status reporting'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
test_commit A &&
|
||||
test_commit B oneside added &&
|
||||
git checkout A^0 &&
|
||||
test_commit C oneside created
|
||||
'
|
||||
|
||||
test_expect_success 'A/A conflict' '
|
||||
git checkout B^0 &&
|
||||
test_must_fail git merge C
|
||||
'
|
||||
|
||||
test_expect_success 'Report path with conflict' '
|
||||
git diff --cached --name-status >actual &&
|
||||
echo "U oneside" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'Report new path with conflict' '
|
||||
git diff --cached --name-status HEAD^ >actual &&
|
||||
echo "U oneside" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
cat >expect <<EOF
|
||||
# On branch side
|
||||
# Unmerged paths:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
# (use "git add <file>..." to mark resolution)
|
||||
#
|
||||
# deleted by us: foo
|
||||
#
|
||||
no changes added to commit (use "git add" and/or "git commit -a")
|
||||
EOF
|
||||
|
||||
test_expect_success 'M/D conflict does not segfault' '
|
||||
mkdir mdconflict &&
|
||||
(
|
||||
cd mdconflict &&
|
||||
git init &&
|
||||
test_commit initial foo "" &&
|
||||
test_commit modify foo foo &&
|
||||
git checkout -b side HEAD^ &&
|
||||
git rm foo &&
|
||||
git commit -m delete &&
|
||||
test_must_fail git merge master &&
|
||||
test_must_fail git status > ../actual
|
||||
) &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
479
wt-status.c
479
wt-status.c
@ -1,6 +1,5 @@
|
||||
#include "cache.h"
|
||||
#include "wt-status.h"
|
||||
#include "color.h"
|
||||
#include "object.h"
|
||||
#include "dir.h"
|
||||
#include "commit.h"
|
||||
@ -11,38 +10,18 @@
|
||||
#include "run-command.h"
|
||||
#include "remote.h"
|
||||
|
||||
int wt_status_relative_paths = 1;
|
||||
int wt_status_use_color = -1;
|
||||
static int wt_status_submodule_summary;
|
||||
static char wt_status_colors[][COLOR_MAXLEN] = {
|
||||
static char default_wt_status_colors[][COLOR_MAXLEN] = {
|
||||
GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
|
||||
GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */
|
||||
GIT_COLOR_RED, /* WT_STATUS_CHANGED */
|
||||
GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */
|
||||
GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */
|
||||
GIT_COLOR_RED, /* WT_STATUS_UNMERGED */
|
||||
};
|
||||
|
||||
enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
|
||||
static int parse_status_slot(const char *var, int offset)
|
||||
static const char *color(int slot, struct wt_status *s)
|
||||
{
|
||||
if (!strcasecmp(var+offset, "header"))
|
||||
return WT_STATUS_HEADER;
|
||||
if (!strcasecmp(var+offset, "updated")
|
||||
|| !strcasecmp(var+offset, "added"))
|
||||
return WT_STATUS_UPDATED;
|
||||
if (!strcasecmp(var+offset, "changed"))
|
||||
return WT_STATUS_CHANGED;
|
||||
if (!strcasecmp(var+offset, "untracked"))
|
||||
return WT_STATUS_UNTRACKED;
|
||||
if (!strcasecmp(var+offset, "nobranch"))
|
||||
return WT_STATUS_NOBRANCH;
|
||||
die("bad config variable '%s'", var);
|
||||
}
|
||||
|
||||
static const char *color(int slot)
|
||||
{
|
||||
return wt_status_use_color > 0 ? wt_status_colors[slot] : "";
|
||||
return s->use_color > 0 ? s->color_palette[slot] : "";
|
||||
}
|
||||
|
||||
void wt_status_prepare(struct wt_status *s)
|
||||
@ -51,16 +30,35 @@ void wt_status_prepare(struct wt_status *s)
|
||||
const char *head;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
memcpy(s->color_palette, default_wt_status_colors,
|
||||
sizeof(default_wt_status_colors));
|
||||
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
s->use_color = -1;
|
||||
s->relative_paths = 1;
|
||||
head = resolve_ref("HEAD", sha1, 0, NULL);
|
||||
s->branch = head ? xstrdup(head) : NULL;
|
||||
s->reference = "HEAD";
|
||||
s->fp = stdout;
|
||||
s->index_file = get_index_file();
|
||||
s->change.strdup_strings = 1;
|
||||
s->untracked.strdup_strings = 1;
|
||||
}
|
||||
|
||||
static void wt_status_print_unmerged_header(struct wt_status *s)
|
||||
{
|
||||
const char *c = color(WT_STATUS_HEADER, s);
|
||||
color_fprintf_ln(s->fp, c, "# Unmerged paths:");
|
||||
if (!s->is_initial)
|
||||
color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
|
||||
else
|
||||
color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");
|
||||
color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to mark resolution)");
|
||||
color_fprintf_ln(s->fp, c, "#");
|
||||
}
|
||||
|
||||
static void wt_status_print_cached_header(struct wt_status *s)
|
||||
{
|
||||
const char *c = color(WT_STATUS_HEADER);
|
||||
const char *c = color(WT_STATUS_HEADER, s);
|
||||
color_fprintf_ln(s->fp, c, "# Changes to be committed:");
|
||||
if (!s->is_initial) {
|
||||
color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
|
||||
@ -73,7 +71,7 @@ static void wt_status_print_cached_header(struct wt_status *s)
|
||||
static void wt_status_print_dirty_header(struct wt_status *s,
|
||||
int has_deleted)
|
||||
{
|
||||
const char *c = color(WT_STATUS_HEADER);
|
||||
const char *c = color(WT_STATUS_HEADER, s);
|
||||
color_fprintf_ln(s->fp, c, "# Changed but not updated:");
|
||||
if (!has_deleted)
|
||||
color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to update what will be committed)");
|
||||
@ -85,7 +83,7 @@ static void wt_status_print_dirty_header(struct wt_status *s,
|
||||
|
||||
static void wt_status_print_untracked_header(struct wt_status *s)
|
||||
{
|
||||
const char *c = color(WT_STATUS_HEADER);
|
||||
const char *c = color(WT_STATUS_HEADER, s);
|
||||
color_fprintf_ln(s->fp, c, "# Untracked files:");
|
||||
color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to include in what will be committed)");
|
||||
color_fprintf_ln(s->fp, c, "#");
|
||||
@ -93,23 +91,63 @@ static void wt_status_print_untracked_header(struct wt_status *s)
|
||||
|
||||
static void wt_status_print_trailer(struct wt_status *s)
|
||||
{
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
|
||||
}
|
||||
|
||||
#define quote_path quote_path_relative
|
||||
|
||||
static void wt_status_print_filepair(struct wt_status *s,
|
||||
int t, struct diff_filepair *p)
|
||||
static void wt_status_print_unmerged_data(struct wt_status *s,
|
||||
struct string_list_item *it)
|
||||
{
|
||||
const char *c = color(t);
|
||||
const char *c = color(WT_STATUS_UNMERGED, s);
|
||||
struct wt_status_change_data *d = it->util;
|
||||
struct strbuf onebuf = STRBUF_INIT;
|
||||
const char *one, *how = "bug";
|
||||
|
||||
one = quote_path(it->string, -1, &onebuf, s->prefix);
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
|
||||
switch (d->stagemask) {
|
||||
case 1: how = "both deleted:"; break;
|
||||
case 2: how = "added by us:"; break;
|
||||
case 3: how = "deleted by them:"; break;
|
||||
case 4: how = "added by them:"; break;
|
||||
case 5: how = "deleted by us:"; break;
|
||||
case 6: how = "both added:"; break;
|
||||
case 7: how = "both modified:"; break;
|
||||
}
|
||||
color_fprintf(s->fp, c, "%-20s%s\n", how, one);
|
||||
strbuf_release(&onebuf);
|
||||
}
|
||||
|
||||
static void wt_status_print_change_data(struct wt_status *s,
|
||||
int change_type,
|
||||
struct string_list_item *it)
|
||||
{
|
||||
struct wt_status_change_data *d = it->util;
|
||||
const char *c = color(change_type, s);
|
||||
int status = status;
|
||||
char *one_name;
|
||||
char *two_name;
|
||||
const char *one, *two;
|
||||
struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
|
||||
|
||||
one = quote_path(p->one->path, -1, &onebuf, s->prefix);
|
||||
two = quote_path(p->two->path, -1, &twobuf, s->prefix);
|
||||
one_name = two_name = it->string;
|
||||
switch (change_type) {
|
||||
case WT_STATUS_UPDATED:
|
||||
status = d->index_status;
|
||||
if (d->head_path)
|
||||
one_name = d->head_path;
|
||||
break;
|
||||
case WT_STATUS_CHANGED:
|
||||
status = d->worktree_status;
|
||||
break;
|
||||
}
|
||||
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
|
||||
switch (p->status) {
|
||||
one = quote_path(one_name, -1, &onebuf, s->prefix);
|
||||
two = quote_path(two_name, -1, &twobuf, s->prefix);
|
||||
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
|
||||
switch (status) {
|
||||
case DIFF_STATUS_ADDED:
|
||||
color_fprintf(s->fp, c, "new file: %s", one);
|
||||
break;
|
||||
@ -135,64 +173,114 @@ static void wt_status_print_filepair(struct wt_status *s,
|
||||
color_fprintf(s->fp, c, "unmerged: %s", one);
|
||||
break;
|
||||
default:
|
||||
die("bug: unhandled diff status %c", p->status);
|
||||
die("bug: unhandled diff status %c", status);
|
||||
}
|
||||
fprintf(s->fp, "\n");
|
||||
strbuf_release(&onebuf);
|
||||
strbuf_release(&twobuf);
|
||||
}
|
||||
|
||||
static void wt_status_print_updated_cb(struct diff_queue_struct *q,
|
||||
struct diff_options *options,
|
||||
void *data)
|
||||
static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
|
||||
struct diff_options *options,
|
||||
void *data)
|
||||
{
|
||||
struct wt_status *s = data;
|
||||
int shown_header = 0;
|
||||
int i;
|
||||
|
||||
if (!q->nr)
|
||||
return;
|
||||
s->workdir_dirty = 1;
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
if (q->queue[i]->status == 'U')
|
||||
continue;
|
||||
if (!shown_header) {
|
||||
wt_status_print_cached_header(s);
|
||||
s->commitable = 1;
|
||||
shown_header = 1;
|
||||
struct diff_filepair *p;
|
||||
struct string_list_item *it;
|
||||
struct wt_status_change_data *d;
|
||||
|
||||
p = q->queue[i];
|
||||
it = string_list_insert(p->one->path, &s->change);
|
||||
d = it->util;
|
||||
if (!d) {
|
||||
d = xcalloc(1, sizeof(*d));
|
||||
it->util = d;
|
||||
}
|
||||
wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
|
||||
if (!d->worktree_status)
|
||||
d->worktree_status = p->status;
|
||||
}
|
||||
if (shown_header)
|
||||
wt_status_print_trailer(s);
|
||||
}
|
||||
|
||||
static void wt_status_print_changed_cb(struct diff_queue_struct *q,
|
||||
struct diff_options *options,
|
||||
void *data)
|
||||
static int unmerged_mask(const char *path)
|
||||
{
|
||||
int pos, mask;
|
||||
struct cache_entry *ce;
|
||||
|
||||
pos = cache_name_pos(path, strlen(path));
|
||||
if (0 <= pos)
|
||||
return 0;
|
||||
|
||||
mask = 0;
|
||||
pos = -pos-1;
|
||||
while (pos < active_nr) {
|
||||
ce = active_cache[pos++];
|
||||
if (strcmp(ce->name, path) || !ce_stage(ce))
|
||||
break;
|
||||
mask |= (1 << (ce_stage(ce) - 1));
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
|
||||
struct diff_options *options,
|
||||
void *data)
|
||||
{
|
||||
struct wt_status *s = data;
|
||||
int i;
|
||||
if (q->nr) {
|
||||
int has_deleted = 0;
|
||||
s->workdir_dirty = 1;
|
||||
for (i = 0; i < q->nr; i++)
|
||||
if (q->queue[i]->status == DIFF_STATUS_DELETED) {
|
||||
has_deleted = 1;
|
||||
break;
|
||||
}
|
||||
wt_status_print_dirty_header(s, has_deleted);
|
||||
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
struct diff_filepair *p;
|
||||
struct string_list_item *it;
|
||||
struct wt_status_change_data *d;
|
||||
|
||||
p = q->queue[i];
|
||||
it = string_list_insert(p->two->path, &s->change);
|
||||
d = it->util;
|
||||
if (!d) {
|
||||
d = xcalloc(1, sizeof(*d));
|
||||
it->util = d;
|
||||
}
|
||||
if (!d->index_status)
|
||||
d->index_status = p->status;
|
||||
switch (p->status) {
|
||||
case DIFF_STATUS_COPIED:
|
||||
case DIFF_STATUS_RENAMED:
|
||||
d->head_path = xstrdup(p->one->path);
|
||||
break;
|
||||
case DIFF_STATUS_UNMERGED:
|
||||
d->stagemask = unmerged_mask(p->two->path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < q->nr; i++)
|
||||
wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
|
||||
if (q->nr)
|
||||
wt_status_print_trailer(s);
|
||||
}
|
||||
|
||||
static void wt_status_print_updated(struct wt_status *s)
|
||||
static void wt_status_collect_changes_worktree(struct wt_status *s)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev, NULL);
|
||||
setup_revisions(0, NULL, &rev, NULL);
|
||||
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = wt_status_collect_changed_cb;
|
||||
rev.diffopt.format_callback_data = s;
|
||||
run_diff_files(&rev, 0);
|
||||
}
|
||||
|
||||
static void wt_status_collect_changes_index(struct wt_status *s)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev, NULL);
|
||||
setup_revisions(0, NULL, &rev,
|
||||
s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);
|
||||
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = wt_status_print_updated_cb;
|
||||
rev.diffopt.format_callback = wt_status_collect_updated_cb;
|
||||
rev.diffopt.format_callback_data = s;
|
||||
rev.diffopt.detect_rename = 1;
|
||||
rev.diffopt.rename_limit = 200;
|
||||
@ -200,15 +288,155 @@ static void wt_status_print_updated(struct wt_status *s)
|
||||
run_diff_index(&rev, 1);
|
||||
}
|
||||
|
||||
static void wt_status_collect_changes_initial(struct wt_status *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct string_list_item *it;
|
||||
struct wt_status_change_data *d;
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
|
||||
it = string_list_insert(ce->name, &s->change);
|
||||
d = it->util;
|
||||
if (!d) {
|
||||
d = xcalloc(1, sizeof(*d));
|
||||
it->util = d;
|
||||
}
|
||||
if (ce_stage(ce)) {
|
||||
d->index_status = DIFF_STATUS_UNMERGED;
|
||||
d->stagemask |= (1 << (ce_stage(ce) - 1));
|
||||
}
|
||||
else
|
||||
d->index_status = DIFF_STATUS_ADDED;
|
||||
}
|
||||
}
|
||||
|
||||
static void wt_status_collect_untracked(struct wt_status *s)
|
||||
{
|
||||
int i;
|
||||
struct dir_struct dir;
|
||||
|
||||
if (!s->show_untracked_files)
|
||||
return;
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
|
||||
dir.flags |=
|
||||
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
|
||||
setup_standard_excludes(&dir);
|
||||
|
||||
fill_directory(&dir, NULL);
|
||||
for(i = 0; i < dir.nr; i++) {
|
||||
struct dir_entry *ent = dir.entries[i];
|
||||
if (!cache_name_is_other(ent->name, ent->len))
|
||||
continue;
|
||||
s->workdir_untracked = 1;
|
||||
string_list_insert(ent->name, &s->untracked);
|
||||
}
|
||||
}
|
||||
|
||||
void wt_status_collect(struct wt_status *s)
|
||||
{
|
||||
wt_status_collect_changes_worktree(s);
|
||||
|
||||
if (s->is_initial)
|
||||
wt_status_collect_changes_initial(s);
|
||||
else
|
||||
wt_status_collect_changes_index(s);
|
||||
wt_status_collect_untracked(s);
|
||||
}
|
||||
|
||||
static void wt_status_print_unmerged(struct wt_status *s)
|
||||
{
|
||||
int shown_header = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->change.nr; i++) {
|
||||
struct wt_status_change_data *d;
|
||||
struct string_list_item *it;
|
||||
it = &(s->change.items[i]);
|
||||
d = it->util;
|
||||
if (!d->stagemask)
|
||||
continue;
|
||||
if (!shown_header) {
|
||||
wt_status_print_unmerged_header(s);
|
||||
shown_header = 1;
|
||||
}
|
||||
wt_status_print_unmerged_data(s, it);
|
||||
}
|
||||
if (shown_header)
|
||||
wt_status_print_trailer(s);
|
||||
|
||||
}
|
||||
|
||||
static void wt_status_print_updated(struct wt_status *s)
|
||||
{
|
||||
int shown_header = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->change.nr; i++) {
|
||||
struct wt_status_change_data *d;
|
||||
struct string_list_item *it;
|
||||
it = &(s->change.items[i]);
|
||||
d = it->util;
|
||||
if (!d->index_status ||
|
||||
d->index_status == DIFF_STATUS_UNMERGED)
|
||||
continue;
|
||||
if (!shown_header) {
|
||||
wt_status_print_cached_header(s);
|
||||
s->commitable = 1;
|
||||
shown_header = 1;
|
||||
}
|
||||
wt_status_print_change_data(s, WT_STATUS_UPDATED, it);
|
||||
}
|
||||
if (shown_header)
|
||||
wt_status_print_trailer(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 : has delete
|
||||
* 0 : no change
|
||||
* 1 : some change but no delete
|
||||
*/
|
||||
static int wt_status_check_worktree_changes(struct wt_status *s)
|
||||
{
|
||||
int i;
|
||||
int changes = 0;
|
||||
|
||||
for (i = 0; i < s->change.nr; i++) {
|
||||
struct wt_status_change_data *d;
|
||||
d = s->change.items[i].util;
|
||||
if (!d->worktree_status ||
|
||||
d->worktree_status == DIFF_STATUS_UNMERGED)
|
||||
continue;
|
||||
changes = 1;
|
||||
if (d->worktree_status == DIFF_STATUS_DELETED)
|
||||
return -1;
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
static void wt_status_print_changed(struct wt_status *s)
|
||||
{
|
||||
struct rev_info rev;
|
||||
init_revisions(&rev, "");
|
||||
setup_revisions(0, NULL, &rev, NULL);
|
||||
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = wt_status_print_changed_cb;
|
||||
rev.diffopt.format_callback_data = s;
|
||||
run_diff_files(&rev, 0);
|
||||
int i;
|
||||
int worktree_changes = wt_status_check_worktree_changes(s);
|
||||
|
||||
if (!worktree_changes)
|
||||
return;
|
||||
|
||||
wt_status_print_dirty_header(s, worktree_changes < 0);
|
||||
|
||||
for (i = 0; i < s->change.nr; i++) {
|
||||
struct wt_status_change_data *d;
|
||||
struct string_list_item *it;
|
||||
it = &(s->change.items[i]);
|
||||
d = it->util;
|
||||
if (!d->worktree_status ||
|
||||
d->worktree_status == DIFF_STATUS_UNMERGED)
|
||||
continue;
|
||||
wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
|
||||
}
|
||||
wt_status_print_trailer(s);
|
||||
}
|
||||
|
||||
static void wt_status_print_submodule_summary(struct wt_status *s)
|
||||
@ -228,7 +456,7 @@ static void wt_status_print_submodule_summary(struct wt_status *s)
|
||||
NULL
|
||||
};
|
||||
|
||||
sprintf(summary_limit, "%d", wt_status_submodule_summary);
|
||||
sprintf(summary_limit, "%d", s->submodule_summary);
|
||||
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
|
||||
|
||||
memset(&sm_summary, 0, sizeof(sm_summary));
|
||||
@ -243,32 +471,20 @@ static void wt_status_print_submodule_summary(struct wt_status *s)
|
||||
|
||||
static void wt_status_print_untracked(struct wt_status *s)
|
||||
{
|
||||
struct dir_struct dir;
|
||||
int i;
|
||||
int shown_header = 0;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
if (!s->untracked.nr)
|
||||
return;
|
||||
|
||||
if (!s->untracked)
|
||||
dir.flags |=
|
||||
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
|
||||
setup_standard_excludes(&dir);
|
||||
|
||||
fill_directory(&dir, NULL);
|
||||
for(i = 0; i < dir.nr; i++) {
|
||||
struct dir_entry *ent = dir.entries[i];
|
||||
if (!cache_name_is_other(ent->name, ent->len))
|
||||
continue;
|
||||
if (!shown_header) {
|
||||
s->workdir_untracked = 1;
|
||||
wt_status_print_untracked_header(s);
|
||||
shown_header = 1;
|
||||
}
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s",
|
||||
quote_path(ent->name, ent->len,
|
||||
&buf, s->prefix));
|
||||
wt_status_print_untracked_header(s);
|
||||
for (i = 0; i < s->untracked.nr; i++) {
|
||||
struct string_list_item *it;
|
||||
it = &(s->untracked.items[i]);
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s",
|
||||
quote_path(it->string, strlen(it->string),
|
||||
&buf, s->prefix));
|
||||
}
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
@ -310,15 +526,15 @@ static void wt_status_print_tracking(struct wt_status *s)
|
||||
return;
|
||||
|
||||
for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER),
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
|
||||
"# %.*s", (int)(ep - cp), cp);
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
|
||||
}
|
||||
|
||||
void wt_status_print(struct wt_status *s)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *branch_color = color(WT_STATUS_HEADER);
|
||||
const char *branch_color = color(WT_STATUS_HEADER, s);
|
||||
|
||||
s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
|
||||
if (s->branch) {
|
||||
@ -328,26 +544,29 @@ void wt_status_print(struct wt_status *s)
|
||||
branch_name += 11;
|
||||
else if (!strcmp(branch_name, "HEAD")) {
|
||||
branch_name = "";
|
||||
branch_color = color(WT_STATUS_NOBRANCH);
|
||||
branch_color = color(WT_STATUS_NOBRANCH, s);
|
||||
on_what = "Not currently on any branch.";
|
||||
}
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER), "# ");
|
||||
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# ");
|
||||
color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name);
|
||||
if (!s->is_initial)
|
||||
wt_status_print_tracking(s);
|
||||
}
|
||||
|
||||
wt_status_collect(s);
|
||||
|
||||
if (s->is_initial) {
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit");
|
||||
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
|
||||
}
|
||||
|
||||
wt_status_print_unmerged(s);
|
||||
wt_status_print_updated(s);
|
||||
wt_status_print_changed(s);
|
||||
if (wt_status_submodule_summary)
|
||||
if (s->submodule_summary)
|
||||
wt_status_print_submodule_summary(s);
|
||||
if (show_untracked_files)
|
||||
if (s->show_untracked_files)
|
||||
wt_status_print_untracked(s);
|
||||
else if (s->commitable)
|
||||
fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n");
|
||||
@ -361,53 +580,13 @@ void wt_status_print(struct wt_status *s)
|
||||
; /* nothing */
|
||||
else if (s->workdir_dirty)
|
||||
printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
|
||||
else if (s->workdir_untracked)
|
||||
else if (s->untracked.nr)
|
||||
printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
|
||||
else if (s->is_initial)
|
||||
printf("nothing to commit (create/copy files and use \"git add\" to track)\n");
|
||||
else if (!show_untracked_files)
|
||||
else if (!s->show_untracked_files)
|
||||
printf("nothing to commit (use -u to show untracked files)\n");
|
||||
else
|
||||
printf("nothing to commit (working directory clean)\n");
|
||||
}
|
||||
}
|
||||
|
||||
int git_status_config(const char *k, const char *v, void *cb)
|
||||
{
|
||||
if (!strcmp(k, "status.submodulesummary")) {
|
||||
int is_bool;
|
||||
wt_status_submodule_summary = git_config_bool_or_int(k, v, &is_bool);
|
||||
if (is_bool && wt_status_submodule_summary)
|
||||
wt_status_submodule_summary = -1;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
|
||||
wt_status_use_color = git_config_colorbool(k, v, -1);
|
||||
return 0;
|
||||
}
|
||||
if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
|
||||
int slot = parse_status_slot(k, 13);
|
||||
if (!v)
|
||||
return config_error_nonbool(k);
|
||||
color_parse(v, k, wt_status_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.relativepaths")) {
|
||||
wt_status_relative_paths = git_config_bool(k, v);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.showuntrackedfiles")) {
|
||||
if (!v)
|
||||
return config_error_nonbool(k);
|
||||
else if (!strcmp(v, "no"))
|
||||
show_untracked_files = SHOW_NO_UNTRACKED_FILES;
|
||||
else if (!strcmp(v, "normal"))
|
||||
show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||
else if (!strcmp(v, "all"))
|
||||
show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
|
||||
else
|
||||
return error("Invalid untracked files mode '%s'", v);
|
||||
return 0;
|
||||
}
|
||||
return git_diff_ui_config(k, v, cb);
|
||||
}
|
||||
|
26
wt-status.h
26
wt-status.h
@ -2,13 +2,16 @@
|
||||
#define STATUS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "string-list.h"
|
||||
#include "color.h"
|
||||
|
||||
enum color_wt_status {
|
||||
WT_STATUS_HEADER,
|
||||
WT_STATUS_HEADER = 0,
|
||||
WT_STATUS_UPDATED,
|
||||
WT_STATUS_CHANGED,
|
||||
WT_STATUS_UNTRACKED,
|
||||
WT_STATUS_NOBRANCH,
|
||||
WT_STATUS_UNMERGED,
|
||||
};
|
||||
|
||||
enum untracked_status_type {
|
||||
@ -16,7 +19,13 @@ enum untracked_status_type {
|
||||
SHOW_NORMAL_UNTRACKED_FILES,
|
||||
SHOW_ALL_UNTRACKED_FILES
|
||||
};
|
||||
extern enum untracked_status_type show_untracked_files;
|
||||
|
||||
struct wt_status_change_data {
|
||||
int worktree_status;
|
||||
int index_status;
|
||||
int stagemask;
|
||||
char *head_path;
|
||||
};
|
||||
|
||||
struct wt_status {
|
||||
int is_initial;
|
||||
@ -24,8 +33,13 @@ struct wt_status {
|
||||
const char *reference;
|
||||
int verbose;
|
||||
int amend;
|
||||
int untracked;
|
||||
int nowarn;
|
||||
int use_color;
|
||||
int relative_paths;
|
||||
int submodule_summary;
|
||||
enum untracked_status_type show_untracked_files;
|
||||
char color_palette[WT_STATUS_UNMERGED+1][COLOR_MAXLEN];
|
||||
|
||||
/* These are computed during processing of the individual sections */
|
||||
int commitable;
|
||||
int workdir_dirty;
|
||||
@ -33,12 +47,12 @@ struct wt_status {
|
||||
const char *index_file;
|
||||
FILE *fp;
|
||||
const char *prefix;
|
||||
struct string_list change;
|
||||
struct string_list untracked;
|
||||
};
|
||||
|
||||
int git_status_config(const char *var, const char *value, void *cb);
|
||||
extern int wt_status_use_color;
|
||||
extern int wt_status_relative_paths;
|
||||
void wt_status_prepare(struct wt_status *s);
|
||||
void wt_status_print(struct wt_status *s);
|
||||
void wt_status_collect(struct wt_status *s);
|
||||
|
||||
#endif /* STATUS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user