git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/3] Fix D/F issues in stash
@ 2021-09-08  1:43 Elijah Newren via GitGitGadget
  2021-09-08  1:43 ` [PATCH 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-08  1:43 UTC (permalink / raw)
  To: git; +Cc: Elijah Newren

This series fixes a few D/F issues in the stash command. These were some
issues I found while working on unintentional removal of untracked
files/directories and the current working directory, and I'm just submitting
them separately.

Elijah Newren (3):
  t3903: document a pair of directory/file bugs
  stash: avoid feeding directories to update-index
  stash: restore untracked files AFTER restoring tracked files

 builtin/stash.c  | 15 ++++++++++++---
 t/t3903-stash.sh | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 3 deletions(-)


base-commit: e0a2f5cbc585657e757385ad918f167f519cfb96
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1086%2Fnewren%2Fstash-df-fixes-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1086/newren/stash-df-fixes-v1
Pull-Request: https://github.com/git/git/pull/1086
-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/3] t3903: document a pair of directory/file bugs
  2021-09-08  1:43 [PATCH 0/3] Fix D/F issues in stash Elijah Newren via GitGitGadget
@ 2021-09-08  1:43 ` Elijah Newren via GitGitGadget
  2021-09-08 16:19   ` Junio C Hamano
  2021-09-08  1:43 ` [PATCH 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-08  1:43 UTC (permalink / raw)
  To: git; +Cc: Elijah Newren, Elijah Newren

From: Elijah Newren <newren@gmail.com>

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 t/t3903-stash.sh | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 873aa56e359..0727a494aa4 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1307,4 +1307,42 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
 	test_must_be_empty err
 '
 
+test_expect_failure '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 &&
+		cp filler/file expect &&
+		git stash push
+	)
+'
+
+test_expect_failure 'git stash can pop directory/file 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_done
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/3] stash: avoid feeding directories to update-index
  2021-09-08  1:43 [PATCH 0/3] Fix D/F issues in stash Elijah Newren via GitGitGadget
  2021-09-08  1:43 ` [PATCH 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
@ 2021-09-08  1:43 ` Elijah Newren via GitGitGadget
  2021-09-08  8:02   ` Johannes Schindelin
  2021-09-08  1:43 ` [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-08  1:43 UTC (permalink / raw)
  To: git; +Cc: Elijah Newren, Elijah Newren

From: Elijah Newren <newren@gmail.com>

When a file is removed from the cache, but there is a file of the same
name present in the working directory, we would normally treat that file
in the working directory as untracked.  However, in the case of stash,
doing that would prevent a simple 'git stash push', because the untracked
file would be in the way of restoring the deleted file.

git stash, however, blindly assumes that whatever is in the working
directory for a deleted file is wanted and passes that path along to
update-index.  That causes problems when the working directory contains
a directory with the same name as the deleted file.  Add some code for
this special case that will avoid passing directory names to
update-index.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 builtin/stash.c  | 9 +++++++++
 t/t3903-stash.sh | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/builtin/stash.c b/builtin/stash.c
index 8f42360ca91..b85cf9d267e 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -313,6 +313,12 @@ static int reset_head(void)
 	return run_command(&cp);
 }
 
