Skip to content

Commit df68408

Browse files
committed
Merge branch 'jc/checkout-from-tree-keep-local-changes' into maint
* jc/checkout-from-tree-keep-local-changes: checkout $tree $path: do not clobber local changes in $path not in $tree
2 parents 634b29d + 0a1283b commit df68408

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
@@ -71,7 +71,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
7171
hashcpy(ce->sha1, sha1);
7272
memcpy(ce->name, base, baselen);
7373
memcpy(ce->name + baselen, pathname, len - baselen);
74-
ce->ce_flags = create_ce_flags(len, 0);
74+
ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
7575
ce->ce_mode = create_ce_mode(mode);
7676
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
7777
return 0;
@@ -228,6 +228,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
228228

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

@@ -266,6 +268,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
266268
state.refresh_cache = 1;
267269
for (pos = 0; pos < active_nr; pos++) {
268270
struct cache_entry *ce = active_cache[pos];
271+
if (source_tree && !(ce->ce_flags & CE_UPDATE))
272+
continue;
269273
if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
270274
if (!ce_stage(ce)) {
271275
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)