Skip to content

Commit 66d2c22

Browse files
committed
Merge branch 'jc/checkout-from-tree-keep-local-changes'
* jc/checkout-from-tree-keep-local-changes: checkout $tree $path: do not clobber local changes in $path not in $tree
2 parents a9af6c4 + 0a1283b commit 66d2c22

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

builtin/checkout.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
7272
hashcpy(ce->sha1, sha1);
7373
memcpy(ce->name, base, baselen);
7474
memcpy(ce->name + baselen, pathname, len - baselen);
75-
ce->ce_flags = create_ce_flags(len, 0);
75+
ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
7676
ce->ce_mode = create_ce_mode(mode);
7777
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
7878
return 0;
@@ -229,6 +229,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
229229

230230
for (pos = 0; pos < active_nr; pos++) {
231231
struct cache_entry *ce = active_cache[pos];
232+
if (source_tree && !(ce->ce_flags & CE_UPDATE))
233+
continue;
232234
match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
233235
}
234236

@@ -267,6 +269,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
267269
state.refresh_cache = 1;
268270
for (pos = 0; pos < active_nr; pos++) {
269271
struct cache_entry *ce = active_cache[pos];
272+
if (source_tree && !(ce->ce_flags & CE_UPDATE))
273+
continue;
270274
if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
271275
if (!ce_stage(ce)) {
272276
errs |= checkout_entry(ce, &state, NULL);

t/t2022-checkout-paths.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/sh
2+
3+
test_description='checkout $tree -- $paths'
4+
. ./test-lib.sh
5+
6+
test_expect_success setup '
7+
mkdir dir &&
8+
>dir/master &&
9+
echo common >dir/common &&
10+
git add dir/master dir/common &&
11+
test_tick && git commit -m "master has dir/master" &&
12+
git checkout -b next &&
13+
git mv dir/master dir/next0 &&
14+
echo next >dir/next1 &&
15+
git add dir &&
16+
test_tick && git commit -m "next has dir/next but not dir/master"
17+
'
18+
19+
test_expect_success 'checking out paths out of a tree does not clobber unrelated paths' '
20+
git checkout next &&
21+
git reset --hard &&
22+
rm dir/next0 &&
23+
cat dir/common >expect.common &&
24+
echo modified >expect.next1 &&
25+
cat expect.next1 >dir/next1 &&
26+
echo untracked >expect.next2 &&
27+
cat expect.next2 >dir/next2 &&
28+
29+
git checkout master dir &&
30+
31+
test_cmp expect.common dir/common &&
32+
test_path_is_file dir/master &&
33+
git diff --exit-code master dir/master &&
34+
35+
test_path_is_missing dir/next0 &&
36+
test_cmp expect.next1 dir/next1 &&
37+
test_path_is_file dir/next2 &&
38+
test_must_fail git ls-files --error-unmatch dir/next2 &&
39+
test_cmp expect.next2 dir/next2
40+
'
41+
42+
test_done

0 commit comments

Comments
 (0)