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>
Thomas Rast committed
Aug 13, 2009 at 14:29 UTC
8f0bef6df91c48d79f982bdb55f784ce445ba5b2
1 file changed
+55
-27
git-add--interactive.perl
+55
-27
@@ -73,6 +73,22 @@ sub colored {
73
# command line options
74
my $patch_mode;
75
76
+sub apply_patch;
77
+
78
+my %patch_modes = (
79
+ 'stage' => {
80
+ DIFF => 'diff-files -p',
81
+ APPLY => sub { apply_patch 'apply --cached', @_; },
82
+ APPLY_CHECK => 'apply --cached',
83
+ VERB => 'Stage',
84
+ TARGET => '',
85
+ PARTICIPLE => 'staging',
86
+ FILTER => 'file-only',
87
+ },
88
+);
89
+
90
+my %patch_mode_flavour = %{$patch_modes{stage}};
91
+
92
sub run_cmd_pipe {
93
if ($^O eq 'MSWin32' || $^O eq 'msys') {
94
my @invalid = grep {m/[":*]/} @_;
@@ -613,12 +629,21 @@ sub add_untracked_cmd {
629
print "\n";
630
}
631
632
+sub run_git_apply {
633
+ my $cmd = shift;
634
+ my $fh;
635
+ open $fh, '| git ' . $cmd;
636
+ print $fh @_;
637
+ return close $fh;
638
+}
639
+
640
sub parse_diff {
641
my ($path) = @_;
618
- my @diff = run_cmd_pipe(qw(git diff-files -p --), $path);
642
+ my @diff_cmd = split(" ", $patch_mode_flavour{DIFF});
643
+ my @diff = run_cmd_pipe("git", @diff_cmd, "--", $path);
644
my @colored = ();
645
if ($diff_use_color) {
621
- @colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);
646
+ @colored = run_cmd_pipe("git", @diff_cmd, qw(--color --), $path);
647
}
648
my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
649
@@ -877,6 +902,7 @@ sub edit_hunk_manually {
902
or die "failed to open hunk edit file for writing: " . $!;
903
print $fh "# Manual hunk edit mode -- see bottom for a quick guide\n";
904
print $fh @$oldtext;
905
+ my $participle = $patch_mode_flavour{PARTICIPLE};
906
print $fh <<EOF;
907
# ---
908
# To remove '-' lines, make them ' ' lines (context).
@@ -884,7 +910,7 @@ sub edit_hunk_manually {
910
# Lines starting with # will be removed.
911
#
912
# If the patch applies cleanly, the edited hunk will immediately be
887
-# marked for staging. If it does not apply cleanly, you will be given
913
+# marked for $participle. If it does not apply cleanly, you will be given
914
# an opportunity to edit again. If all lines of the hunk are removed,
915
# then the edit is aborted and the hunk is left unchanged.
916
EOF
@@ -918,11 +944,8 @@ EOF
944
945
sub diff_applies {
946
my $fh;
921
- open $fh, '| git apply --recount --cached --check';
922
- for my $h (@_) {
923
- print $fh @{$h->{TEXT}};
924
- }
925
- return close $fh;
947
+ return run_git_apply($patch_mode_flavour{APPLY_CHECK} . ' --recount --check',
948
+ map { @{$_->{TEXT}} } @_);
949
}
950
951
sub _restore_terminal_and_die {
@@ -988,12 +1011,14 @@ sub edit_hunk_loop {
1011
}
1012
1013
sub help_patch_cmd {
991
- print colored $help_color, <<\EOF ;
992
-y - stage this hunk
993
-n - do not stage this hunk
994
-q - quit, do not stage this hunk nor any of the remaining ones
995
-a - stage this and all the remaining hunks in the file
996
-d - do not stage this hunk nor any of the remaining hunks in the file
1014
+ my $verb = lc $patch_mode_flavour{VERB};
1015
+ my $target = $patch_mode_flavour{TARGET};
1016
+ print colored $help_color, <<EOF ;
1017
+y - $verb this hunk$target
1018
+n - do not $verb this hunk$target
1019
+q - quit, do not $verb this hunk nor any of the remaining ones
1020
+a - $verb this and all the remaining hunks in the file
1021
+d - do not $verb this hunk nor any of the remaining hunks in the file
1022
g - select a hunk to go to
1023
/ - search for a hunk matching the given regex
1024
j - leave this hunk undecided, see next undecided hunk
@@ -1006,8 +1031,17 @@ e - manually edit the current hunk
1031
EOF
1032
}
1033
1034
+sub apply_patch {
1035
+ my $cmd = shift;
1036
+ my $ret = run_git_apply $cmd . ' --recount', @_;
1037
+ if (!$ret) {
1038
+ print STDERR @_;
1039
+ }
1040
+ return $ret;
1041
+}
1042
+
1043
sub patch_update_cmd {
1010
- my @all_mods = list_modified('file-only');
1044
+ my @all_mods = list_modified($patch_mode_flavour{FILTER});
1045
my @mods = grep { !($_->{BINARY}) } @all_mods;
1046
my @them;
1047
@@ -1138,8 +1172,9 @@ sub patch_update_file {
1172
for (@{$hunk[$ix]{DISPLAY}}) {
1173
print;
1174
}
1141
- print colored $prompt_color, 'Stage ',
1142
- ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'),
1175
+ print colored $prompt_color, $patch_mode_flavour{VERB},
1176
+ ($hunk[$ix]{TYPE} eq 'mode' ? ' mode change' : ' this hunk'),
1177
+ $patch_mode_flavour{TARGET},
1178
" [y,n,q,a,d,/$other,?]? ";
1179
my $line = prompt_single_character;
1180
if ($line) {
@@ -1313,16 +1348,9 @@ sub patch_update_file {
1348
1349
if (@result) {
1350
my $fh;
1316
-
1317
- open $fh, '| git apply --cached --recount';
1318
- for (@{$head->{TEXT}}, @result) {
1319
- print $fh $_;
1320
- }
1321
- if (!close $fh) {
1322
- for (@{$head->{TEXT}}, @result) {
1323
- print STDERR $_;
1324
- }
1325
- }
1351
+ my @patch = (@{$head->{TEXT}}, @result);
1352
+ my $apply_routine = $patch_mode_flavour{APPLY};
1353
+ &$apply_routine(@patch);
1354
refresh();
1355
}
1356