提交 b877cb4a 编写于 作者: J Junio C Hamano

Merge branch 'dl/merge-cleanup-scissors-fix'

The list of conflicted paths shown in the editor while concluding a
conflicted merge was shown above the scissors line when the
clean-up mode is set to "scissors", even though it was commented
out just like the list of updated paths and other information to
help the user explain the merge better.

* dl/merge-cleanup-scissors-fix:
  cherry-pick/revert: add scissors line on merge conflict
  sequencer.c: save and restore cleanup mode
  merge: add scissors line on merge conflict
  merge: cleanup messages like commit
  parse-options.h: extract common --cleanup option
  commit: extract cleanup_mode functions to sequencer
  t7502: clean up style
  t7604: clean up style
  t3507: clean up style
  t7600: clean up style
......@@ -57,6 +57,13 @@ OPTIONS
With this option, 'git cherry-pick' will let you edit the commit
message prior to committing.
--cleanup=<mode>::
This option determines how the commit message will be cleaned up before
being passed on to the commit machinery. See linkgit:git-commit[1] for more
details. In particular, if the '<mode>' is given a value of `scissors`,
scissors will be appended to `MERGE_MSG` before being passed on in the case
of a conflict.
-x::
When recording the commit, append a line that says
"(cherry picked from commit ...)" to the original commit
......
......@@ -66,6 +66,13 @@ more details.
With this option, 'git revert' will not start the commit
message editor.
--cleanup=<mode>::
This option determines how the commit message will be cleaned up before
being passed on to the commit machinery. See linkgit:git-commit[1] for more
details. In particular, if the '<mode>' is given a value of `scissors`,
scissors will be appended to `MERGE_MSG` before being passed on in the case
of a conflict.
-n::
--no-commit::
Usually the command automatically creates some commits with
......
......@@ -32,6 +32,13 @@ they run `git merge`. To make it easier to adjust such scripts to the
updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
set to `no` at the beginning of them.
--cleanup=<mode>::
This option determines how the merge message will be cleaned up before
commiting. See linkgit:git-commit[1] for more details. In addition, if
the '<mode>' is given a value of `scissors`, scissors will be appended
to `MERGE_MSG` before being passed on to the commit machinery in the
case of a merge conflict.
--ff::
When the merge resolves as a fast-forward, only update the branch
pointer, without creating a merge commit. This is the default
......
......@@ -668,6 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
const char *hook_arg2 = NULL;
int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
int old_display_comment_prefix;
int merge_contains_scissors = 0;
/* This checks and barfs if author is badly specified */
determine_author_info(author_ident);
......@@ -728,6 +729,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
strbuf_addbuf(&sb, &message);
hook_arg1 = "message";
} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
size_t merge_msg_start;
/*
* prepend SQUASH_MSG here if it exists and a
* "merge --squash" was originally performed
......@@ -738,8 +741,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
hook_arg1 = "squash";
} else
hook_arg1 = "merge";
merge_msg_start = sb.len;
if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
die_errno(_("could not read MERGE_MSG"));
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
wt_status_locate_end(sb.buf + merge_msg_start,
sb.len - merge_msg_start) <
sb.len - merge_msg_start)
merge_contains_scissors = 1;
} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
......@@ -807,7 +818,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct ident_split ci, ai;
if (whence != FROM_COMMIT) {
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
!merge_contains_scissors)
wt_status_add_cut_line(s->fp);
status_printf_ln(s, GIT_COLOR_NORMAL,
whence == FROM_MERGE
......@@ -832,10 +844,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
_("Please enter the commit message for your changes."
" Lines starting\nwith '%c' will be ignored, and an empty"
" message aborts the commit.\n"), comment_line_char);
else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
whence == FROM_COMMIT)
wt_status_add_cut_line(s->fp);
else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
if (whence == FROM_COMMIT && !merge_contains_scissors)
wt_status_add_cut_line(s->fp);
} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
status_printf(s, GIT_COLOR_NORMAL,
_("Please enter the commit message for your changes."
" Lines starting\n"
......@@ -1172,24 +1184,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
if (argc == 0 && (also || (only && !amend && !allow_empty)))
die(_("No paths with --include/--only does not make sense."));
if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
COMMIT_MSG_CLEANUP_SPACE;
else if (!strcmp(cleanup_arg, "verbatim"))
cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
else if (!strcmp(cleanup_arg, "whitespace"))
cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
else if (!strcmp(cleanup_arg, "strip"))
cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
else if (!strcmp(cleanup_arg, "scissors"))
cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
COMMIT_MSG_CLEANUP_SPACE;
/*
* Please update _git_commit() in git-completion.bash when you
* add new options.
*/
else
die(_("Invalid cleanup mode %s"), cleanup_arg);
cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
handle_untracked_files_arg(s);
......@@ -1491,7 +1486,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")),
OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
OPT_CLEANUP(&cleanup_arg),
OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
......@@ -1627,11 +1622,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
die(_("could not read commit message: %s"), strerror(saved_errno));
}
if (verbose || /* Truncate the message just before the diff, if any. */
cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
cleanup_message(&sb, cleanup_mode, verbose);
if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
rollback_index_files();
......
......@@ -38,6 +38,7 @@
#include "tag.h"
#include "alias.h"
#include "commit-reach.h"
#include "wt-status.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
......@@ -98,6 +99,9 @@ enum ff_type {
static enum ff_type fast_forward = FF_ALLOW;
static const char *cleanup_arg;
static enum commit_msg_cleanup_mode cleanup_mode;
static int option_parse_message(const struct option *opt,
const char *arg, int unset)
{
......@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
N_("perform a commit if the merge succeeds (default)")),
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
OPT_CLEANUP(&cleanup_arg),
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
OPT_SET_INT_F(0, "ff-only", &fast_forward,
N_("abort if fast-forward is not possible"),
......@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
return git_config_string(&pull_twohead, k, v);
else if (!strcmp(k, "pull.octopus"))
return git_config_string(&pull_octopus, k, v);
else if (!strcmp(k, "commit.cleanup"))
return git_config_string(&cleanup_arg, k, v);
else if (!strcmp(k, "merge.renormalize"))
option_renormalize = git_config_bool(k, v);
else if (!strcmp(k, "merge.ff")) {
......@@ -800,8 +807,13 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
static const char merge_editor_comment[] =
N_("Please enter a commit message to explain why this merge is necessary,\n"
"especially if it merges an updated upstream into a topic branch.\n"
"\n"
"Lines starting with '%c' will be ignored, and an empty message aborts\n"
"\n");
static const char scissors_editor_comment[] =
N_("An empty message aborts the commit.\n");
static const char no_scissors_editor_comment[] =
N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
"the commit.\n");
static void write_merge_heads(struct commit_list *);
......@@ -809,11 +821,19 @@ static void prepare_to_commit(struct commit_list *remoteheads)
{
struct strbuf msg = STRBUF_INIT;
strbuf_addbuf(&msg, &merge_msg);
strbuf_addch(&msg, '\n');
if (squash)
BUG("the control must not reach here under --squash");
if (0 < option_edit)
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
if (0 < option_edit) {
strbuf_addch(&msg, '\n');
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
wt_status_append_cut_line(&msg);
strbuf_commented_addf(&msg, "\n");
}
strbuf_commented_addf(&msg, _(merge_editor_comment));
strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
scissors_editor_comment :
no_scissors_editor_comment), comment_line_char);
}
if (signoff)
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
......@@ -832,7 +852,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
abort_commit(remoteheads, NULL);
read_merge_msg(&msg);
strbuf_stripspace(&msg, 0 < option_edit);
cleanup_message(&msg, cleanup_mode, 0);
if (!msg.len)
abort_commit(remoteheads, _("Empty commit message."));
strbuf_release(&merge_msg);
......@@ -880,7 +900,6 @@ static int finish_automerge(struct commit *head,
parents = remoteheads;
if (!head_subsumed || fast_forward == FF_NO)
commit_list_insert(head, &parents);
strbuf_addch(&merge_msg, '\n');
prepare_to_commit(remoteheads);
if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
&result_commit, NULL, sign_commit))
......@@ -901,7 +920,15 @@ static int suggest_conflicts(void)
filename = git_path_merge_msg(the_repository);
fp = xfopen(filename, "a");
append_conflicts_hint(&the_index, &msgbuf);
/*
* We can't use cleanup_mode because if we're not using the editor,
* get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
* though the message is meant to be processed later by git-commit.
* Thus, we will get the cleanup mode which is returned when we _are_
* using an editor.
*/
append_conflicts_hint(&the_index, &msgbuf,
get_cleanup_mode(cleanup_arg, 1));
fputs(msgbuf.buf, fp);
strbuf_release(&msgbuf);
fclose(fp);
......@@ -1301,6 +1328,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
resolve_undo_clear();
if (option_edit < 0)
option_edit = default_edit_option();
cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
if (verbosity < 0)
show_diffstat = 0;
......@@ -1386,9 +1418,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
fast_forward = FF_NO;
}
if (option_edit < 0)
option_edit = default_edit_option();
if (!use_strategies) {
if (!remoteheads)
; /* already up-to-date */
......
......@@ -24,6 +24,7 @@
#include "lockfile.h"
#include "wt-status.h"
#include "commit-reach.h"
#include "sequencer.h"
enum rebase_type {
REBASE_INVALID = -1,
......@@ -101,6 +102,7 @@ static char *opt_signoff;
static char *opt_squash;
static char *opt_commit;
static char *opt_edit;
static char *cleanup_arg;
static char *opt_ff;
static char *opt_verify_signatures;
static int opt_autostash = -1;
......@@ -168,6 +170,7 @@ static struct option pull_options[] = {
OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
N_("edit message before committing"),
PARSE_OPT_NOARG),
OPT_CLEANUP(&cleanup_arg),
OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
N_("allow fast-forward"),
PARSE_OPT_NOARG),
......@@ -645,6 +648,8 @@ static int run_merge(void)
argv_array_push(&args, opt_commit);
if (opt_edit)
argv_array_push(&args, opt_edit);
if (cleanup_arg)
argv_array_pushf(&args, "--cleanup=%s", cleanup_arg);
if (opt_ff)
argv_array_push(&args, opt_ff);
if (opt_verify_signatures)
......@@ -876,6 +881,13 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
if (cleanup_arg)
/*
* this only checks the validity of cleanup_arg; we don't need
* a valid value for use_editor
*/
get_cleanup_mode(cleanup_arg, 0);
parse_repo_refspecs(argc, argv, &repo, &refspecs);
if (!opt_ff)
......
......@@ -96,11 +96,13 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
{
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
int cmd = 0;
struct option base_options[] = {
OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
OPT_CLEANUP(&cleanup_arg),
OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
......@@ -137,6 +139,11 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
if (opts->keep_redundant_commits)
opts->allow_empty = 1;
if (cleanup_arg) {
opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
opts->explicit_cleanup = 1;
}
/* Check for incompatible command line arguments */
if (cmd) {
char *this_operation;
......
......@@ -408,8 +408,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
N_("how to strip spaces and #comments from message")),
OPT_CLEANUP(&cleanup_arg),
OPT_STRING('u', "local-user", &keyid, N_("key-id"),
N_("use another key to sign the tag")),
OPT__FORCE(&force, N_("replace the tag if exists"), 0),
......
......@@ -316,5 +316,6 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG)
#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
#define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
#endif
......@@ -181,7 +181,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
opts->explicit_cleanup = 1;
} else if (!strcmp(s, "scissors")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
opts->explicit_cleanup = 1;
} else {
warning(_("invalid commit message cleanup mode '%s'"),
......@@ -515,11 +515,54 @@ static int fast_forward_to(struct repository *r,
return 0;
}
enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
int use_editor)
{
if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
return use_editor ? COMMIT_MSG_CLEANUP_ALL :
COMMIT_MSG_CLEANUP_SPACE;
else if (!strcmp(cleanup_arg, "verbatim"))
return COMMIT_MSG_CLEANUP_NONE;
else if (!strcmp(cleanup_arg, "whitespace"))
return COMMIT_MSG_CLEANUP_SPACE;
else if (!strcmp(cleanup_arg, "strip"))
return COMMIT_MSG_CLEANUP_ALL;
else if (!strcmp(cleanup_arg, "scissors"))
return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
COMMIT_MSG_CLEANUP_SPACE;
else
die(_("Invalid cleanup mode %s"), cleanup_arg);
}
/*
* NB using int rather than enum cleanup_mode to stop clang's
* -Wtautological-constant-out-of-range-compare complaining that the comparison
* is always true.
*/
static const char *describe_cleanup_mode(int cleanup_mode)
{
static const char *modes[] = { "whitespace",
"verbatim",
"scissors",
"strip" };
if (cleanup_mode < ARRAY_SIZE(modes))
return modes[cleanup_mode];
BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
}
void append_conflicts_hint(struct index_state *istate,
struct strbuf *msgbuf)
struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
{
int i;
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
strbuf_addch(msgbuf, '\n');
wt_status_append_cut_line(msgbuf);
strbuf_addch(msgbuf, comment_line_char);
}
strbuf_addch(msgbuf, '\n');
strbuf_commented_addf(msgbuf, "Conflicts:\n");
for (i = 0; i < istate->cache_nr;) {
......@@ -587,7 +630,8 @@ static int do_recursive_merge(struct repository *r,
_(action_name(opts)));
if (!clean)
append_conflicts_hint(r->index, msgbuf);
append_conflicts_hint(r->index, msgbuf,
opts->default_msg_cleanup);
return !clean;
}
......@@ -906,7 +950,6 @@ static int run_git_commit(struct repository *r,
unsigned int flags)
{
struct child_process cmd = CHILD_PROCESS_INIT;
const char *value;
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
......@@ -976,7 +1019,7 @@ static int run_git_commit(struct repository *r,
argv_array_push(&cmd.args, "-e");
else if (!(flags & CLEANUP_MSG) &&
!opts->signoff && !opts->record_origin &&
git_config_get_value("commit.cleanup", &value))
!opts->explicit_cleanup)
argv_array_push(&cmd.args, "--cleanup=verbatim");
if ((flags & ALLOW_EMPTY))
......@@ -1017,6 +1060,16 @@ static int rest_is_empty(const struct strbuf *sb, int start)
return 1;
}
void cleanup_message(struct strbuf *msgbuf,
enum commit_msg_cleanup_mode cleanup_mode, int verbose)
{
if (verbose || /* Truncate the message just before the diff, if any. */
cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
}
/*
* Find out if the message in the strbuf contains only whitespace and
* Signed-off-by lines.
......@@ -2313,7 +2366,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
opts->allow_rerere_auto =
git_config_bool_or_int(key, value, &error_flag) ?
RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
else
else if (!strcmp(key, "options.default-msg-cleanup")) {
opts->explicit_cleanup = 1;
opts->default_msg_cleanup = get_cleanup_mode(value, 1);
} else
return error(_("invalid key: %s"), key);
if (!error_flag)
......@@ -2735,6 +2791,11 @@ static int save_opts(struct replay_opts *opts)
"options.allow-rerere-auto",
opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
"true" : "false");
if (opts->explicit_cleanup)
res |= git_config_set_in_file_gently(opts_file,
"options.default-msg-cleanup",
describe_cleanup_mode(opts->default_msg_cleanup));
return res;
}
......
......@@ -163,7 +163,14 @@ int todo_list_rearrange_squash(struct todo_list *todo_list);
*/
void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf);
void append_conflicts_hint(struct index_state *istate,
struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode);
enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
int use_editor);
void cleanup_message(struct strbuf *msgbuf,
enum commit_msg_cleanup_mode cleanup_mode, int verbose);
int message_is_empty(const struct strbuf *sb,
enum commit_msg_cleanup_mode cleanup_mode);
int template_untouched(const struct strbuf *sb, const char *template_file,
......
......@@ -93,7 +93,7 @@ test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
pristine_detach initial &&
echo foo > foo &&
echo foo >foo &&
test_must_fail git cherry-pick base &&
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
'
......@@ -101,7 +101,7 @@ test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
test_expect_success \
'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
pristine_detach initial &&
echo foo > foo &&
echo foo >foo &&
test_must_fail git cherry-pick --strategy=resolve base &&
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
'
......@@ -180,23 +180,63 @@ test_expect_success 'failed cherry-pick registers participants in index' '
git ls-files --stage foo &&
git checkout picked -- foo &&
git ls-files --stage foo
} > stages &&
} >stages &&
sed "
1 s/ 0 / 1 /
2 s/ 0 / 2 /
3 s/ 0 / 3 /
" < stages > expected &&
" stages >expected &&
git read-tree -u --reset HEAD &&
test_must_fail git cherry-pick picked &&
git ls-files --stage --unmerged > actual &&
git ls-files --stage --unmerged >actual &&
test_cmp expected actual
'
test_expect_success \
'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
pristine_detach initial &&
git config commit.cleanup scissors &&
cat <<-EOF >expected &&
picked
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
# foo
EOF
test_must_fail git cherry-pick picked &&
test_i18ncmp expected .git/MERGE_MSG
'
test_expect_success \
'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
pristine_detach initial &&
git config --unset commit.cleanup &&
cat <<-EOF >expected &&
picked
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
# foo
EOF
test_must_fail git cherry-pick --cleanup=scissors picked &&
test_i18ncmp expected .git/MERGE_MSG
'
test_expect_success 'failed cherry-pick describes conflict in work tree' '
pristine_detach initial &&
cat <<-EOF > expected &&
cat <<-EOF >expected &&
<<<<<<< HEAD
a
=======
......@@ -206,14 +246,14 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
test_must_fail git cherry-pick picked &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
test_cmp expected actual
'
test_expect_success 'diff3 -m style' '
pristine_detach initial &&
git config merge.conflictstyle diff3 &&
cat <<-EOF > expected &&
cat <<-EOF >expected &&
<<<<<<< HEAD
a
||||||| parent of objid picked
......@@ -225,14 +265,14 @@ test_expect_success 'diff3 -m style' '
test_must_fail git cherry-pick picked &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
test_cmp expected actual
'
test_expect_success 'revert also handles conflicts sanely' '
git config --unset merge.conflictstyle &&
pristine_detach initial &&
cat <<-EOF > expected &&
cat <<-EOF >expected &&
<<<<<<< HEAD
a
=======
......@@ -246,24 +286,24 @@ test_expect_success 'revert also handles conflicts sanely' '
git ls-files --stage foo &&
git checkout base -- foo &&
git ls-files --stage foo
} > stages &&
} >stages &&
sed "
1 s/ 0 / 1 /
2 s/ 0 / 2 /
3 s/ 0 / 3 /
" < stages > expected-stages &&
" stages >expected-stages &&
git read-tree -u --reset HEAD &&
head=$(git rev-parse HEAD) &&
test_must_fail git revert picked &&
newhead=$(git rev-parse HEAD) &&
git ls-files --stage --unmerged > actual-stages &&
git ls-files --stage --unmerged >actual-stages &&
test "$head" = "$newhead" &&
test_must_fail git update-index --refresh -q &&
test_must_fail git diff-index --exit-code HEAD &&
test_cmp expected-stages actual-stages &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
test_cmp expected actual
'
......@@ -289,7 +329,7 @@ test_expect_success 'revert --no-commit sets REVERT_HEAD' '
test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
pristine_detach base &&
echo foo > foo &&
echo foo >foo &&
test_must_fail git revert base &&
test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
test_must_fail git rev-parse --verify REVERT_HEAD
......@@ -324,7 +364,7 @@ test_expect_success 'failed commit does not clear REVERT_HEAD' '
test_expect_success 'revert conflict, diff3 -m style' '
pristine_detach initial &&
git config merge.conflictstyle diff3 &&
cat <<-EOF > expected &&
cat <<-EOF >expected &&
<<<<<<< HEAD
a
||||||| objid picked
......@@ -336,10 +376,56 @@ test_expect_success 'revert conflict, diff3 -m style' '
test_must_fail git revert picked &&
sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
test_cmp expected actual
'
test_expect_success \
'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
pristine_detach initial &&
git config commit.cleanup scissors &&
cat >expected <<-EOF &&
Revert "picked"
This reverts commit OBJID.
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
# foo
EOF
test_must_fail git revert picked &&
sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
test_i18ncmp expected actual
'
test_expect_success \
'revert conflict, ensure cleanup=scissors places scissors line properly' '
pristine_detach initial &&
git config --unset commit.cleanup &&
cat >expected <<-EOF &&
Revert "picked"
This reverts commit OBJID.
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
# foo
EOF
test_must_fail git revert --cleanup=scissors picked &&
sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
test_i18ncmp expected actual
'
test_expect_success 'failed cherry-pick does not forget -s' '
pristine_detach initial &&
test_must_fail git cherry-pick -s picked &&
......@@ -350,7 +436,7 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
pristine_detach initial &&
test_must_fail git cherry-pick -s picked-signed &&
git commit -a -s &&
test $(git show -s |grep -c "Signed-off-by") = 1
test $(git show -s >tmp && grep -c "Signed-off-by" tmp && rm tmp) = 1
'
test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
......@@ -364,7 +450,7 @@ test_expect_success 'commit after failed cherry-pick adds -s at the right place'
Signed-off-by: C O Mitter <committer@example.com>
# Conflicts:
EOF
grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
grep -e "^# Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
test_cmp expect actual &&
cat <<-\EOF >expected &&
......@@ -383,7 +469,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
# emulate old-style conflicts block
mv .git/MERGE_MSG .git/MERGE_MSG+ &&
sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
sed -e "/^# Conflicts:/,\$s/^# *//" .git/MERGE_MSG+ >.git/MERGE_MSG &&
git commit -a &&
git commit --amend -s &&
......@@ -393,7 +479,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
Signed-off-by: C O Mitter <committer@example.com>
Conflicts:
EOF
grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
grep -e "^Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
test_cmp expect actual
'
......
......@@ -77,6 +77,14 @@ test_expect_success 'git pull -q -v' '
test_must_be_empty out &&
test -s err)
'
test_expect_success 'git pull --cleanup errors early on invalid argument' '
mkdir clonedcleanup &&
(cd clonedcleanup && git init &&
test_must_fail git pull --cleanup invalid "../parent" >out 2>err &&
test_must_be_empty out &&
test -s err)
'
test_expect_success 'git pull --force' '
mkdir clonedoldstyle &&
......
......@@ -16,7 +16,8 @@ commit_msg_is () {
# Arguments: [<prefix] [<commit message>] [<commit options>]
check_summary_oneline() {
test_tick &&
git commit ${3+"$3"} -m "$2" | head -1 > act &&
git commit ${3+"$3"} -m "$2" >raw &&
head -n 1 raw >act &&
# branch name
SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
......@@ -68,7 +69,7 @@ test_expect_success 'output summary format for merges' '
git checkout recursive-a &&
test_must_fail git merge recursive-b &&
# resolve the conflict
echo commit-a > file1 &&
echo commit-a >file1 &&
git add file1 &&
check_summary_oneline "" "Merge"
'
......@@ -142,9 +143,11 @@ test_expect_success 'sign off' '
>positive &&
git add positive &&
git commit -s -m "thank you" &&
actual=$(git cat-file commit HEAD | sed -ne "s/Signed-off-by: //p") &&
expected=$(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") &&
test "z$actual" = "z$expected"
git cat-file commit HEAD >commit.msg &&
sed -ne "s/Signed-off-by: //p" commit.msg >actual &&
git var GIT_COMMITTER_IDENT >ident &&
sed -e "s/>.*/>/" ident >expected &&
test_cmp expected actual
'
......@@ -153,8 +156,8 @@ test_expect_success 'multiple -m' '
>negative &&
git add negative &&
git commit -m "one" -m "two" -m "three" &&
actual=$(git cat-file commit HEAD | sed -e "1,/^\$/d") &&
expected=$(echo one; echo; echo two; echo; echo three) &&
actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" tmp && rm tmp) &&
expected=$(test_write_lines "one" "" "two" "" "three") &&
test "z$actual" = "z$expected"
'
......@@ -163,7 +166,8 @@ test_expect_success 'verbose' '
echo minus >negative &&
git add negative &&
git status -v | sed -ne "/^diff --git /p" >actual &&
git status -v >raw &&
sed -ne "/^diff --git /p" raw >actual &&
echo "diff --git a/negative b/negative" >expect &&
test_cmp expect actual
......@@ -189,7 +193,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-t)' '
echo >>negative &&
git commit --cleanup=verbatim --no-status -t expect -a &&
git cat-file -p HEAD |sed -e "1,/^\$/d" >actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_cmp expect actual
'
......@@ -198,7 +203,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-F)' '
echo >>negative &&
git commit --cleanup=verbatim -F expect -a &&
git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_cmp expect actual
'
......@@ -207,7 +213,8 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
echo >>negative &&
git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_cmp expect actual
'
......@@ -215,10 +222,11 @@ test_expect_success 'cleanup commit messages (verbatim option,-m)' '
test_expect_success 'cleanup commit messages (whitespace option,-F)' '
echo >>negative &&
{ echo;echo "# text";echo; } >text &&
test_write_lines "" "# text" "" >text &&
echo "# text" >expect &&
git commit --cleanup=whitespace -F text -a &&
git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_cmp expect actual
'
......@@ -226,48 +234,51 @@ test_expect_success 'cleanup commit messages (whitespace option,-F)' '
test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
echo >>negative &&
cat >text <<EOF &&
cat >text <<-\EOF &&
# to be kept
# to be kept
# ------------------------ >8 ------------------------
# to be kept, too
# ------------------------ >8 ------------------------
to be removed
# ------------------------ >8 ------------------------
to be removed, too
EOF
# ------------------------ >8 ------------------------
# to be kept, too
# ------------------------ >8 ------------------------
to be removed
# ------------------------ >8 ------------------------
to be removed, too
EOF
cat >expect <<EOF &&
# to be kept
cat >expect <<-\EOF &&
# to be kept
# ------------------------ >8 ------------------------
# to be kept, too
EOF
# ------------------------ >8 ------------------------
# to be kept, too
EOF
git commit --cleanup=scissors -e -F text -a &&
git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_cmp expect actual
'
test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' '
echo >>negative &&
cat >text <<EOF &&
# ------------------------ >8 ------------------------
to be removed
EOF
cat >text <<-\EOF &&
# ------------------------ >8 ------------------------
to be removed
EOF
git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_must_be_empty actual
'
test_expect_success 'cleanup commit messages (strip option,-F)' '
echo >>negative &&
{ echo;echo "# text";echo sample;echo; } >text &&
test_write_lines "" "# text" "sample" "" >text &&
echo sample >expect &&
git commit --cleanup=strip -F text -a &&
git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
git cat-file -p HEAD >raw &&
sed -e "1,/^\$/d" raw >actual &&
test_cmp expect actual
'
......@@ -275,7 +286,7 @@ test_expect_success 'cleanup commit messages (strip option,-F)' '
test_expect_success 'cleanup commit messages (strip option,-F,-e)' '
echo >>negative &&
{ echo;echo sample;echo; } >text &&
test_write_lines "" "sample" "" >text &&
git commit -e -F text -a &&
head -n 4 .git/COMMIT_EDITMSG >actual
'
......@@ -387,7 +398,7 @@ test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
'
write_script .git/FAKE_EDITOR <<EOF
echo editor started > "$(pwd)/.git/result"
echo editor started >"$(pwd)/.git/result"
exit 0
EOF
......@@ -455,7 +466,7 @@ EOF
test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' '
echo >>negative &&
! "$SHELL_PATH" -c '\''
echo kill -TERM $$ >> .git/FAKE_EDITOR
echo kill -TERM $$ >>.git/FAKE_EDITOR
GIT_EDITOR=.git/FAKE_EDITOR
export GIT_EDITOR
exec git commit -a'\'' &&
......@@ -471,7 +482,8 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '
test_must_fail git merge second master &&
git checkout master g &&
EDITOR=: git commit -a &&
git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual &&
git cat-file commit HEAD >raw &&
sed -n -e "s/^parent //p" -e "/^$/q" raw >actual &&
test_cmp expect actual
'
......@@ -480,7 +492,8 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo
git reset --hard &&
git commit -s -m "hello: kitty" --allow-empty &&
git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_line_count = 3 actual
'
......
......@@ -233,20 +233,65 @@ test_expect_success 'merge --squash c3 with c7' '
cat result.9z >file &&
git commit --no-edit -a &&
{
cat <<-EOF
Squashed commit of the following:
cat >expect <<-EOF &&
Squashed commit of the following:
$(git show -s c7)
$(git show -s c7)
# Conflicts:
# file
EOF
} >expect &&
git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
# Conflicts:
# file
EOF
git cat-file commit HEAD >raw &&
sed -e '1,/^$/d' raw >actual &&
test_cmp expect actual
'
test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
git config commit.cleanup scissors &&
git reset --hard c3 &&
test_must_fail git merge c7 &&
cat result.9z >file &&
git commit --no-edit -a &&
cat >expect <<-\EOF &&
Merge tag '"'"'c7'"'"'
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
# file
EOF
git cat-file commit HEAD >raw &&
sed -e '1,/^$/d' raw >actual &&
test_i18ncmp expect actual
'
test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
git config commit.cleanup scissors &&
git reset --hard c3 &&
test_must_fail git merge --squash c7 &&
cat result.9z >file &&
git commit --no-edit -a &&
cat >expect <<-EOF &&
Squashed commit of the following:
$(git show -s c7)
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
# file
EOF
git cat-file commit HEAD >raw &&
sed -e '1,/^$/d' raw >actual &&
test_i18ncmp expect actual
'
test_debug 'git log --graph --decorate --oneline --all'
test_expect_success 'merge c1 with c2 and c3' '
......@@ -680,10 +725,10 @@ cat >editor <<\EOF
(
echo "Merge work done on the side branch c1"
echo
cat <"$1"
cat "$1"
) >"$1.tmp" && mv "$1.tmp" "$1"
# strip comments and blank lines from end of message
sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
sed -e '/^#/d' "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' >expected
EOF
chmod 755 editor
......@@ -768,14 +813,14 @@ test_expect_success 'set up mod-256 conflict scenario' '
git commit -m base &&
# one side changes the first line of each to "master"
sed s/-1/-master/ <file >tmp &&
sed s/-1/-master/ file >tmp &&
mv tmp file &&
git commit -am master &&
# and the other to "side"; merging the two will
# yield 256 separate conflicts
git checkout -b side HEAD^ &&
sed s/-1/-side/ <file >tmp &&
sed s/-1/-side/ file >tmp &&
mv tmp file &&
git commit -am side
'
......@@ -814,7 +859,7 @@ EOF
test_expect_success EXECKEEPSPID 'killed merge can be completed with --continue' '
git reset --hard c0 &&
! "$SHELL_PATH" -c '\''
echo kill -TERM $$ >> .git/FAKE_EDITOR
echo kill -TERM $$ >>.git/FAKE_EDITOR
GIT_EDITOR=.git/FAKE_EDITOR
export GIT_EDITOR
exec git merge --no-ff --edit c1'\'' &&
......
......@@ -16,16 +16,16 @@ create_merge_msgs() {
}
test_expect_success 'setup' '
echo c0 > c0.c &&
echo c0 >c0.c &&
git add c0.c &&
git commit -m c0 &&
git tag c0 &&
echo c1 > c1.c &&
echo c1 >c1.c &&
git add c1.c &&
git commit -m c1 &&
git tag c1 &&
git reset --hard c0 &&
echo c2 > c2.c &&
echo c2 >c2.c &&
git add c2.c &&
git commit -m c2 &&
git tag c2 &&
......@@ -36,15 +36,80 @@ test_expect_success 'setup' '
test_expect_success 'merge c2 with a custom message' '
git reset --hard c1 &&
git merge -m "$(cat exp.subject)" c2 &&
git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_cmp exp.subject actual
'
test_expect_success 'merge --log appends to custom message' '
git reset --hard c1 &&
git merge --log -m "$(cat exp.subject)" c2 &&
git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_cmp exp.log actual
'
mesg_with_comment_and_newlines='
# text
'
test_expect_success 'prepare file with comment line and trailing newlines' '
printf "%s" "$mesg_with_comment_and_newlines" >expect
'
test_expect_success 'cleanup commit messages (verbatim option)' '
git reset --hard c1 &&
git merge --cleanup=verbatim -F expect c2 &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_cmp expect actual
'
test_expect_success 'cleanup commit messages (whitespace option)' '
git reset --hard c1 &&
test_write_lines "" "# text" "" >text &&
echo "# text" >expect &&
git merge --cleanup=whitespace -F text c2 &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_cmp expect actual
'
test_expect_success 'cleanup merge messages (scissors option)' '
git reset --hard c1 &&
cat >text <<-\EOF &&
# to be kept
# ------------------------ >8 ------------------------
# to be kept, too
# ------------------------ >8 ------------------------
to be removed
# ------------------------ >8 ------------------------
to be removed, too
EOF
cat >expect <<-\EOF &&
# to be kept
# ------------------------ >8 ------------------------
# to be kept, too
EOF
git merge --cleanup=scissors -e -F text c2 &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_cmp expect actual
'
test_expect_success 'cleanup commit messages (strip option)' '
git reset --hard c1 &&
test_write_lines "" "# text" "sample" "" >text &&
echo sample >expect &&
git merge --cleanup=strip -F text c2 &&
git cat-file commit HEAD >raw &&
sed -e "1,/^$/d" raw >actual &&
test_cmp expect actual
'
test_done
......@@ -1006,13 +1006,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
return len;
}
void wt_status_add_cut_line(FILE *fp)
void wt_status_append_cut_line(struct strbuf *buf)
{
const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
strbuf_commented_addf(buf, "%s", cut_line);
strbuf_add_commented_lines(buf, explanation, strlen(explanation));
}
void wt_status_add_cut_line(FILE *fp)
{
struct strbuf buf = STRBUF_INIT;
fprintf(fp, "%c %s", comment_line_char, cut_line);
strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
wt_status_append_cut_line(&buf);
fputs(buf.buf, fp);
strbuf_release(&buf);
}
......
......@@ -129,6 +129,7 @@ struct wt_status {
};
size_t wt_status_locate_end(const char *s, size_t len);
void wt_status_append_cut_line(struct strbuf *buf);
void wt_status_add_cut_line(FILE *fp);
void wt_status_prepare(struct repository *r, struct wt_status *s);
void wt_status_print(struct wt_status *s);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册