Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 894ccf4

Browse files
authored
Merge pull request libgit2#4535 from libgit2/ethomson/checkout_typechange_with_index_and_wd
checkout: when examining index (instead of workdir), also examine mode
2 parents afc5124 + 4e4771d commit 894ccf4

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

src/checkout.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,23 @@ static bool checkout_is_workdir_modified(
205205
return rval;
206206
}
207207

208-
/* Look at the cache to decide if the workdir is modified. If not,
209-
* we can simply compare the oid in the cache to the baseitem instead
210-
* of hashing the file. If so, we allow the checkout to proceed if the
211-
* oid is identical (ie, the staged item is what we're trying to check
212-
* out.)
208+
/*
209+
* Look at the cache to decide if the workdir is modified: if the
210+
* cache contents match the workdir contents, then we do not need
211+
* to examine the working directory directly, instead we can
212+
* examine the cache to see if _it_ has been modified. This allows
213+
* us to avoid touching the disk.
213214
*/
214-
if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
215-
if (git_index_time_eq(&wditem->mtime, &ie->mtime) &&
216-
wditem->file_size == ie->file_size &&
217-
!is_file_mode_changed(wditem->mode, ie->mode))
218-
return !is_workdir_base_or_new(&ie->id, baseitem, newitem);
215+
ie = git_index_get_bypath(data->index, wditem->path, 0);
216+
217+
if (ie != NULL &&
218+
git_index_time_eq(&wditem->mtime, &ie->mtime) &&
219+
wditem->file_size == ie->file_size &&
220+
!is_file_mode_changed(wditem->mode, ie->mode)) {
221+
222+
/* The workdir is modified iff the index entry is modified */
223+
return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
224+
is_file_mode_changed(baseitem->mode, ie->mode);
219225
}
220226

221227
/* depending on where base is coming from, we may or may not know

tests/checkout/head.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,48 @@ void test_checkout_head__do_remove_tracked_subdir(void)
136136
cl_assert(!git_path_isfile("testrepo/subdir/tracked-file"));
137137
cl_assert(git_path_isfile("testrepo/subdir/untracked-file"));
138138
}
139+
140+
void test_checkout_head__typechange_workdir(void)
141+
{
142+
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
143+
git_object *target;
144+
struct stat st;
145+
146+
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
147+
148+
cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
149+
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
150+
151+
cl_must_pass(p_chmod("testrepo/new.txt", 0755));
152+
cl_git_pass(git_checkout_head(g_repo, &opts));
153+
154+
cl_git_pass(p_stat("testrepo/new.txt", &st));
155+
cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
156+
157+
git_object_free(target);
158+
}
159+
160+
void test_checkout_head__typechange_index_and_workdir(void)
161+
{
162+
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
163+
git_object *target;
164+
git_index *index;
165+
struct stat st;
166+
167+
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
168+
169+
cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
170+
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
171+
172+
cl_must_pass(p_chmod("testrepo/new.txt", 0755));
173+
cl_git_pass(git_repository_index(&index, g_repo));
174+
cl_git_pass(git_index_add_bypath(index, "new.txt"));
175+
cl_git_pass(git_index_write(index));
176+
cl_git_pass(git_checkout_head(g_repo, &opts));
177+
178+
cl_git_pass(p_stat("testrepo/new.txt", &st));
179+
cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
180+
181+
git_object_free(target);
182+
git_index_free(index);
183+
}

0 commit comments

Comments
 (0)