+static int is_path_a_directory(const char *path)
+{
+	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 +326,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 */
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 0727a494aa4..fc74918ccc0 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1307,7 +1307,7 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
 	test_must_be_empty err
 '
 
-test_expect_failure 'git stash succeeds despite directory/file change' '
+test_expect_success 'git stash succeeds despite directory/file change' '
 	test_create_repo directory_file_switch_v1 &&
 	(
 		cd directory_file_switch_v1 &&
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files
  2021-09-08  1:43 [PATCH 0/3] Fix D/F issues in stash Elijah Newren via GitGitGadget
  2021-09-08  1:43 ` [PATCH 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
  2021-09-08  1:43 ` [PATCH 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
@ 2021-09-08  1:43 ` Elijah Newren via GitGitGadget
  2021-09-08 13:15   ` Derrick Stolee
  2021-09-08 16:30   ` Junio C Hamano
  2021-09-08  8:04 ` [PATCH 0/3] Fix D/F issues in stash Johannes Schindelin
  2021-09-10 10:29 ` [PATCH v2 " Elijah Newren via GitGitGadget
  4 siblings, 2 replies; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-08  1:43 UTC (permalink / raw)
  To: git; +Cc: Elijah Newren, Elijah Newren

From: Elijah Newren <newren@gmail.com>

If a user deletes a file and places a directory of untracked files
there, then stashes all these changes, the untracked directory of files
cannot be restored until after the corresponding file in the way is
removed.  So, restore changes to tracked files before restoring
untracked files.

There is no similar problem to worry about in the opposite directory,
because untracked files are always additive.  Said another way, there's
no way to "stash a removal of an untracked file" because if an untracked
file is removed, git simply doesn't know about it.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 builtin/stash.c  | 6 +++---
 t/t3903-stash.sh | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/stash.c b/builtin/stash.c
index b85cf9d267e..9a1f6a5a854 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -530,9 +530,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";
@@ -567,6 +564,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;
 
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index fc74918ccc0..bfd3158a502 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1325,7 +1325,7 @@ test_expect_success 'git stash succeeds despite directory/file change' '
 	)
 '
 
-test_expect_failure 'git stash can pop directory/file saved changes' '
+test_expect_success 'git stash can pop directory/file saved changes' '
 	test_create_repo directory_file_switch_v2 &&
 	(
 		cd directory_file_switch_v2 &&
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] stash: avoid feeding directories to update-index
  2021-09-08  1:43 ` [PATCH 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
@ 2021-09-08  8:02   ` Johannes Schindelin
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2021-09-08  8:02 UTC (permalink / raw)
  To: Elijah Newren via GitGitGadget; +Cc: git, Elijah Newren, Elijah Newren

Hi Elijah,

On Wed, 8 Sep 2021, Elijah Newren via GitGitGadget wrote:

> From: Elijah Newren <newren@gmail.com>
>
> When a file is removed from the cache, but there is a file of the same
> name present in the working directory, we would normally treat that file
> in the working directory as untracked.  However, in the case of stash,
> doing that would prevent a simple 'git stash push', because the untracked
> file would be in the way of restoring the deleted file.
>
> git stash, however, blindly assumes that whatever is in the working
> directory for a deleted file is wanted and passes that path along to
> update-index.  That causes problems when the working directory contains
> a directory with the same name as the deleted file.  Add some code for
> this special case that will avoid passing directory names to
> update-index.
>
> Signed-off-by: Elijah Newren <newren@gmail.com>
> ---
>  builtin/stash.c  | 9 +++++++++
>  t/t3903-stash.sh | 2 +-
>  2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/stash.c b/builtin/stash.c
> index 8f42360ca91..b85cf9d267e 100644
> --- a/builtin/stash.c
> +++ b/builtin/stash.c
> @@ -313,6 +313,12 @@ static int reset_head(void)
>  	return run_command(&cp);
>  }
>
> +static int is_path_a_directory(const char *path)
> +{
> +	struct stat st;
> +	return (!lstat(path, &st) && S_ISDIR(st.st_mode));
> +}

Git's API is unnecessarily confusing (because grown organically), so it is
easy to get confused by that `is_directory()` function that is declared in
`cache.h` and defined in `abspath.c`:

	/*
	 * Do not use this for inspecting *tracked* content.  When path is a
	 * symlink to a directory, we do not want to say it is a directory when
	 * dealing with tracked content in the working tree.
	 */
	int is_directory(const char *path)
	{
		struct stat st;
		return (!stat(path, &st) && S_ISDIR(st.st_mode));
	}

The difference I see is that you use an `lstat()`, which is kind of
important here.

Maybe you could add a paragraph pointing out that we cannot use
`is_directory()` here because it would follow symbolic links, which we
need to avoid here?

> +
>  static void add_diff_to_buf(struct diff_queue_struct *q,
>  			    struct diff_options *options,
>  			    void *data)
> @@ -320,6 +326,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 */
> diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
> index 0727a494aa4..fc74918ccc0 100755
> --- a/t/t3903-stash.sh
> +++ b/t/t3903-stash.sh
> @@ -1307,7 +1307,7 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
>  	test_must_be_empty err
>  '
>
> -test_expect_failure 'git stash succeeds despite directory/file change' '
> +test_expect_success 'git stash succeeds despite directory/file change' '

Excellent!

Thanks,
Dscho

>  	test_create_repo directory_file_switch_v1 &&
>  	(
>  		cd directory_file_switch_v1 &&
> --
> gitgitgadget
>
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/3] Fix D/F issues in stash
  2021-09-08  1:43 [PATCH 0/3] Fix D/F issues in stash Elijah Newren via GitGitGadget
                   ` (2 preceding siblings ...)
  2021-09-08  1:43 ` [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
@ 2021-09-08  8:04 ` Johannes Schindelin
  2021-09-08 13:15   ` Derrick Stolee
  2021-09-10 10:29 ` [PATCH v2 " Elijah Newren via GitGitGadget
  4 siblings, 1 reply; 14+ messages in thread
From: Johannes Schindelin @ 2021-09-08  8:04 UTC (permalink / raw)
  To: Elijah Newren via GitGitGadget; +Cc: git, Elijah Newren

Hi Elijah,

On Wed, 8 Sep 2021, Elijah Newren via GitGitGadget wrote:

> This series fixes a few D/F issues in the stash command. These were some
> issues I found while working on unintentional removal of untracked
> files/directories and the current working directory, and I'm just submitting
> them separately.

Awesome work! Apart from asking for an additional clarification in the
commit message of the second patch, I have nothing else to offer but my
sincere thanks for working on the `stash` code.

Thank you,
Dscho

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files
  2021-09-08  1:43 ` [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
@ 2021-09-08 13:15   ` Derrick Stolee
  2021-09-08 16:30   ` Junio C Hamano
  1 sibling, 0 replies; 14+ messages in thread
From: Derrick Stolee @ 2021-09-08 13:15 UTC (permalink / raw)
  To: Elijah Newren via GitGitGadget, git; +Cc: Elijah Newren

On 9/7/2021 9:43 PM, Elijah Newren via GitGitGadget wrote:
> From: Elijah Newren <newren@gmail.com>
> 
> If a user deletes a file and places a directory of untracked files
> there, then stashes all these changes, the untracked directory of files
> cannot be restored until after the corresponding file in the way is
> removed.  So, restore changes to tracked files before restoring
> untracked files.
> 
> There is no similar problem to worry about in the opposite directory,

s/directory/direction/ ?

> because untracked files are always additive.  Said another way, there's
> no way to "stash a removal of an untracked file" because if an untracked
> file is removed, git simply doesn't know about it.

Makes sense.

Thanks,
-Stolee

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/3] Fix D/F issues in stash
  2021-09-08  8:04 ` [PATCH 0/3] Fix D/F issues in stash Johannes Schindelin
@ 2021-09-08 13:15   ` Derrick Stolee
  0 siblings, 0 replies; 14+ messages in thread
From: Derrick Stolee @ 2021-09-08 13:15 UTC (permalink / raw)
  To: Johannes Schindelin, Elijah Newren via GitGitGadget; +Cc: git, Elijah Newren

On 9/8/2021 4:04 AM, Johannes Schindelin wrote:
> Hi Elijah,
> 
> On Wed, 8 Sep 2021, Elijah Newren via GitGitGadget wrote:
> 
>> This series fixes a few D/F issues in the stash command. These were some
>> issues I found while working on unintentional removal of untracked
>> files/directories and the current working directory, and I'm just submitting
>> them separately.
> 
> Awesome work! Apart from asking for an additional clarification in the
> commit message of the second patch, I have nothing else to offer but my
> sincere thanks for working on the `stash` code.

I found what is probably a typo in a commit message, but otherwise this
looks great.

Thanks,
-Stolee

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] t3903: document a pair of directory/file bugs
  2021-09-08  1:43 ` [PATCH 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
@ 2021-09-08 16:19   ` Junio C Hamano
  0 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2021-09-08 16:19 UTC (permalink / raw)
  To: Elijah Newren via GitGitGadget; +Cc: git, Elijah Newren

"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Elijah Newren <newren@gmail.com>
>
> Signed-off-by: Elijah Newren <newren@gmail.com>
> ---
>  t/t3903-stash.sh | 38 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
>
> diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
> index 873aa56e359..0727a494aa4 100755
> --- a/t/t3903-stash.sh
> +++ b/t/t3903-stash.sh
> @@ -1307,4 +1307,42 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
>  	test_must_be_empty err
>  '
>  
> +test_expect_failure '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 &&
> +		cp filler/file expect &&
> +		git stash push

Creating 'expect' that is not used---perhaps this side also wants to
apply the created stash and check the result, like the other side
does, or something?

Of course, an obvious alternative is to stop making a needless
'expect'.

> +	)
> +'
> +
> +test_expect_failure 'git stash can pop directory/file 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_done

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files
  2021-09-08  1:43 ` [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
  2021-09-08 13:15   ` Derrick Stolee
@ 2021-09-08 16:30   ` Junio C Hamano
  1 sibling, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2021-09-08 16:30 UTC (permalink / raw)
  To: Elijah Newren via GitGitGadget; +Cc: git, Elijah Newren

"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Elijah Newren <newren@gmail.com>
>
> If a user deletes a file and places a directory of untracked files
> there, then stashes all these changes, the untracked directory of files
> cannot be restored until after the corresponding file in the way is
> removed.  So, restore changes to tracked files before restoring
> untracked files.
>
> There is no similar problem to worry about in the opposite directory,

direction, I think.

If a user deletes a directory with tracked files in it and places an
untracked file at the path the directory used to be, and then stash
all these changes, that would be the opposite direction, I would
presume?  The untracked file would be restorable only after applying
the removal of the tracked files that occupied the directory.

Which would be fine if we apply the changes to the tracked ones first.

OK.

After creating a stash, we clear the working tree.  How do we do
that exactly, and would we have a similar problem there?  We need to
first remove the untracked file that currently occupies where the
directory used to be in HEAD, and then create the directory and
resurrect the tracked files in the directory from HEAD, in my
modified example above.  In the file-becomes-directory scenario, is
the story the same?

Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 0/3] Fix D/F issues in stash
  2021-09-08  1:43 [PATCH 0/3] Fix D/F issues in stash Elijah Newren via GitGitGadget
                   ` (3 preceding siblings ...)
  2021-09-08  8:04 ` [PATCH 0/3] Fix D/F issues in stash Johannes Schindelin
@ 2021-09-10 10:29 ` Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
                     ` (2 more replies)
  4 siblings, 3 replies; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-10 10:29 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Derrick Stolee, Elijah Newren

This series fixes a few D/F issues in the stash command. These were some
issues I found while working on unintentional removal of untracked
files/directories and the current working directory, and I'm just submitting
them separately.

Changes since v1:

 * Fix accidental creation of file named 'expect' (copy-paste problem...)
 * Documented the reason for adding is_path_a_directory() and not using
   is_directory()
 * Removed typo, fixed up confusing wording, and added a companion test to
   show that F->D and D->F have the same fix.

Elijah Newren (3):
  t3903: document a pair of directory/file bugs
  stash: avoid feeding directories to update-index
  stash: restore untracked files AFTER restoring tracked files

 builtin/stash.c  | 20 ++++++++++++++---
 t/t3903-stash.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 3 deletions(-)


base-commit: e0a2f5cbc585657e757385ad918f167f519cfb96
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1086%2Fnewren%2Fstash-df-fixes-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1086/newren/stash-df-fixes-v2
Pull-Request: https://github.com/git/git/pull/1086

Range-diff vs v1:

 1:  bc66a6ae75d ! 1:  5ddb70d332b t3903: document a pair of directory/file bugs
     @@ Metadata
       ## Commit message ##
          t3903: document a pair of directory/file bugs
      
     +    There are three tests here, because the second bug is documented with
     +    two tests: a file -> directory change and a directory -> file change.
     +    The reason for the two tests is just to verify that both are indeed
     +    broken but that both will be fixed by the same simple change (which will
     +    be provided in a subsequent patch).
     +
          Signed-off-by: Elijah Newren <newren@gmail.com>
      
       ## t/t3903-stash.sh ##
     @@ t/t3903-stash.sh: test_expect_success 'stash -c stash.useBuiltin=false warning '
      +		git rm filler &&
      +		mkdir filler &&
      +		echo contents >filler/file &&
     -+		cp filler/file expect &&
      +		git stash push
      +	)
      +'
      +
     -+test_expect_failure 'git stash can pop directory/file saved changes' '
     ++test_expect_failure 'git stash can pop file -> directory saved changes' '
      +	test_create_repo directory_file_switch_v2 &&
      +	(
      +		cd directory_file_switch_v2 &&
     @@ t/t3903-stash.sh: test_expect_success 'stash -c stash.useBuiltin=false warning '
      +		test_cmp expect filler/file
      +	)
      +'
     ++
     ++test_expect_failure '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
 2:  c7f5ae66a92 ! 2:  31e38c6c33c stash: avoid feeding directories to update-index
     @@ builtin/stash.c: static int reset_head(void)
       
      +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));
      +}
 3:  ac8ca07481d ! 3:  6254938948c stash: restore untracked files AFTER restoring tracked files
     @@ Commit message
          removed.  So, restore changes to tracked files before restoring
          untracked files.
      
     -    There is no similar problem to worry about in the opposite directory,
     -    because untracked files are always additive.  Said another way, there's
     -    no way to "stash a removal of an untracked file" because if an untracked
     -    file is removed, git simply doesn't know about it.
     +    There is no counterpart problem to worry about with the user deleting an
     +    untracked file and then add a tracked one in its place.  Git does not
     +    track untracked files, and so will not know the untracked file was
     +    deleted, and thus won't be able to stash the removal of that file.
      
          Signed-off-by: Elijah Newren <newren@gmail.com>
      
     @@ t/t3903-stash.sh: test_expect_success 'git stash succeeds despite directory/file
       	)
       '
       
     --test_expect_failure 'git stash can pop directory/file saved changes' '
     -+test_expect_success 'git stash can pop directory/file saved changes' '
     +-test_expect_failure 'git stash can pop file -> directory saved changes' '
     ++test_expect_success 'git stash can pop file -> directory saved changes' '
       	test_create_repo directory_file_switch_v2 &&
       	(
       		cd directory_file_switch_v2 &&
     +@@ t/t3903-stash.sh: test_expect_failure 'git stash can pop file -> directory saved changes' '
     + 	)
     + '
     + 
     +-test_expect_failure 'git stash can pop directory -> file saved changes' '
     ++test_expect_success 'git stash can pop directory -> file saved changes' '
     + 	test_create_repo directory_file_switch_v3 &&
     + 	(
     + 		cd directory_file_switch_v3 &&

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/3] t3903: document a pair of directory/file bugs
  2021-09-10 10:29 ` [PATCH v2 " Elijah Newren via GitGitGadget
@ 2021-09-10 10:29   ` Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
  2 siblings, 0 replies; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-10 10:29 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Derrick Stolee, Elijah Newren, Elijah Newren

From: Elijah Newren <newren@gmail.com>

There are three tests here, because the second bug is documented with
two tests: a file -> directory change and a directory -> file change.
The reason for the two tests is just to verify that both are indeed
broken but that both will be fixed by the same simple change (which will
be provided in a subsequent patch).

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 t/t3903-stash.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 873aa56e359..7346f8d1037 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1307,4 +1307,62 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
 	test_must_be_empty err
 '
 
+test_expect_failure '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_failure '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_failure '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
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/3] stash: avoid feeding directories to update-index
  2021-09-10 10:29 ` [PATCH v2 " Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
@ 2021-09-10 10:29   ` Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
  2 siblings, 0 replies; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-10 10:29 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Derrick Stolee, Elijah Newren, Elijah Newren

