зеркало из https://github.com/microsoft/git.git
Merge branch 'ci/commit--interactive-atomic'
* ci/commit--interactive-atomic: Test atomic git-commit --interactive Add commit to list of config.singlekey commands Add support for -p/--patch to git-commit Allow git commit --interactive with paths t7501.8: feed a meaningful command Use a temporary index for git commit --interactive
This commit is contained in:
Коммит
7a77754cf6
|
@ -1310,9 +1310,10 @@ interactive.singlekey::
|
||||||
In interactive commands, allow the user to provide one-letter
|
In interactive commands, allow the user to provide one-letter
|
||||||
input with a single key (i.e., without hitting enter).
|
input with a single key (i.e., without hitting enter).
|
||||||
Currently this is used by the `\--patch` mode of
|
Currently this is used by the `\--patch` mode of
|
||||||
linkgit:git-add[1], linkgit:git-reset[1], linkgit:git-stash[1] and
|
linkgit:git-add[1], linkgit:git-checkout[1], linkgit:git-commit[1],
|
||||||
linkgit:git-checkout[1]. Note that this setting is silently
|
linkgit:git-reset[1], and linkgit:git-stash[1]. Note that this
|
||||||
ignored if portable keystroke input is not available.
|
setting is silently ignored if portable keystroke input
|
||||||
|
is not available.
|
||||||
|
|
||||||
log.date::
|
log.date::
|
||||||
Set the default date-time mode for the 'log' command.
|
Set the default date-time mode for the 'log' command.
|
||||||
|
|
|
@ -8,11 +8,12 @@ git-commit - Record changes to the repository
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]
|
'git commit' [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
|
||||||
[(-c | -C | --fixup | --squash) <commit>] [-F <file> | -m <msg>]
|
[--dry-run] [(-c | -C | --fixup | --squash) <commit>]
|
||||||
[--reset-author] [--allow-empty] [--allow-empty-message] [--no-verify]
|
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
|
||||||
[-e] [--author=<author>] [--date=<date>] [--cleanup=<mode>]
|
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
|
||||||
[--status | --no-status] [-i | -o] [--] [<file>...]
|
[--date=<date>] [--cleanup=<mode>] [--status | --no-status]
|
||||||
|
[-i | -o] [--] [<file>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -39,9 +40,10 @@ The content to be added can be specified in several ways:
|
||||||
that have been removed from the working tree, and then perform the
|
that have been removed from the working tree, and then perform the
|
||||||
actual commit;
|
actual commit;
|
||||||
|
|
||||||
5. by using the --interactive switch with the 'commit' command to decide one
|
5. by using the --interactive or --patch switches with the 'commit' command
|
||||||
by one which files should be part of the commit, before finalizing the
|
to decide one by one which files or hunks should be part of the commit,
|
||||||
operation. Currently, this is done by invoking 'git add --interactive'.
|
before finalizing the operation. See the ``Interactive Mode`` section of
|
||||||
|
linkgit:git-add[1] to learn how to operate these modes.
|
||||||
|
|
||||||
The `--dry-run` option 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
|
summary of what is included by any of the above for the next
|
||||||
|
@ -59,6 +61,12 @@ OPTIONS
|
||||||
been modified and deleted, but new files you have not
|
been modified and deleted, but new files you have not
|
||||||
told git about are not affected.
|
told git about are not affected.
|
||||||
|
|
||||||
|
-p::
|
||||||
|
--patch::
|
||||||
|
Use the interactive patch selection interface to chose
|
||||||
|
which changes to commit. See linkgit:git-add[1] for
|
||||||
|
details.
|
||||||
|
|
||||||
-C <commit>::
|
-C <commit>::
|
||||||
--reuse-message=<commit>::
|
--reuse-message=<commit>::
|
||||||
Take an existing commit object, and reuse the log message
|
Take an existing commit object, and reuse the log message
|
||||||
|
|
|
@ -242,7 +242,7 @@ int run_add_interactive(const char *revision, const char *patch_mode,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int interactive_add(int argc, const char **argv, const char *prefix)
|
int interactive_add(int argc, const char **argv, const char *prefix, int patch)
|
||||||
{
|
{
|
||||||
const char **pathspec = NULL;
|
const char **pathspec = NULL;
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ int interactive_add(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
return run_add_interactive(NULL,
|
return run_add_interactive(NULL,
|
||||||
patch_interactive ? "--patch" : NULL,
|
patch ? "--patch" : NULL,
|
||||||
pathspec);
|
pathspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
if (patch_interactive)
|
if (patch_interactive)
|
||||||
add_interactive = 1;
|
add_interactive = 1;
|
||||||
if (add_interactive)
|
if (add_interactive)
|
||||||
exit(interactive_add(argc - 1, argv + 1, prefix));
|
exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
|
||||||
|
|
||||||
if (edit_interactive)
|
if (edit_interactive)
|
||||||
return(edit_patch(argc, argv, prefix));
|
return(edit_patch(argc, argv, prefix));
|
||||||
|
|
|
@ -83,7 +83,7 @@ static const char *template_file;
|
||||||
static const char *author_message, *author_message_buffer;
|
static const char *author_message, *author_message_buffer;
|
||||||
static char *edit_message, *use_message;
|
static char *edit_message, *use_message;
|
||||||
static char *fixup_message, *squash_message;
|
static char *fixup_message, *squash_message;
|
||||||
static int all, edit_flag, also, interactive, only, amend, signoff;
|
static int all, edit_flag, also, interactive, patch_interactive, only, amend, signoff;
|
||||||
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
||||||
static int no_post_rewrite, allow_empty_message;
|
static int no_post_rewrite, allow_empty_message;
|
||||||
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
||||||
|
@ -152,6 +152,7 @@ static struct option builtin_commit_options[] = {
|
||||||
OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
|
OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
|
||||||
OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
|
OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
|
||||||
OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
|
OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
|
||||||
|
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
|
||||||
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
|
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
|
||||||
OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
|
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, "dry-run", &dry_run, "show what would be committed"),
|
||||||
|
@ -336,18 +337,11 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
|
||||||
int fd;
|
int fd;
|
||||||
struct string_list partial;
|
struct string_list partial;
|
||||||
const char **pathspec = NULL;
|
const char **pathspec = NULL;
|
||||||
|
char *old_index_env = NULL;
|
||||||
int refresh_flags = REFRESH_QUIET;
|
int refresh_flags = REFRESH_QUIET;
|
||||||
|
|
||||||
if (is_status)
|
if (is_status)
|
||||||
refresh_flags |= REFRESH_UNMERGED;
|
refresh_flags |= REFRESH_UNMERGED;
|
||||||
if (interactive) {
|
|
||||||
if (interactive_add(argc, argv, prefix) != 0)
|
|
||||||
die(_("interactive add failed"));
|
|
||||||
if (read_cache_preload(NULL) < 0)
|
|
||||||
die(_("index file corrupt"));
|
|
||||||
commit_style = COMMIT_AS_IS;
|
|
||||||
return get_index_file();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*argv)
|
if (*argv)
|
||||||
pathspec = get_pathspec(prefix, argv);
|
pathspec = get_pathspec(prefix, argv);
|
||||||
|
@ -355,6 +349,33 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
|
||||||
if (read_cache_preload(pathspec) < 0)
|
if (read_cache_preload(pathspec) < 0)
|
||||||
die(_("index file corrupt"));
|
die(_("index file corrupt"));
|
||||||
|
|
||||||
|
if (interactive) {
|
||||||
|
fd = hold_locked_index(&index_lock, 1);
|
||||||
|
|
||||||
|
refresh_cache_or_die(refresh_flags);
|
||||||
|
|
||||||
|
if (write_cache(fd, active_cache, active_nr) ||
|
||||||
|
close_lock_file(&index_lock))
|
||||||
|
die(_("unable to create temporary index"));
|
||||||
|
|
||||||
|
old_index_env = getenv(INDEX_ENVIRONMENT);
|
||||||
|
setenv(INDEX_ENVIRONMENT, index_lock.filename, 1);
|
||||||
|
|
||||||
|
if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
|
||||||
|
die(_("interactive add failed"));
|
||||||
|
|
||||||
|
if (old_index_env && *old_index_env)
|
||||||
|
setenv(INDEX_ENVIRONMENT, old_index_env, 1);
|
||||||
|
else
|
||||||
|
unsetenv(INDEX_ENVIRONMENT);
|
||||||
|
|
||||||
|
discard_cache();
|
||||||
|
read_cache_from(index_lock.filename);
|
||||||
|
|
||||||
|
commit_style = COMMIT_NORMAL;
|
||||||
|
return index_lock.filename;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non partial, non as-is commit.
|
* Non partial, non as-is commit.
|
||||||
*
|
*
|
||||||
|
@ -1043,8 +1064,11 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||||
author_message_buffer = read_commit_message(author_message);
|
author_message_buffer = read_commit_message(author_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (patch_interactive)
|
||||||
|
interactive = 1;
|
||||||
|
|
||||||
if (!!also + !!only + !!all + !!interactive > 1)
|
if (!!also + !!only + !!all + !!interactive > 1)
|
||||||
die(_("Only one of --include/--only/--all/--interactive can be used."));
|
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
|
||||||
if (argc == 0 && (also || (only && !amend)))
|
if (argc == 0 && (also || (only && !amend)))
|
||||||
die(_("No paths with --include/--only does not make sense."));
|
die(_("No paths with --include/--only does not make sense."));
|
||||||
if (argc == 0 && only && amend)
|
if (argc == 0 && only && amend)
|
||||||
|
@ -1066,8 +1090,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
|
||||||
|
|
||||||
if (all && argc > 0)
|
if (all && argc > 0)
|
||||||
die(_("Paths with -a does not make sense."));
|
die(_("Paths with -a does not make sense."));
|
||||||
else if (interactive && argc > 0)
|
|
||||||
die(_("Paths with --interactive does not make sense."));
|
|
||||||
|
|
||||||
if (null_termination && status_format == STATUS_FORMAT_LONG)
|
if (null_termination && status_format == STATUS_FORMAT_LONG)
|
||||||
status_format = STATUS_FORMAT_PORCELAIN;
|
status_format = STATUS_FORMAT_PORCELAIN;
|
||||||
|
|
2
commit.h
2
commit.h
|
@ -161,7 +161,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
|
||||||
int is_descendant_of(struct commit *, struct commit_list *);
|
int is_descendant_of(struct commit *, struct commit_list *);
|
||||||
int in_merge_bases(struct commit *, struct commit **, int);
|
int in_merge_bases(struct commit *, struct commit **, int);
|
||||||
|
|
||||||
extern int interactive_add(int argc, const char **argv, const char *prefix);
|
extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);
|
||||||
extern int run_add_interactive(const char *revision, const char *patch_mode,
|
extern int run_add_interactive(const char *revision, const char *patch_mode,
|
||||||
const char **pathspec);
|
const char **pathspec);
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,13 @@ test_expect_success \
|
||||||
"echo King of the bongo >file &&
|
"echo King of the bongo >file &&
|
||||||
test_must_fail git commit -m foo -a file"
|
test_must_fail git commit -m foo -a file"
|
||||||
|
|
||||||
test_expect_success PERL \
|
test_expect_success PERL 'can use paths with --interactive' '
|
||||||
"using paths with --interactive" \
|
echo bong-o-bong >file &&
|
||||||
"echo bong-o-bong >file &&
|
# 2: update, 1:st path, that is all, 7: quit
|
||||||
! (echo 7 | git commit -m foo --interactive file)"
|
( echo 2; echo 1; echo; echo 7 ) |
|
||||||
|
git commit -m foo --interactive file &&
|
||||||
|
git reset --hard HEAD^
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
"using invalid commit with -C" \
|
"using invalid commit with -C" \
|
||||||
|
@ -131,6 +134,16 @@ test_expect_success PERL \
|
||||||
"interactive add" \
|
"interactive add" \
|
||||||
"echo 7 | git commit --interactive | grep 'What now'"
|
"echo 7 | git commit --interactive | grep 'What now'"
|
||||||
|
|
||||||
|
test_expect_success PERL \
|
||||||
|
"commit --interactive doesn't change index if editor aborts" \
|
||||||
|
"echo zoo >file &&
|
||||||
|
test_must_fail git diff --exit-code >diff1 &&
|
||||||
|
(echo u ; echo '*' ; echo q) |
|
||||||
|
(EDITOR=: && export EDITOR &&
|
||||||
|
test_must_fail git commit --interactive) &&
|
||||||
|
git diff >diff2 &&
|
||||||
|
test_cmp diff1 diff2"
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
"showing committed revisions" \
|
"showing committed revisions" \
|
||||||
"git rev-list HEAD >current"
|
"git rev-list HEAD >current"
|
||||||
|
|
Загрузка…
Ссылка в новой задаче