Code

Introduce commit notes
[git.git] / git-add--interactive.perl
index d14f48c8379cb287e2e1bbe9c8fb7946e6b160fe..392efb913f7c2ff13bbbb46e4414325b71e07676 100755 (executable)
@@ -75,6 +75,8 @@ my $patch_mode;
 my $patch_mode_revision;
 
 sub apply_patch;
+sub apply_patch_for_checkout_commit;
+sub apply_patch_for_stash;
 
 my %patch_modes = (
        'stage' => {
@@ -86,6 +88,15 @@ my %patch_modes = (
                PARTICIPLE => 'staging',
                FILTER => 'file-only',
        },
+       'stash' => {
+               DIFF => 'diff-index -p HEAD',
+               APPLY => sub { apply_patch 'apply --cached', @_; },
+               APPLY_CHECK => 'apply --cached',
+               VERB => 'Stash',
+               TARGET => '',
+               PARTICIPLE => 'stashing',
+               FILTER => undef,
+       },
        'reset_head' => {
                DIFF => 'diff-index -p --cached',
                APPLY => sub { apply_patch 'apply -R --cached', @_; },
@@ -104,6 +115,33 @@ my %patch_modes = (
                PARTICIPLE => 'applying',
                FILTER => 'index-only',
        },
+       'checkout_index' => {
+               DIFF => 'diff-files -p',
+               APPLY => sub { apply_patch 'apply -R', @_; },
+               APPLY_CHECK => 'apply -R',
+               VERB => 'Discard',
+               TARGET => ' from worktree',
+               PARTICIPLE => 'discarding',
+               FILTER => 'file-only',
+       },
+       'checkout_head' => {
+               DIFF => 'diff-index -p',
+               APPLY => sub { apply_patch_for_checkout_commit '-R', @_ },
+               APPLY_CHECK => 'apply -R',
+               VERB => 'Discard',
+               TARGET => ' from index and worktree',
+               PARTICIPLE => 'discarding',
+               FILTER => undef,
+       },
+       'checkout_nothead' => {
+               DIFF => 'diff-index -R -p',
+               APPLY => sub { apply_patch_for_checkout_commit '', @_ },
+               APPLY_CHECK => 'apply',
+               VERB => 'Apply',
+               TARGET => ' to index and worktree',
+               PARTICIPLE => 'applying',
+               FILTER => undef,
+       },
 );
 
 my %patch_mode_flavour = %{$patch_modes{stage}};
@@ -895,6 +933,10 @@ sub coalesce_overlapping_hunks {
        my ($last_o_ctx, $last_was_dirty);
 
        for (grep { $_->{USE} } @in) {
+               if ($_->{TYPE} ne 'hunk') {
+                       push @out, $_;
+                       next;
+               }
                my $text = $_->{TEXT};
                my ($o_ofs) = parse_hunk_header($text->[0]);
                if (defined $last_o_ctx &&
@@ -1069,6 +1111,29 @@ sub apply_patch {
        return $ret;
 }
 
+sub apply_patch_for_checkout_commit {
+       my $reverse = shift;
+       my $applies_index = run_git_apply 'apply '.$reverse.' --cached --recount --check', @_;
+       my $applies_worktree = run_git_apply 'apply '.$reverse.' --recount --check', @_;
+
+       if ($applies_worktree && $applies_index) {
+               run_git_apply 'apply '.$reverse.' --cached --recount', @_;
+               run_git_apply 'apply '.$reverse.' --recount', @_;
+               return 1;
+       } elsif (!$applies_index) {
+               print colored $error_color, "The selected hunks do not apply to the index!\n";
+               if (prompt_yesno "Apply them to the worktree anyway? ") {
+                       return run_git_apply 'apply '.$reverse.' --recount', @_;
+               } else {
+                       print colored $error_color, "Nothing was applied.\n";
+                       return 0;
+               }
+       } else {
+               print STDERR @_;
+               return 0;
+       }
+}
+
 sub patch_update_cmd {
        my @all_mods = list_modified($patch_mode_flavour{FILTER});
        my @mods = grep { !($_->{BINARY}) } @all_mods;
@@ -1432,8 +1497,18 @@ sub process_args {
                                                       'reset_head' : 'reset_nothead');
                                        $arg = shift @ARGV or die "missing --";
                                }
-                       } elsif ($1 eq 'stage') {
-                               $patch_mode = 'stage';
+                       } elsif ($1 eq 'checkout') {
+                               $arg = shift @ARGV or die "missing --";
+                               if ($arg eq '--') {
+                                       $patch_mode = 'checkout_index';
+                               } else {
+                                       $patch_mode_revision = $arg;
+                                       $patch_mode = ($arg eq 'HEAD' ?
+                                                      'checkout_head' : 'checkout_nothead');
+                                       $arg = shift @ARGV or die "missing --";
+                               }
+                       } elsif ($1 eq 'stage' or $1 eq 'stash') {
+                               $patch_mode = $1;
                                $arg = shift @ARGV or die "missing --";
                        } else {
                                die "unknown --patch mode: $1";