Merge branch 'wc/add-i'
* wc/add-i: git-add -i: add help text for list-and-choose UI add -i: allow prefix highlighting for "Add untracked" as well. Highlight keyboard shortcuts in git-add--interactive Document all help keys in "git add -i" patch mode. Add "--patch" option to git-add--interactive add -i: Fix running from a subdirectory builtin-add: fix command line building to call interactive git-add -i: allow multiple selection in patch subcommand Add path-limiting to git-add--interactive Teach builtin-add to pass multiple paths to git-add--interactive
This commit is contained in:
commit
ab7d707669
@ -61,7 +61,14 @@ OPTIONS
|
|||||||
|
|
||||||
-i, \--interactive::
|
-i, \--interactive::
|
||||||
Add modified contents in the working tree interactively to
|
Add modified contents in the working tree interactively to
|
||||||
the index.
|
the index. Optional path arguments may be supplied to limit
|
||||||
|
operation to a subset of the working tree. See ``Interactive
|
||||||
|
mode'' for details.
|
||||||
|
|
||||||
|
-p, \--patch:
|
||||||
|
Similar to Interactive mode but the initial command loop is
|
||||||
|
bypassed and the 'patch' subcommand is invoked using each of
|
||||||
|
the specified filepatterns before exiting.
|
||||||
|
|
||||||
-u::
|
-u::
|
||||||
Update only files that git already knows about. This is similar
|
Update only files that git already knows about. This is similar
|
||||||
@ -210,6 +217,8 @@ patch::
|
|||||||
k - do not decide on this hunk now, and view the previous
|
k - do not decide on this hunk now, and view the previous
|
||||||
undecided hunk
|
undecided hunk
|
||||||
K - do not decide on this hunk now, and view the previous hunk
|
K - do not decide on this hunk now, and view the previous hunk
|
||||||
|
s - split the current hunk into smaller hunks
|
||||||
|
? - print help
|
||||||
+
|
+
|
||||||
After deciding the fate for all hunks, if there is any hunk
|
After deciding the fate for all hunks, if there is any hunk
|
||||||
that was chosen, the index is updated with the selected hunks.
|
that was chosen, the index is updated with the selected hunks.
|
||||||
|
@ -19,7 +19,7 @@ static const char * const builtin_add_usage[] = {
|
|||||||
"git-add [options] [--] <filepattern>...",
|
"git-add [options] [--] <filepattern>...",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
static int patch_interactive = 0, add_interactive = 0;
|
||||||
static int take_worktree_changes;
|
static int take_worktree_changes;
|
||||||
|
|
||||||
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
||||||
@ -135,11 +135,40 @@ static void refresh(int verbose, const char **pathspec)
|
|||||||
free(seen);
|
free(seen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int interactive_add(void)
|
static const char **validate_pathspec(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
const char *argv[2] = { "add--interactive", NULL };
|
const char **pathspec = get_pathspec(prefix, argv);
|
||||||
|
|
||||||
return run_command_v_opt(argv, RUN_GIT_CMD);
|
return pathspec;
|
||||||
|
}
|
||||||
|
|
||||||
|
int interactive_add(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
int status, ac;
|
||||||
|
const char **args;
|
||||||
|
const char **pathspec = NULL;
|
||||||
|
|
||||||
|
if (argc) {
|
||||||
|
pathspec = validate_pathspec(argc, argv, prefix);
|
||||||
|
if (!pathspec)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
args = xcalloc(sizeof(const char *), (argc + 4));
|
||||||
|
ac = 0;
|
||||||
|
args[ac++] = "add--interactive";
|
||||||
|
if (patch_interactive)
|
||||||
|
args[ac++] = "--patch";
|
||||||
|
args[ac++] = "--";
|
||||||
|
if (argc) {
|
||||||
|
memcpy(&(args[ac]), pathspec, sizeof(const char *) * argc);
|
||||||
|
ac += argc;
|
||||||
|
}
|
||||||
|
args[ac] = NULL;
|
||||||
|
|
||||||
|
status = run_command_v_opt(args, RUN_GIT_CMD);
|
||||||
|
free(args);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct lock_file lock_file;
|
static struct lock_file lock_file;
|
||||||
@ -148,13 +177,13 @@ static const char ignore_error[] =
|
|||||||
"The following paths are ignored by one of your .gitignore files:\n";
|
"The following paths are ignored by one of your .gitignore files:\n";
|
||||||
|
|
||||||
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
||||||
static int add_interactive = 0;
|
|
||||||
|
|
||||||
static struct option builtin_add_options[] = {
|
static struct option builtin_add_options[] = {
|
||||||
OPT__DRY_RUN(&show_only),
|
OPT__DRY_RUN(&show_only),
|
||||||
OPT__VERBOSE(&verbose),
|
OPT__VERBOSE(&verbose),
|
||||||
OPT_GROUP(""),
|
OPT_GROUP(""),
|
||||||
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
|
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
|
||||||
|
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
|
||||||
OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
|
OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
|
||||||
OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
|
OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
|
||||||
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
||||||
@ -163,17 +192,16 @@ static struct option builtin_add_options[] = {
|
|||||||
|
|
||||||
int cmd_add(int argc, const char **argv, const char *prefix)
|
int cmd_add(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i, newfd, orig_argc = argc;
|
int i, newfd;
|
||||||
const char **pathspec;
|
const char **pathspec;
|
||||||
struct dir_struct dir;
|
struct dir_struct dir;
|
||||||
|
|
||||||
argc = parse_options(argc, argv, builtin_add_options,
|
argc = parse_options(argc, argv, builtin_add_options,
|
||||||
builtin_add_usage, 0);
|
builtin_add_usage, 0);
|
||||||
if (add_interactive) {
|
if (patch_interactive)
|
||||||
if (add_interactive != 1 || orig_argc != 2)
|
add_interactive = 1;
|
||||||
die("add --interactive does not take any parameters");
|
if (add_interactive)
|
||||||
exit(interactive_add());
|
exit(interactive_add(argc, argv, prefix));
|
||||||
}
|
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_default_config);
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ static void add_remove_files(struct path_list *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *prepare_index(const char **files, const char *prefix)
|
static char *prepare_index(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct tree *tree;
|
struct tree *tree;
|
||||||
@ -171,7 +171,7 @@ static char *prepare_index(const char **files, const char *prefix)
|
|||||||
const char **pathspec = NULL;
|
const char **pathspec = NULL;
|
||||||
|
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
interactive_add();
|
interactive_add(argc, argv, prefix);
|
||||||
commit_style = COMMIT_AS_IS;
|
commit_style = COMMIT_AS_IS;
|
||||||
return get_index_file();
|
return get_index_file();
|
||||||
}
|
}
|
||||||
@ -179,8 +179,8 @@ static char *prepare_index(const char **files, const char *prefix)
|
|||||||
if (read_cache() < 0)
|
if (read_cache() < 0)
|
||||||
die("index file corrupt");
|
die("index file corrupt");
|
||||||
|
|
||||||
if (*files)
|
if (*argv)
|
||||||
pathspec = get_pathspec(prefix, files);
|
pathspec = get_pathspec(prefix, argv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non partial, non as-is commit.
|
* Non partial, non as-is commit.
|
||||||
@ -603,7 +603,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
argc = parse_and_validate_options(argc, argv, builtin_status_usage);
|
argc = parse_and_validate_options(argc, argv, builtin_status_usage);
|
||||||
|
|
||||||
index_file = prepare_index(argv, prefix);
|
index_file = prepare_index(argc, argv, prefix);
|
||||||
|
|
||||||
commitable = run_status(stdout, index_file, prefix);
|
commitable = run_status(stdout, index_file, prefix);
|
||||||
|
|
||||||
@ -703,7 +703,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
argc = parse_and_validate_options(argc, argv, builtin_commit_usage);
|
argc = parse_and_validate_options(argc, argv, builtin_commit_usage);
|
||||||
|
|
||||||
index_file = prepare_index(argv, prefix);
|
index_file = prepare_index(argc, argv, prefix);
|
||||||
|
|
||||||
if (!no_verify && run_hook(index_file, "pre-commit", NULL)) {
|
if (!no_verify && run_hook(index_file, "pre-commit", NULL)) {
|
||||||
rollback_index_files();
|
rollback_index_files();
|
||||||
|
2
commit.h
2
commit.h
@ -113,7 +113,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
|
|||||||
|
|
||||||
int in_merge_bases(struct commit *, struct commit **, int);
|
int in_merge_bases(struct commit *, struct commit **, int);
|
||||||
|
|
||||||
extern int interactive_add(void);
|
extern int interactive_add(int argc, const char **argv, const char *prefix);
|
||||||
extern int rerere(void);
|
extern int rerere(void);
|
||||||
|
|
||||||
static inline int single_parent(struct commit *commit)
|
static inline int single_parent(struct commit *commit)
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
|
# command line options
|
||||||
|
my $patch_mode;
|
||||||
|
|
||||||
sub run_cmd_pipe {
|
sub run_cmd_pipe {
|
||||||
if ($^O eq 'MSWin32') {
|
if ($^O eq 'MSWin32') {
|
||||||
my @invalid = grep {m/[":*]/} @_;
|
my @invalid = grep {m/[":*]/} @_;
|
||||||
@ -37,14 +40,13 @@ sub list_untracked {
|
|||||||
chomp $_;
|
chomp $_;
|
||||||
$_;
|
$_;
|
||||||
}
|
}
|
||||||
run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @_);
|
run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $status_fmt = '%12s %12s %s';
|
my $status_fmt = '%12s %12s %s';
|
||||||
my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');
|
my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');
|
||||||
|
|
||||||
# Returns list of hashes, contents of each of which are:
|
# Returns list of hashes, contents of each of which are:
|
||||||
# PRINT: print message
|
|
||||||
# VALUE: pathname
|
# VALUE: pathname
|
||||||
# BINARY: is a binary path
|
# BINARY: is a binary path
|
||||||
# INDEX: is index different from HEAD?
|
# INDEX: is index different from HEAD?
|
||||||
@ -56,9 +58,17 @@ sub list_modified {
|
|||||||
my ($only) = @_;
|
my ($only) = @_;
|
||||||
my (%data, @return);
|
my (%data, @return);
|
||||||
my ($add, $del, $adddel, $file);
|
my ($add, $del, $adddel, $file);
|
||||||
|
my @tracked = ();
|
||||||
|
|
||||||
|
if (@ARGV) {
|
||||||
|
@tracked = map {
|
||||||
|
chomp $_; $_;
|
||||||
|
} run_cmd_pipe(qw(git ls-files --exclude-standard --), @ARGV);
|
||||||
|
return if (!@tracked);
|
||||||
|
}
|
||||||
|
|
||||||
for (run_cmd_pipe(qw(git diff-index --cached
|
for (run_cmd_pipe(qw(git diff-index --cached
|
||||||
--numstat --summary HEAD))) {
|
--numstat --summary HEAD --), @tracked)) {
|
||||||
if (($add, $del, $file) =
|
if (($add, $del, $file) =
|
||||||
/^([-\d]+) ([-\d]+) (.*)/) {
|
/^([-\d]+) ([-\d]+) (.*)/) {
|
||||||
my ($change, $bin);
|
my ($change, $bin);
|
||||||
@ -81,7 +91,7 @@ sub list_modified {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (run_cmd_pipe(qw(git diff-files --numstat --summary))) {
|
for (run_cmd_pipe(qw(git diff-files --numstat --summary --), @tracked)) {
|
||||||
if (($add, $del, $file) =
|
if (($add, $del, $file) =
|
||||||
/^([-\d]+) ([-\d]+) (.*)/) {
|
/^([-\d]+) ([-\d]+) (.*)/) {
|
||||||
if (!exists $data{$file}) {
|
if (!exists $data{$file}) {
|
||||||
@ -122,8 +132,6 @@ sub list_modified {
|
|||||||
}
|
}
|
||||||
push @return, +{
|
push @return, +{
|
||||||
VALUE => $_,
|
VALUE => $_,
|
||||||
PRINT => (sprintf $status_fmt,
|
|
||||||
$it->{INDEX}, $it->{FILE}, $_),
|
|
||||||
%$it,
|
%$it,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -159,10 +167,96 @@ sub find_unique {
|
|||||||
return $found;
|
return $found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# inserts string into trie and updates count for each character
|
||||||
|
sub update_trie {
|
||||||
|
my ($trie, $string) = @_;
|
||||||
|
foreach (split //, $string) {
|
||||||
|
$trie = $trie->{$_} ||= {COUNT => 0};
|
||||||
|
$trie->{COUNT}++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns an array of tuples (prefix, remainder)
|
||||||
|
sub find_unique_prefixes {
|
||||||
|
my @stuff = @_;
|
||||||
|
my @return = ();
|
||||||
|
|
||||||
|
# any single prefix exceeding the soft limit is omitted
|
||||||
|
# if any prefix exceeds the hard limit all are omitted
|
||||||
|
# 0 indicates no limit
|
||||||
|
my $soft_limit = 0;
|
||||||
|
my $hard_limit = 3;
|
||||||
|
|
||||||
|
# build a trie modelling all possible options
|
||||||
|
my %trie;
|
||||||
|
foreach my $print (@stuff) {
|
||||||
|
if ((ref $print) eq 'ARRAY') {
|
||||||
|
$print = $print->[0];
|
||||||
|
}
|
||||||
|
elsif ((ref $print) eq 'HASH') {
|
||||||
|
$print = $print->{VALUE};
|
||||||
|
}
|
||||||
|
update_trie(\%trie, $print);
|
||||||
|
push @return, $print;
|
||||||
|
}
|
||||||
|
|
||||||
|
# use the trie to find the unique prefixes
|
||||||
|
for (my $i = 0; $i < @return; $i++) {
|
||||||
|
my $ret = $return[$i];
|
||||||
|
my @letters = split //, $ret;
|
||||||
|
my %search = %trie;
|
||||||
|
my ($prefix, $remainder);
|
||||||
|
my $j;
|
||||||
|
for ($j = 0; $j < @letters; $j++) {
|
||||||
|
my $letter = $letters[$j];
|
||||||
|
if ($search{$letter}{COUNT} == 1) {
|
||||||
|
$prefix = substr $ret, 0, $j + 1;
|
||||||
|
$remainder = substr $ret, $j + 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
my $prefix = substr $ret, 0, $j;
|
||||||
|
return ()
|
||||||
|
if ($hard_limit && $j + 1 > $hard_limit);
|
||||||
|
}
|
||||||
|
%search = %{$search{$letter}};
|
||||||
|
}
|
||||||
|
if ($soft_limit && $j + 1 > $soft_limit) {
|
||||||
|
$prefix = undef;
|
||||||
|
$remainder = $ret;
|
||||||
|
}
|
||||||
|
$return[$i] = [$prefix, $remainder];
|
||||||
|
}
|
||||||
|
return @return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# filters out prefixes which have special meaning to list_and_choose()
|
||||||
|
sub is_valid_prefix {
|
||||||
|
my $prefix = shift;
|
||||||
|
return (defined $prefix) &&
|
||||||
|
!($prefix =~ /[\s,]/) && # separators
|
||||||
|
!($prefix =~ /^-/) && # deselection
|
||||||
|
!($prefix =~ /^\d+/) && # selection
|
||||||
|
($prefix ne '*') && # "all" wildcard
|
||||||
|
($prefix ne '?'); # prompt help
|
||||||
|
}
|
||||||
|
|
||||||
|
# given a prefix/remainder tuple return a string with the prefix highlighted
|
||||||
|
# for now use square brackets; later might use ANSI colors (underline, bold)
|
||||||
|
sub highlight_prefix {
|
||||||
|
my $prefix = shift;
|
||||||
|
my $remainder = shift;
|
||||||
|
return $remainder unless defined $prefix;
|
||||||
|
return is_valid_prefix($prefix) ?
|
||||||
|
"[$prefix]$remainder" :
|
||||||
|
"$prefix$remainder";
|
||||||
|
}
|
||||||
|
|
||||||
sub list_and_choose {
|
sub list_and_choose {
|
||||||
my ($opts, @stuff) = @_;
|
my ($opts, @stuff) = @_;
|
||||||
my (@chosen, @return);
|
my (@chosen, @return);
|
||||||
my $i;
|
my $i;
|
||||||
|
my @prefixes = find_unique_prefixes(@stuff) unless $opts->{LIST_ONLY};
|
||||||
|
|
||||||
TOPLOOP:
|
TOPLOOP:
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -177,13 +271,21 @@ sub list_and_choose {
|
|||||||
for ($i = 0; $i < @stuff; $i++) {
|
for ($i = 0; $i < @stuff; $i++) {
|
||||||
my $chosen = $chosen[$i] ? '*' : ' ';
|
my $chosen = $chosen[$i] ? '*' : ' ';
|
||||||
my $print = $stuff[$i];
|
my $print = $stuff[$i];
|
||||||
if (ref $print) {
|
my $ref = ref $print;
|
||||||
if ((ref $print) eq 'ARRAY') {
|
my $highlighted = highlight_prefix(@{$prefixes[$i]})
|
||||||
$print = $print->[0];
|
if @prefixes;
|
||||||
|
if ($ref eq 'ARRAY') {
|
||||||
|
$print = $highlighted || $print->[0];
|
||||||
|
}
|
||||||
|
elsif ($ref eq 'HASH') {
|
||||||
|
my $value = $highlighted || $print->{VALUE};
|
||||||
|
$print = sprintf($status_fmt,
|
||||||
|
$print->{INDEX},
|
||||||
|
$print->{FILE},
|
||||||
|
$value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$print = $print->{PRINT};
|
$print = $highlighted || $print;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
printf("%s%2d: %s", $chosen, $i+1, $print);
|
printf("%s%2d: %s", $chosen, $i+1, $print);
|
||||||
if (($opts->{LIST_FLAT}) &&
|
if (($opts->{LIST_FLAT}) &&
|
||||||
@ -217,6 +319,12 @@ sub list_and_choose {
|
|||||||
}
|
}
|
||||||
chomp $line;
|
chomp $line;
|
||||||
last if $line eq '';
|
last if $line eq '';
|
||||||
|
if ($line eq '?') {
|
||||||
|
$opts->{SINGLETON} ?
|
||||||
|
singleton_prompt_help_cmd() :
|
||||||
|
prompt_help_cmd();
|
||||||
|
next TOPLOOP;
|
||||||
|
}
|
||||||
for my $choice (split(/[\s,]+/, $line)) {
|
for my $choice (split(/[\s,]+/, $line)) {
|
||||||
my $choose = 1;
|
my $choose = 1;
|
||||||
my ($bottom, $top);
|
my ($bottom, $top);
|
||||||
@ -252,7 +360,7 @@ sub list_and_choose {
|
|||||||
$chosen[$i] = $choose;
|
$chosen[$i] = $choose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last if ($opts->{IMMEDIATE});
|
last if ($opts->{IMMEDIATE} || $line eq '*');
|
||||||
}
|
}
|
||||||
for ($i = 0; $i < @stuff; $i++) {
|
for ($i = 0; $i < @stuff; $i++) {
|
||||||
if ($chosen[$i]) {
|
if ($chosen[$i]) {
|
||||||
@ -262,6 +370,28 @@ sub list_and_choose {
|
|||||||
return @return;
|
return @return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub singleton_prompt_help_cmd {
|
||||||
|
print <<\EOF ;
|
||||||
|
Prompt help:
|
||||||
|
1 - select a numbered item
|
||||||
|
foo - select item based on unique prefix
|
||||||
|
- (empty) select nothing
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prompt_help_cmd {
|
||||||
|
print <<\EOF ;
|
||||||
|
Prompt help:
|
||||||
|
1 - select a single item
|
||||||
|
3-5 - select a range of items
|
||||||
|
2-3,6-9 - select multiple ranges
|
||||||
|
foo - select item based on unique prefix
|
||||||
|
-... - unselect specified items
|
||||||
|
* - choose all items
|
||||||
|
- (empty) finish selecting
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
sub status_cmd {
|
sub status_cmd {
|
||||||
list_and_choose({ LIST_ONLY => 1, HEADER => $status_head },
|
list_and_choose({ LIST_ONLY => 1, HEADER => $status_head },
|
||||||
list_modified());
|
list_modified());
|
||||||
@ -544,27 +674,36 @@ sub help_patch_cmd {
|
|||||||
print <<\EOF ;
|
print <<\EOF ;
|
||||||
y - stage this hunk
|
y - stage this hunk
|
||||||
n - do not stage this hunk
|
n - do not stage this hunk
|
||||||
a - stage this and all the remaining hunks
|
a - stage this and all the remaining hunks in the file
|
||||||
d - do not stage this hunk nor any of the remaining hunks
|
d - do not stage this hunk nor any of the remaining hunks in the file
|
||||||
j - leave this hunk undecided, see next undecided hunk
|
j - leave this hunk undecided, see next undecided hunk
|
||||||
J - leave this hunk undecided, see next hunk
|
J - leave this hunk undecided, see next hunk
|
||||||
k - leave this hunk undecided, see previous undecided hunk
|
k - leave this hunk undecided, see previous undecided hunk
|
||||||
K - leave this hunk undecided, see previous hunk
|
K - leave this hunk undecided, see previous hunk
|
||||||
s - split the current hunk into smaller hunks
|
s - split the current hunk into smaller hunks
|
||||||
|
? - print help
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
sub patch_update_cmd {
|
sub patch_update_cmd {
|
||||||
my @mods = list_modified('file-only');
|
my @mods = grep { !($_->{BINARY}) } list_modified('file-only');
|
||||||
@mods = grep { !($_->{BINARY}) } @mods;
|
my @them;
|
||||||
return if (!@mods);
|
|
||||||
|
|
||||||
my ($it) = list_and_choose({ PROMPT => 'Patch update',
|
if (!@mods) {
|
||||||
SINGLETON => 1,
|
print STDERR "No changes.\n";
|
||||||
IMMEDIATE => 1,
|
return 0;
|
||||||
|
}
|
||||||
|
if ($patch_mode) {
|
||||||
|
@them = @mods;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@them = list_and_choose({ PROMPT => 'Patch update',
|
||||||
HEADER => $status_head, },
|
HEADER => $status_head, },
|
||||||
@mods);
|
@mods);
|
||||||
patch_update_file($it->{VALUE}) if ($it);
|
}
|
||||||
|
for (@them) {
|
||||||
|
patch_update_file($_->{VALUE});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub patch_update_file {
|
sub patch_update_file {
|
||||||
@ -775,6 +914,20 @@ add untracked - add contents of untracked files to the staged set of changes
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub process_args {
|
||||||
|
return unless @ARGV;
|
||||||
|
my $arg = shift @ARGV;
|
||||||
|
if ($arg eq "--patch") {
|
||||||
|
$patch_mode = 1;
|
||||||
|
$arg = shift @ARGV or die "missing --";
|
||||||
|
die "invalid argument $arg, expecting --"
|
||||||
|
unless $arg eq "--";
|
||||||
|
}
|
||||||
|
elsif ($arg ne "--") {
|
||||||
|
die "invalid argument $arg, expecting --";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sub main_loop {
|
sub main_loop {
|
||||||
my @cmd = ([ 'status', \&status_cmd, ],
|
my @cmd = ([ 'status', \&status_cmd, ],
|
||||||
[ 'update', \&update_cmd, ],
|
[ 'update', \&update_cmd, ],
|
||||||
@ -803,6 +956,12 @@ sub main_loop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_args();
|
||||||
refresh();
|
refresh();
|
||||||
|
if ($patch_mode) {
|
||||||
|
patch_update_cmd();
|
||||||
|
}
|
||||||
|
else {
|
||||||
status_cmd();
|
status_cmd();
|
||||||
main_loop();
|
main_loop();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user