Skip to content

Commit

Permalink
Merge pull request git-for-windows#494: reset: fix mixed reset when u…
Browse files Browse the repository at this point in the history
…sing virtual filesystem

This replaces git-for-windows#493 (can't reopen a PR after a force-push...).

I updated this commit with a more firm version of the fix. This hopefully answers Victoria's excellent concerns with the previous approach.

I did not manage to get an automated test for this, but I did carefully verify this manually with a few commits in a VFS for Git enlistment (with different files every time). I updated the commit message with more details about why this works.

---

This fork contains changes specific to monorepo scenarios. If you are an
external contributor, then please detail your reason for submitting to
this fork:

* [X] This change only applies to the virtualization hook and VFS for Git.

Resolves git-for-windows#490.
  • Loading branch information
derrickstolee authored and dscho committed Aug 21, 2023
2 parents ae1a769 + 0bc3512 commit 44aaf87
Showing 1 changed file with 48 additions and 2 deletions.
50 changes: 48 additions & 2 deletions builtin/reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include "add-interactive.h"
#include "strbuf.h"
#include "quote.h"
#include "dir.h"
#include "entry.h"

#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)

Expand Down Expand Up @@ -156,9 +158,47 @@ static void update_index_from_diff(struct diff_queue_struct *q,

for (i = 0; i < q->nr; i++) {
int pos;
int respect_skip_worktree = 1;
struct diff_filespec *one = q->queue[i]->one;
struct diff_filespec *two = q->queue[i]->two;
int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
int is_missing = !(one->mode && !is_null_oid(&one->oid));
int was_missing = !two->mode && is_null_oid(&two->oid);
struct cache_entry *ce;
struct cache_entry *ceBefore;
struct checkout state = CHECKOUT_INIT;

/*
* When using the virtual filesystem feature, the cache entries that are
* added here will not have the skip-worktree bit set.
*
* Without this code there is data that is lost because the files that
* would normally be in the working directory are not there and show as
* deleted for the next status or in the case of added files just disappear.
* We need to create the previous version of the files in the working
* directory so that they will have the right content and the next
* status call will show modified or untracked files correctly.
*/
if (core_virtualfilesystem && !file_exists(two->path))
{
pos = index_name_pos(&the_index, two->path, strlen(two->path));
if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) &&
(is_missing || !was_missing))
{
state.force = 1;
state.refresh_cache = 1;
state.istate = &the_index;
ceBefore = make_cache_entry(&the_index, two->mode,
&two->oid, two->path,
0, 0);
if (!ceBefore)
die(_("make_cache_entry failed for path '%s'"),
two->path);

checkout_entry(ceBefore, &state, NULL, NULL);
respect_skip_worktree = 0;
}
}

if (!is_in_reset_tree && !intent_to_add) {
remove_file_from_index(&the_index, one->path);
Expand All @@ -177,8 +217,14 @@ static void update_index_from_diff(struct diff_queue_struct *q,
* to properly construct the reset sparse directory.
*/
pos = index_name_pos(&the_index, one->path, strlen(one->path));
if ((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index)))

/*
* Do not add the SKIP_WORKTREE bit back if we populated the
* file on purpose in a virtual filesystem scenario.
*/
if (respect_skip_worktree &&
((pos >= 0 && ce_skip_worktree(the_index.cache[pos])) ||
(pos < 0 && !path_in_sparse_checkout(one->path, &the_index))))
ce->ce_flags |= CE_SKIP_WORKTREE;

if (!ce)
Expand Down

0 comments on commit 44aaf87

Please sign in to comment.