From: tboegi@web.de
To: tboegi@web.de, git@vger.kernel.org, friebetill@gmail.com,
phillip.wood123@gmail.com
Subject: [PATCH v1 1/1] git stash needing mkdir deletes untracked file
Date: Tue, 8 Aug 2023 19:26:24 +0200 [thread overview]
Message-ID: <20230808172624.14205-1-tboegi@web.de> (raw)
In-Reply-To: <5260C6A0-C53C-4F6D-B899-6AD8601F8458@gmail.com>
From: Torsten Bögershausen <tboegi@web.de>
The following sequence leads to loss of work:
git init
mkdir README
touch README/README
git add .
git commit -m "Init project"
echo "Test" > README/README
mv README/README README2
rmdir README
mv README2 README
git stash
git stash pop
The problem is, that `git stash` needs to create the directory README/
and to be able to do this, the file README needs to be removed.
And this is, where the work was lost.
There are different possibilities preventing this loss of work:
a)
`git stash` does refuse the removel of the untracked file,
when a directory with the same name needs to be created
There is a small problem here:
In the ideal world, the stash would do nothing at all,
and not do anything but complain.
The current code makes this hard to achieve
An other solution could be to do as much stash work as possible,
but stop when the file/directory conflict is detected.
This would create some inconsistent state.
b) Create the directory as needed, but rename the file before doing that.
This would let the `git stash` proceed as usual and create a "new" file,
which may be surprising for some worlflows.
This change goes for b), as it seems the most intuitive solution for
Git users.
Introdue a new function rename_to_untracked_or_warn() and use it
in create_directories() in entry.c
Reported-by: Till Friebe <friebetill@gmail.com>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
---
entry.c | 25 ++++++++++++++++++++++++-
t/t3903-stash.sh | 23 +++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/entry.c b/entry.c
index 43767f9043..76d8a0762d 100644
--- a/entry.c
+++ b/entry.c
@@ -15,6 +15,28 @@
#include "entry.h"
#include "parallel-checkout.h"
+static int rename_to_untracked_or_warn(const char *file)
+{
+ const size_t file_name_len = strlen(file);
+ const static char *dot_untracked = ".untracked";
+ const size_t dot_un_len = strlen(dot_untracked);
+ struct strbuf sb;
+ int ret;
+
+ strbuf_init(&sb, file_name_len + dot_un_len);
+ strbuf_add(&sb, file, file_name_len);
+ strbuf_add(&sb, dot_untracked, dot_un_len);
+ ret = rename(file, sb.buf);
+
+ if (ret) {
+ int saved_errno = errno;
+ warning_errno(_("unable rename '%s' into '%s'"), file, sb.buf);
+ errno = saved_errno;
+ }
+ strbuf_release(&sb);
+ return ret;
+}
+
static void create_directories(const char *path, int path_len,
const struct checkout *state)
{
@@ -48,7 +70,8 @@ static void create_directories(const char *path, int path_len,
*/
if (mkdir(buf, 0777)) {
if (errno == EEXIST && state->force &&
- !unlink_or_warn(buf) && !mkdir(buf, 0777))
+ !rename_to_untracked_or_warn(buf) &&
+ !mkdir(buf, 0777))
continue;
die_errno("cannot create directory at '%s'", buf);
}
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 0b3dfeaea2..1a210f8a5a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1512,4 +1512,27 @@ test_expect_success 'restore untracked files even when we hit conflicts' '
)
'
+test_expect_success 'stash mkdir README needed - README.untracked created' '
+ git init mkdir_needed_file_untracked &&
+ (
+ cd mkdir_needed_file_untracked &&
+ mkdir README &&
+ touch README/README &&
+ git add . &&
+ git commit -m "Add README/README" &&
+ echo Version2 > README/README &&
+ mv README/README README2 &&
+ rmdir README &&
+ mv README2 README &&
+ git stash &&
+ test_path_is_file README.untracked &&
+ echo Version2 >expect &&
+ test_cmp expect README.untracked &&
+ rm expect &&
+ git stash pop &&
+ test_path_is_file README.untracked &&
+ echo Version2 >expect &&
+ test_cmp expect README.untracked
+ )
+'
test_done
--
2.41.0.394.ge43f4fd0bd
next prev parent reply other threads:[~2023-08-08 19:00 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-21 17:31 Lost files after git stash && git stash pop Till Friebe
2023-07-22 21:44 ` Torsten Bögershausen
2023-07-23 10:01 ` Phillip Wood
2023-07-23 20:52 ` Torsten Bögershausen
2023-07-24 9:59 ` Phillip Wood
2023-08-08 17:26 ` tboegi [this message]
2023-08-08 18:03 ` [PATCH v1 1/1] git stash needing mkdir deletes untracked file Torsten Bögershausen
2023-08-08 19:28 ` Eric Sunshine
2023-08-09 13:15 ` Phillip Wood
2023-08-09 18:47 ` Torsten Bögershausen
2023-08-15 9:15 ` Phillip Wood
2023-08-15 15:25 ` Torsten Bögershausen
2023-08-15 18:03 ` Junio C Hamano
2023-08-09 20:57 ` Junio C Hamano
2023-08-15 9:16 ` Phillip Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230808172624.14205-1-tboegi@web.de \
--to=tboegi@web.de \
--cc=friebetill@gmail.com \
--cc=git@vger.kernel.org \
--cc=phillip.wood123@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).