Merge branch 'en/stash-df-fix'

"git stash", where the tentative change involves changing a
directory to a file (or vice versa), was confused, which has been
corrected.

* en/stash-df-fix:
  stash: restore untracked files AFTER restoring tracked files
  stash: avoid feeding directories to update-index
  t3903: document a pair of directory/file bugs
This commit is contained in:
Junio C Hamano 2021-10-03 21:49:16 -07:00
commit 4a6fd7d3c7
2 changed files with 75 additions and 3 deletions

View file

@ -313,6 +313,17 @@ static int reset_head(void)
return run_command(&cp);
}
static int is_path_a_directory(const char *path)
{
/*
* This function differs from abspath.c:is_directory() in that
* here we use lstat() instead of stat(); we do not want to
* follow symbolic links here.
*/
struct stat st;
return (!lstat(path, &st) && S_ISDIR(st.st_mode));
}
static void add_diff_to_buf(struct diff_queue_struct *q,
struct diff_options *options,
void *data)
@ -320,6 +331,9 @@ static void add_diff_to_buf(struct diff_queue_struct *q,
int i;
for (i = 0; i < q->nr; i++) {
if (is_path_a_directory(q->queue[i]->one->path))
continue;
strbuf_addstr(data, q->queue[i]->one->path);
/* NUL-terminate: will be fed to update-index -z */
@ -521,9 +535,6 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
}
}
if (info->has_u && restore_untracked(&info->u_tree))
return error(_("could not restore untracked files from stash"));
init_merge_options(&o, the_repository);
o.branch1 = "Updated upstream";
@ -558,6 +569,9 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
unstage_changes_unless_new(&c_tree);
}
if (info->has_u && restore_untracked(&info->u_tree))
return error(_("could not restore untracked files from stash"));
if (!quiet) {
struct child_process cp = CHILD_PROCESS_INIT;

View file

@ -1307,4 +1307,62 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
test_must_be_empty err
'
test_expect_success 'git stash succeeds despite directory/file change' '
test_create_repo directory_file_switch_v1 &&
(
cd directory_file_switch_v1 &&
test_commit init &&
test_write_lines this file has some words >filler &&
git add filler &&
git commit -m filler &&
git rm filler &&
mkdir filler &&
echo contents >filler/file &&
git stash push
)
'
test_expect_success 'git stash can pop file -> directory saved changes' '
test_create_repo directory_file_switch_v2 &&
(
cd directory_file_switch_v2 &&
test_commit init &&
test_write_lines this file has some words >filler &&
git add filler &&
git commit -m filler &&
git rm filler &&
mkdir filler &&
echo contents >filler/file &&
cp filler/file expect &&
git stash push --include-untracked &&
git stash apply --index &&
test_cmp expect filler/file
)
'
test_expect_success 'git stash can pop directory -> file saved changes' '
test_create_repo directory_file_switch_v3 &&
(
cd directory_file_switch_v3 &&
test_commit init &&
mkdir filler &&
test_write_lines some words >filler/file1 &&
test_write_lines and stuff >filler/file2 &&
git add filler &&
git commit -m filler &&
git rm -rf filler &&
echo contents >filler &&
cp filler expect &&
git stash push --include-untracked &&
git stash apply --index &&
test_cmp expect filler
)
'
test_done