diff options
author | Thomas Rast <trast@student.ethz.ch> | 2009-08-15 13:48:30 +0200 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2009-08-15 15:18:05 -0700 |
commit | 4f353658b9c15e9188530fac5ae79d0aa1538e85 (patch) | |
tree | c65622dc13e452b85cb31f54b6d54497e862aafb /git-add--interactive.perl | |
parent | d002ef4d9446b9fe4d0c397131edce58781df2f1 (diff) | |
download | git-4f353658b9c15e9188530fac5ae79d0aa1538e85.tar.gz |
Implement 'git checkout --patch'
This introduces a --patch mode for git-checkout. In the index usage
git checkout --patch -- [files...]
it lets the user discard edits from the <files> at the granularity of
hunks (by selecting hunks from 'git diff' and then reverse applying
them to the worktree).
We also accept a revision argument. In the case
git checkout --patch HEAD -- [files...]
we offer hunks from the difference between HEAD and the worktree, and
reverse applies them to both index and worktree, allowing you to
discard staged changes completely. In the non-HEAD usage
git checkout --patch <revision> -- [files...]
it offers hunks from the difference between the worktree and
<revision>. The chosen hunks are then applied to both index and
worktree.
The application to worktree and index is done "atomically" in the
sense that we first check if the patch applies to the index (it should
always apply to the worktree). If it does not, we give the user a
choice to either abort or apply to the worktree anyway.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'git-add--interactive.perl')
-rwxr-xr-x | git-add--interactive.perl | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/git-add--interactive.perl b/git-add--interactive.perl index d14f48c837..21746d5f28 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -75,6 +75,7 @@ my $patch_mode; my $patch_mode_revision; sub apply_patch; +sub apply_patch_for_checkout_commit; my %patch_modes = ( 'stage' => { @@ -104,6 +105,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}}; @@ -1069,6 +1097,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,6 +1483,16 @@ sub process_args { 'reset_head' : 'reset_nothead'); $arg = shift @ARGV or die "missing --"; } + } 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') { $patch_mode = 'stage'; $arg = shift @ARGV or die "missing --"; |