From: Elijah Newren <newren@gmail.com>

When a file is removed from the cache, but there is a file of the same
name present in the working directory, we would normally treat that file
in the working directory as untracked.  However, in the case of stash,
doing that would prevent a simple 'git stash push', because the untracked
file would be in the way of restoring the deleted file.

git stash, however, blindly assumes that whatever is in the working
directory for a deleted file is wanted and passes that path along to
update-index.  That causes problems when the working directory contains
a directory with the same name as the deleted file.  Add some code for
this special case that will avoid passing directory names to
update-index.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 builtin/stash.c  | 14 ++++++++++++++
 t/t3903-stash.sh |  2 +-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/builtin/stash.c b/builtin/stash.c
index 8f42360ca91..9ad2940f87a 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -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 */
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 7346f8d1037..34d1ad9837f 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1307,7 +1307,7 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' '
 	test_must_be_empty err
 '
 
-test_expect_failure 'git stash succeeds despite directory/file change' '
+test_expect_success 'git stash succeeds despite directory/file change' '
 	test_create_repo directory_file_switch_v1 &&
 	(
 		cd directory_file_switch_v1 &&
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/3] stash: restore untracked files AFTER restoring tracked files
  2021-09-10 10:29 ` [PATCH v2 " Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
  2021-09-10 10:29   ` [PATCH v2 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
@ 2021-09-10 10:29   ` Elijah Newren via GitGitGadget
  2 siblings, 0 replies; 14+ messages in thread
From: Elijah Newren via GitGitGadget @ 2021-09-10 10:29 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Derrick Stolee, Elijah Newren, Elijah Newren

From: Elijah Newren <newren@gmail.com>

If a user deletes a file and places a directory of untracked files
there, then stashes all these changes, the untracked directory of files
cannot be restored until after the corresponding file in the way is
removed.  So, restore changes to tracked files before restoring
untracked files.

There is no counterpart problem to worry about with the user deleting an
untracked file and then add a tracked one in its place.  Git does not
track untracked files, and so will not know the untracked file was
deleted, and thus won't be able to stash the removal of that file.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 builtin/stash.c  | 6 +++---
 t/t3903-stash.sh | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/stash.c b/builtin/stash.c
index 9ad2940f87a..5512f4942cd 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -535,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";
@@ -572,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;
 
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 34d1ad9837f..f0a82be9de7 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1324,7 +1324,7 @@ test_expect_success 'git stash succeeds despite directory/file change' '
 	)
 '
 
-test_expect_failure 'git stash can pop file -> directory saved changes' '
+test_expect_success 'git stash can pop file -> directory saved changes' '
 	test_create_repo directory_file_switch_v2 &&
 	(
 		cd directory_file_switch_v2 &&
@@ -1344,7 +1344,7 @@ test_expect_failure 'git stash can pop file -> directory saved changes' '
 	)
 '
 
-test_expect_failure 'git stash can pop directory -> file saved changes' '
+test_expect_success 'git stash can pop directory -> file saved changes' '
 	test_create_repo directory_file_switch_v3 &&
 	(
 		cd directory_file_switch_v3 &&
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2021-09-10 10:30 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-08  1:43 [PATCH 0/3] Fix D/F issues in stash Elijah Newren via GitGitGadget
2021-09-08  1:43 ` [PATCH 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
2021-09-08 16:19   ` Junio C Hamano
2021-09-08  1:43 ` [PATCH 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
2021-09-08  8:02   ` Johannes Schindelin
2021-09-08  1:43 ` [PATCH 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget
2021-09-08 13:15   ` Derrick Stolee
2021-09-08 16:30   ` Junio C Hamano
2021-09-08  8:04 ` [PATCH 0/3] Fix D/F issues in stash Johannes Schindelin
2021-09-08 13:15   ` Derrick Stolee
2021-09-10 10:29 ` [PATCH v2 " Elijah Newren via GitGitGadget
2021-09-10 10:29   ` [PATCH v2 1/3] t3903: document a pair of directory/file bugs Elijah Newren via GitGitGadget
2021-09-10 10:29   ` [PATCH v2 2/3] stash: avoid feeding directories to update-index Elijah Newren via GitGitGadget
2021-09-10 10:29   ` [PATCH v2 3/3] stash: restore untracked files AFTER restoring tracked files Elijah Newren via GitGitGadget

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).