summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-02-18 16:10:33 +0000
committerPatrick Steinhardt <ps@pks.im>2018-03-10 17:45:25 +0000
commit3983fc1dc4785747ca3785ba1ba0d541860ce768 (patch)
tree9e93196a474e5719912333f9730222e69368ffa0
parente74e05ed1d65a07d20b465888029c5aaac0952d5 (diff)
downloadlibgit2-3983fc1dc4785747ca3785ba1ba0d541860ce768.tar.gz
checkout: take mode into account when comparing index to baseline
When checking out a file, we determine whether the baseline (what we expect to be in the working directory) actually matches the contents of the working directory. This is safe behavior to prevent us from overwriting changes in the working directory. We look at the index to optimize this test: if we know that the index matches the working directory, then we can simply look at the index data compared to the baseline. We have historically compared the baseline to the index entry by oid. However, we must also compare the mode of the two items to ensure that they are identical. Otherwise, we will refuse to update the working directory for a mode change.
-rw-r--r--src/checkout.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 105d6e324..cb9a7b3a9 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -205,17 +205,23 @@ static bool checkout_is_workdir_modified(
return rval;
}
- /* Look at the cache to decide if the workdir is modified. If not,
- * we can simply compare the oid in the cache to the baseitem instead
- * of hashing the file. If so, we allow the checkout to proceed if the
- * oid is identical (ie, the staged item is what we're trying to check
- * out.)
+ /*
+ * Look at the cache to decide if the workdir is modified: if the
+ * cache contents match the workdir contents, then we do not need
+ * to examine the working directory directly, instead we can
+ * examine the cache to see if _it_ has been modified. This allows
+ * us to avoid touching the disk.
*/
- if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
- if (git_index_time_eq(&wditem->mtime, &ie->mtime) &&
- wditem->file_size == ie->file_size &&
- !is_file_mode_changed(wditem->mode, ie->mode))
- return !is_workdir_base_or_new(&ie->id, baseitem, newitem);
+ ie = git_index_get_bypath(data->index, wditem->path, 0);
+
+ if (ie != NULL &&
+ git_index_time_eq(&wditem->mtime, &ie->mtime) &&
+ wditem->file_size == ie->file_size &&
+ !is_file_mode_changed(wditem->mode, ie->mode)) {
+
+ /* The workdir is modified iff the index entry is modified */
+ return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
+ is_file_mode_changed(baseitem->mode, ie->mode);
}
/* depending on where base is coming from, we may or may not know