Skip to content

Commit 795a5b2

Browse files
authored
Merge pull request libgit2#4668 from novalis/bad-stash
Fix stash save bug with fast path index check
2 parents f81923e + 5a7d454 commit 795a5b2

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/diff_generate.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ static git_diff_delta *diff_delta__last_for_item(
273273
break;
274274
case GIT_DELTA_MODIFIED:
275275
if (git_oid__cmp(&delta->old_file.id, &item->id) == 0 ||
276-
git_oid__cmp(&delta->new_file.id, &item->id) == 0)
276+
(delta->new_file.mode == item->mode &&
277+
git_oid__cmp(&delta->new_file.id, &item->id) == 0))
277278
return delta;
278279
break;
279280
default:

tests/stash/save.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,46 @@ void test_stash_save__can_include_untracked_and_ignored_files(void)
188188
cl_assert(!git_path_exists("stash/just.ignore"));
189189
}
190190

191+
/*
192+
* Note: this test was flaky prior to fixing #4101 -- run it several
193+
* times to get a failure. The issues is that whether the fast
194+
* (stat-only) codepath is used inside stash's diff operation depends
195+
* on whether files are "racily clean", and there doesn't seem to be
196+
* an easy way to force the exact required state.
197+
*/
198+
void test_stash_save__untracked_regression(void)
199+
{
200+
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
201+
const char *paths[] = {"what", "where", "how", "why"};
202+
git_reference *head;
203+
git_commit *head_commit;
204+
git_buf untracked_dir;
205+
206+
const char* workdir = git_repository_workdir(repo);
207+
208+
git_buf_init(&untracked_dir, 0);
209+
git_buf_printf(&untracked_dir, "%sz", workdir);
210+
211+
cl_assert(!p_mkdir(untracked_dir.ptr, 0777));
212+
213+
cl_git_pass(git_repository_head(&head, repo));
214+
215+
cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT));
216+
217+
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
218+
219+
opts.paths.strings = (char **)paths;
220+
opts.paths.count = 4;
221+
222+
cl_git_pass(git_checkout_tree(repo, (git_object*)head_commit, &opts));
223+
224+
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
225+
226+
assert_commit_message_contains("refs/stash", "WIP on master");
227+
228+
git_buf_free(&untracked_dir);
229+
}
230+
191231
#define MESSAGE "Look Ma! I'm on TV!"
192232
void test_stash_save__can_accept_a_message(void)
193233
{

0 commit comments

Comments
 (0)