git-apply--interactive: Refactor patch mode code
This makes some aspects of the 'git add -p' loop configurable (within the code), so that we can later reuse git-add--interactive for other similar tools. Most fields are fairly straightforward, but APPLY gets a subroutine (instead of just a string a la 'apply --cached') so that we can handle 'checkout -p', which will need to atomically apply the patch twice (index and worktree). Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
6517452d7a
commit
8f0bef6df9
@ -73,6 +73,22 @@ sub colored {
|
|||||||
# command line options
|
# command line options
|
||||||
my $patch_mode;
|
my $patch_mode;
|
||||||
|
|
||||||
|
sub apply_patch;
|
||||||
|
|
||||||
|
my %patch_modes = (
|
||||||
|
'stage' => {
|
||||||
|
DIFF => 'diff-files -p',
|
||||||
|
APPLY => sub { apply_patch 'apply --cached', @_; },
|
||||||
|
APPLY_CHECK => 'apply --cached',
|
||||||
|
VERB => 'Stage',
|
||||||
|
TARGET => '',
|
||||||
|
PARTICIPLE => 'staging',
|
||||||
|
FILTER => 'file-only',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
my %patch_mode_flavour = %{$patch_modes{stage}};
|
||||||
|
|
||||||
sub run_cmd_pipe {
|
sub run_cmd_pipe {
|
||||||
if ($^O eq 'MSWin32' || $^O eq 'msys') {
|
if ($^O eq 'MSWin32' || $^O eq 'msys') {
|
||||||
my @invalid = grep {m/[":*]/} @_;
|
my @invalid = grep {m/[":*]/} @_;
|
||||||
@ -613,12 +629,21 @@ sub add_untracked_cmd {
|
|||||||
print "\n";
|
print "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub run_git_apply {
|
||||||
|
my $cmd = shift;
|
||||||
|
my $fh;
|
||||||
|
open $fh, '| git ' . $cmd;
|
||||||
|
print $fh @_;
|
||||||
|
return close $fh;
|
||||||
|
}
|
||||||
|
|
||||||
sub parse_diff {
|
sub parse_diff {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
my @diff = run_cmd_pipe(qw(git diff-files -p --), $path);
|
my @diff_cmd = split(" ", $patch_mode_flavour{DIFF});
|
||||||
|
my @diff = run_cmd_pipe("git", @diff_cmd, "--", $path);
|
||||||
my @colored = ();
|
my @colored = ();
|
||||||
if ($diff_use_color) {
|
if ($diff_use_color) {
|
||||||
@colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);
|
@colored = run_cmd_pipe("git", @diff_cmd, qw(--color --), $path);
|
||||||
}
|
}
|
||||||
my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
|
my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
|
||||||
|
|
||||||
@ -877,6 +902,7 @@ sub edit_hunk_manually {
|
|||||||
or die "failed to open hunk edit file for writing: " . $!;
|
or die "failed to open hunk edit file for writing: " . $!;
|
||||||
print $fh "# Manual hunk edit mode -- see bottom for a quick guide\n";
|
print $fh "# Manual hunk edit mode -- see bottom for a quick guide\n";
|
||||||
print $fh @$oldtext;
|
print $fh @$oldtext;
|
||||||
|
my $participle = $patch_mode_flavour{PARTICIPLE};
|
||||||
print $fh <<EOF;
|
print $fh <<EOF;
|
||||||
# ---
|
# ---
|
||||||
# To remove '-' lines, make them ' ' lines (context).
|
# To remove '-' lines, make them ' ' lines (context).
|
||||||
@ -884,7 +910,7 @@ sub edit_hunk_manually {
|
|||||||
# Lines starting with # will be removed.
|
# Lines starting with # will be removed.
|
||||||
#
|
#
|
||||||
# If the patch applies cleanly, the edited hunk will immediately be
|
# If the patch applies cleanly, the edited hunk will immediately be
|
||||||
# marked for staging. If it does not apply cleanly, you will be given
|
# marked for $participle. If it does not apply cleanly, you will be given
|
||||||
# an opportunity to edit again. If all lines of the hunk are removed,
|
# an opportunity to edit again. If all lines of the hunk are removed,
|
||||||
# then the edit is aborted and the hunk is left unchanged.
|
# then the edit is aborted and the hunk is left unchanged.
|
||||||
EOF
|
EOF
|
||||||
@ -918,11 +944,8 @@ EOF
|
|||||||
|
|
||||||
sub diff_applies {
|
sub diff_applies {
|
||||||
my $fh;
|
my $fh;
|
||||||
open $fh, '| git apply --recount --cached --check';
|
return run_git_apply($patch_mode_flavour{APPLY_CHECK} . ' --recount --check',
|
||||||
for my $h (@_) {
|
map { @{$_->{TEXT}} } @_);
|
||||||
print $fh @{$h->{TEXT}};
|
|
||||||
}
|
|
||||||
return close $fh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _restore_terminal_and_die {
|
sub _restore_terminal_and_die {
|
||||||
@ -988,12 +1011,14 @@ sub edit_hunk_loop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub help_patch_cmd {
|
sub help_patch_cmd {
|
||||||
print colored $help_color, <<\EOF ;
|
my $verb = lc $patch_mode_flavour{VERB};
|
||||||
y - stage this hunk
|
my $target = $patch_mode_flavour{TARGET};
|
||||||
n - do not stage this hunk
|
print colored $help_color, <<EOF ;
|
||||||
q - quit, do not stage this hunk nor any of the remaining ones
|
y - $verb this hunk$target
|
||||||
a - stage this and all the remaining hunks in the file
|
n - do not $verb this hunk$target
|
||||||
d - do not stage this hunk nor any of the remaining hunks in the file
|
q - quit, do not $verb this hunk nor any of the remaining ones
|
||||||
|
a - $verb this and all the remaining hunks in the file
|
||||||
|
d - do not $verb this hunk nor any of the remaining hunks in the file
|
||||||
g - select a hunk to go to
|
g - select a hunk to go to
|
||||||
/ - search for a hunk matching the given regex
|
/ - search for a hunk matching the given regex
|
||||||
j - leave this hunk undecided, see next undecided hunk
|
j - leave this hunk undecided, see next undecided hunk
|
||||||
@ -1006,8 +1031,17 @@ e - manually edit the current hunk
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub apply_patch {
|
||||||
|
my $cmd = shift;
|
||||||
|
my $ret = run_git_apply $cmd . ' --recount', @_;
|
||||||
|
if (!$ret) {
|
||||||
|
print STDERR @_;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
sub patch_update_cmd {
|
sub patch_update_cmd {
|
||||||
my @all_mods = list_modified('file-only');
|
my @all_mods = list_modified($patch_mode_flavour{FILTER});
|
||||||
my @mods = grep { !($_->{BINARY}) } @all_mods;
|
my @mods = grep { !($_->{BINARY}) } @all_mods;
|
||||||
my @them;
|
my @them;
|
||||||
|
|
||||||
@ -1138,8 +1172,9 @@ sub patch_update_file {
|
|||||||
for (@{$hunk[$ix]{DISPLAY}}) {
|
for (@{$hunk[$ix]{DISPLAY}}) {
|
||||||
print;
|
print;
|
||||||
}
|
}
|
||||||
print colored $prompt_color, 'Stage ',
|
print colored $prompt_color, $patch_mode_flavour{VERB},
|
||||||
($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'),
|
($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' : ' this hunk'),
|
||||||
|
$patch_mode_flavour{TARGET},
|
||||||
" [y,n,q,a,d,/$other,?]? ";
|
" [y,n,q,a,d,/$other,?]? ";
|
||||||
my $line = prompt_single_character;
|
my $line = prompt_single_character;
|
||||||
if ($line) {
|
if ($line) {
|
||||||
@ -1313,16 +1348,9 @@ sub patch_update_file {
|
|||||||
|
|
||||||
if (@result) {
|
if (@result) {
|
||||||
my $fh;
|
my $fh;
|
||||||
|
my @patch = (@{$head->{TEXT}}, @result);
|
||||||
open $fh, '| git apply --cached --recount';
|
my $apply_routine = $patch_mode_flavour{APPLY};
|
||||||
for (@{$head->{TEXT}}, @result) {
|
&$apply_routine(@patch);
|
||||||
print $fh $_;
|
|
||||||
}
|
|
||||||
if (!close $fh) {
|
|
||||||
for (@{$head->{TEXT}}, @result) {
|
|
||||||
print STDERR $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user