2009-08-15 11:48:30 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='git checkout --patch'
|
|
|
|
|
2024-04-22 22:54:05 +00:00
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
2009-08-15 11:48:30 +00:00
|
|
|
. ./lib-patch-mode.sh
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'setup' '
|
2009-08-15 11:48:30 +00:00
|
|
|
mkdir dir &&
|
|
|
|
echo parent > dir/foo &&
|
|
|
|
echo dummy > bar &&
|
|
|
|
git add bar dir/foo &&
|
|
|
|
git commit -m initial &&
|
|
|
|
test_tick &&
|
|
|
|
test_commit second dir/foo head &&
|
|
|
|
set_and_save_state bar bar_work bar_index &&
|
|
|
|
save_head
|
|
|
|
'
|
|
|
|
|
|
|
|
# note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'saying "n" does nothing' '
|
2009-08-15 11:48:30 +00:00
|
|
|
set_and_save_state dir/foo work head &&
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines n n | git checkout -p &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_saved_state dir/foo
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'git checkout -p' '
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines n y | git checkout -p &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo head head
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'git checkout -p with staged changes' '
|
2010-10-31 01:46:54 +00:00
|
|
|
set_state dir/foo work index &&
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines n y | git checkout -p &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo index index
|
|
|
|
'
|
|
|
|
|
add-patch: classify '@' as a synonym for 'HEAD'
Currently, (restore, checkout, reset) commands correctly take '@' as a
synonym for 'HEAD'. However, in patch mode different prompts/messages
are given on command line due to patch mode machinery not considering
'@' to be a synonym for 'HEAD' due to literal string comparison with
the word 'HEAD', and therefore assigning patch_mode_($command)_nothead
and triggering reverse mode (-R in diff-index). The NEEDSWORK comment
suggested comparing commit objects to get around this. However, doing
so would also take a non-checked out branch pointing to the same commit
as HEAD, as HEAD. This would cause confusion to the user.
Therefore, after parsing '@', replace it with 'HEAD' as reasonably
early as possible. This also solves another problem of disparity
between 'git checkout HEAD' and 'git checkout @' (latter detaches at
the HEAD commit and the former does not).
Trade-offs:
- Some of the errors would show the revision argument as 'HEAD' when
given '@'. This should be fine, as most users who probably use '@'
would be aware that it is a shortcut for 'HEAD' and most probably
used to use 'HEAD'. There is also relevant documentation in
'gitrevisions' manpage about '@' being the shortcut for 'HEAD'. Also,
the simplicity of the solution far outweighs this cost.
- Consider '@' as a shortcut for 'HEAD' even if 'refs/heads/@' exists
at a different commit. Naming a branch '@' is an obvious foot-gun and
many existing commands already take '@' for 'HEAD' even if
'refs/heads/@' exists at a different commit or does not exist at all
(e.g. 'git log @', 'git push origin @' etc.). Therefore this is an
existing assumption and should not be a problem.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-02-13 00:05:29 +00:00
|
|
|
for opt in "HEAD" "@"
|
|
|
|
do
|
|
|
|
test_expect_success "git checkout -p $opt with NO staged changes: abort" '
|
|
|
|
set_and_save_state dir/foo work head &&
|
|
|
|
test_write_lines n y n | git checkout -p $opt >output &&
|
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_saved_state dir/foo &&
|
|
|
|
test_grep "Discard" output
|
|
|
|
'
|
2009-08-15 11:48:30 +00:00
|
|
|
|
add-patch: classify '@' as a synonym for 'HEAD'
Currently, (restore, checkout, reset) commands correctly take '@' as a
synonym for 'HEAD'. However, in patch mode different prompts/messages
are given on command line due to patch mode machinery not considering
'@' to be a synonym for 'HEAD' due to literal string comparison with
the word 'HEAD', and therefore assigning patch_mode_($command)_nothead
and triggering reverse mode (-R in diff-index). The NEEDSWORK comment
suggested comparing commit objects to get around this. However, doing
so would also take a non-checked out branch pointing to the same commit
as HEAD, as HEAD. This would cause confusion to the user.
Therefore, after parsing '@', replace it with 'HEAD' as reasonably
early as possible. This also solves another problem of disparity
between 'git checkout HEAD' and 'git checkout @' (latter detaches at
the HEAD commit and the former does not).
Trade-offs:
- Some of the errors would show the revision argument as 'HEAD' when
given '@'. This should be fine, as most users who probably use '@'
would be aware that it is a shortcut for 'HEAD' and most probably
used to use 'HEAD'. There is also relevant documentation in
'gitrevisions' manpage about '@' being the shortcut for 'HEAD'. Also,
the simplicity of the solution far outweighs this cost.
- Consider '@' as a shortcut for 'HEAD' even if 'refs/heads/@' exists
at a different commit. Naming a branch '@' is an obvious foot-gun and
many existing commands already take '@' for 'HEAD' even if
'refs/heads/@' exists at a different commit or does not exist at all
(e.g. 'git log @', 'git push origin @' etc.). Therefore this is an
existing assumption and should not be a problem.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-02-13 00:05:29 +00:00
|
|
|
test_expect_success "git checkout -p $opt with NO staged changes: apply" '
|
|
|
|
test_write_lines n y y | git checkout -p $opt >output &&
|
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo head head &&
|
|
|
|
test_grep "Discard" output
|
|
|
|
'
|
2009-08-15 11:48:30 +00:00
|
|
|
|
add-patch: classify '@' as a synonym for 'HEAD'
Currently, (restore, checkout, reset) commands correctly take '@' as a
synonym for 'HEAD'. However, in patch mode different prompts/messages
are given on command line due to patch mode machinery not considering
'@' to be a synonym for 'HEAD' due to literal string comparison with
the word 'HEAD', and therefore assigning patch_mode_($command)_nothead
and triggering reverse mode (-R in diff-index). The NEEDSWORK comment
suggested comparing commit objects to get around this. However, doing
so would also take a non-checked out branch pointing to the same commit
as HEAD, as HEAD. This would cause confusion to the user.
Therefore, after parsing '@', replace it with 'HEAD' as reasonably
early as possible. This also solves another problem of disparity
between 'git checkout HEAD' and 'git checkout @' (latter detaches at
the HEAD commit and the former does not).
Trade-offs:
- Some of the errors would show the revision argument as 'HEAD' when
given '@'. This should be fine, as most users who probably use '@'
would be aware that it is a shortcut for 'HEAD' and most probably
used to use 'HEAD'. There is also relevant documentation in
'gitrevisions' manpage about '@' being the shortcut for 'HEAD'. Also,
the simplicity of the solution far outweighs this cost.
- Consider '@' as a shortcut for 'HEAD' even if 'refs/heads/@' exists
at a different commit. Naming a branch '@' is an obvious foot-gun and
many existing commands already take '@' for 'HEAD' even if
'refs/heads/@' exists at a different commit or does not exist at all
(e.g. 'git log @', 'git push origin @' etc.). Therefore this is an
existing assumption and should not be a problem.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-02-13 00:05:29 +00:00
|
|
|
test_expect_success "git checkout -p $opt with change already staged" '
|
|
|
|
set_state dir/foo index index &&
|
|
|
|
# the third n is to get out in case it mistakenly does not apply
|
|
|
|
test_write_lines n y n | git checkout -p $opt >output &&
|
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo head head &&
|
|
|
|
test_grep "Discard" output
|
|
|
|
'
|
|
|
|
done
|
2009-08-15 11:48:30 +00:00
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'git checkout -p HEAD^...' '
|
2020-10-07 07:56:15 +00:00
|
|
|
# the third n is to get out in case it mistakenly does not apply
|
|
|
|
test_write_lines n y n | git checkout -p HEAD^... &&
|
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo parent parent
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'git checkout -p HEAD^' '
|
2009-08-15 11:48:30 +00:00
|
|
|
# the third n is to get out in case it mistakenly does not apply
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines n y n | git checkout -p HEAD^ &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo parent parent
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'git checkout -p handles deletion' '
|
add-interactive: fix bogus diff header line ordering
When we look at a patch for adding hunks interactively, we
first split it into a header and a list of hunks. Some of
the header lines, such as mode changes and deletion, however,
become their own selectable hunks. Later when we reassemble
the patch, we simply concatenate the header and the selected
hunks. This leads to patches like this:
diff --git a/file b/file
index d95f3ad..0000000
--- a/file
+++ /dev/null
deleted file mode 100644
@@ -1 +0,0 @@
-content
Notice how the deletion comes _after_ the ---/+++ lines,
when it should come before.
In many cases, we can get away with this as git-apply
accepts the slightly bogus input. However, in the specific
case of a deletion line that is being applied via "apply
-R", this malformed patch triggers an assert in git-apply.
This comes up when discarding a deletion via "git checkout
-p".
Rather than try to make git-apply accept our odd input,
let's just reassemble the patch in the correct order.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 01:05:44 +00:00
|
|
|
set_state dir/foo work index &&
|
|
|
|
rm dir/foo &&
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines n y | git checkout -p &&
|
add-interactive: fix bogus diff header line ordering
When we look at a patch for adding hunks interactively, we
first split it into a header and a list of hunks. Some of
the header lines, such as mode changes and deletion, however,
become their own selectable hunks. Later when we reassemble
the patch, we simply concatenate the header and the selected
hunks. This leads to patches like this:
diff --git a/file b/file
index d95f3ad..0000000
--- a/file
+++ /dev/null
deleted file mode 100644
@@ -1 +0,0 @@
-content
Notice how the deletion comes _after_ the ---/+++ lines,
when it should come before.
In many cases, we can get away with this as git-apply
accepts the slightly bogus input. However, in the specific
case of a deletion line that is being applied via "apply
-R", this malformed patch triggers an assert in git-apply.
This comes up when discarding a deletion via "git checkout
-p".
Rather than try to make git-apply accept our odd input,
let's just reassemble the patch in the correct order.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 01:05:44 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo index index
|
|
|
|
'
|
|
|
|
|
2009-08-15 11:48:30 +00:00
|
|
|
# The idea in the rest is that bar sorts first, so we always say 'y'
|
|
|
|
# first and if the path limiter fails it'll apply to bar instead of
|
|
|
|
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
|
|
|
|
# the failure case (and thus get out of the loop).
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'path limiting works: dir' '
|
2009-08-15 11:48:30 +00:00
|
|
|
set_state dir/foo work head &&
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines y n | git checkout -p dir &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo head head
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'path limiting works: -- dir' '
|
2009-08-15 11:48:30 +00:00
|
|
|
set_state dir/foo work head &&
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines y n | git checkout -p -- dir &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo head head
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'path limiting works: HEAD^ -- dir' '
|
2009-08-15 11:48:30 +00:00
|
|
|
# the third n is to get out in case it mistakenly does not apply
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines y n n | git checkout -p HEAD^ -- dir &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo parent parent
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'path limiting works: foo inside dir' '
|
2009-08-15 11:48:30 +00:00
|
|
|
set_state dir/foo work head &&
|
|
|
|
# the third n is to get out in case it mistakenly does not apply
|
2018-07-02 00:23:42 +00:00
|
|
|
test_write_lines y n n | (cd dir && git checkout -p foo) &&
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_state bar &&
|
|
|
|
verify_state dir/foo head head
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'none of this moved HEAD' '
|
2009-08-15 11:48:30 +00:00
|
|
|
verify_saved_head
|
|
|
|
'
|
|
|
|
|
2021-11-30 14:14:14 +00:00
|
|
|
test_expect_success 'empty tree can be handled' '
|
2020-12-19 14:55:59 +00:00
|
|
|
test_when_finished "git reset --hard" &&
|
|
|
|
git checkout -p $(test_oid empty_tree) --
|
|
|
|
'
|
|
|
|
|
2009-08-15 11:48:30 +00:00
|
|
|
test_done
|