From: Junio C Hamano <hidden> Date: 2016-06-15 22:50:29
Johannes Sixt [off-list ref] writes:
Is it by design that symlinks are less precious than files, or is it an
oversight?
I don't recall making conscious distinction between symmlinks and regular
files, so it is likely to be just a bug. Perhaps using stat() where
lstat() should be used and mistaking an error return as missing, or
something silly like that?
From: Johannes Sixt <hidden> Date: 2016-06-15 22:50:29
On Mittwoch, 2. Februar 2011, Junio C Hamano wrote:
Johannes Sixt [off-list ref] writes:
quoted
Is it by design that symlinks are less precious than files, or is it an
oversight?
I don't recall making conscious distinction between symmlinks and regular
files, so it is likely to be just a bug. Perhaps using stat() where
lstat() should be used and mistaking an error return as missing, or
something silly like that?
Hm, I don't think so. It seems to interact with the lstat_cache. When lstat
reports a symlink, this result is cached; but if it is a regular file, it is
not cached. I don't know, what the consequences are, though... I have to stop
my investigations for tonight.
-- Hannes
From: Johannes Sixt <hidden> Date: 2016-06-15 22:50:30
This adds tests where an untracked file and an untracked symlink are in the
way where a directory should be created by 'git checkout'. Commit b1735b1a
(do not overwrite files in leading path, 2010-12-14) fixed the case where
a file is in the way, but the untracked symlink is still removed silently.
Signed-off-by: Johannes Sixt <redacted>
---
On Mittwoch, 2. Februar 2011, Johannes Sixt wrote:
It seems to interact with the lstat_cache. When lstat
reports a symlink, this result is cached; but if it is a regular file, it
is not cached.
The case where a file is in the way was fixed only in v1.7.3.4, but symlinks
are still affected. Clemens, can you help?
-- Hannes
PS: When a date is given for commit reference in a commit message as above,
do you prefer the author date or the committer date? Above, I took the
committer date, which is 2 months behind the author date.
t/t2019-checkout-overwrite.sh | 50 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)
create mode 100755 t/t2019-checkout-overwrite.sh
@@ -0,0 +1,50 @@+#!/bin/sh++test_description='checkout must not overwrite an untracked objects'+../test-lib.sh++test_expect_success'setup''++mkdir-pa/b/c&&+>a/b/c/d&&+gitadd-A&&+gitcommit-mbase&&+gittagstart+'++test_expect_success'create a commit where dir a/b changed to file''++gitcheckout-bfile&&+rm-rfa/b&&+>a/b&&+gitadd-A&&+gitcommit-m"dir to file"+'++test_expect_success'checkout commit with dir must not remove untracked a/b''++gitrm--cacheda/b&&+gitcommit-m"un-track the file"&&+test_must_failgitcheckoutstart&&+test-fa/b+'++test_expect_success'create a commit where dir a/b changed to symlink''++rm-rfa/b&&# cleanup if previous test failed+gitcheckout-f-bsymlinkstart&&+rm-rfa/b&&+ln-sfooa/b&&+gitadd-A&&+gitcommit-m"dir to symlink"+'++test_expect_failure'checkout commit with dir must not remove untracked a/b''++gitrm--cacheda/b&&+gitcommit-m"un-track the symlink"&&+test_must_failgitcheckoutstart&&+test-ha/b+'++test_done
From: Clemens Buchacher <hidden> Date: 2016-06-15 22:50:30
Hi Hannes,
On Sat, Feb 05, 2011 at 07:18:44PM +0100, Johannes Sixt wrote:
This adds tests where an untracked file and an untracked symlink are in the
way where a directory should be created by 'git checkout'. Commit b1735b1a
(do not overwrite files in leading path, 2010-12-14) fixed the case where
a file is in the way, but the untracked symlink is still removed silently.
Indeed. It was my impression from reading the code that this
behavior is intentional. To protect symlinks from being overwritten
as well, I believe we simply have to remove FL_SYMLINK from the
following line in check_leading_path().
@@ -223,7 +223,7 @@ int check_leading_path(const char *name, int len)intflags;intmatch_len=lstat_cache_matchlen(cache,name,len,&flags,FL_SYMLINK|FL_NOENT|FL_DIR,USE_ONLY_LSTAT);-if(flags&(FL_SYMLINK|FL_NOENT))+if(flags&FL_NOENT)return0;elseif(flags&FL_DIR)return-1;
It does fix your testcase, but it may break others and I will have
to review the code to be sure.
Clemens
@@ -223,7 +223,7 @@ int check_leading_path(const char *name, int len)intflags;intmatch_len=lstat_cache_matchlen(cache,name,len,&flags,FL_SYMLINK|FL_NOENT|FL_DIR,USE_ONLY_LSTAT);-if(flags&(FL_SYMLINK|FL_NOENT))+if(flags&FL_NOENT)return0;elseif(flags&FL_DIR)return-1;
This function used to be named has-symlink-or-noent-leading-path before
f66caaf (do not overwrite files in leading path, 2010-10-09) and was used
to check for exactly that condition. For example, verify_absent_1() used
it to verify that a path A/B/C/D is not on the filesystem (e.g. in
preparation for checking it out) by making sure that none of A, A/B, or
A/B/C exists -- or is an untracked symlink. If one of them is a symlink
leading elsewhere, even if lstat("A/B/C/D") said the path exists, A/B/C/D
is not something we have in the work tree, and we decide that we can check
out the path by possibly removing intermediate symbolic link and running
mkdir.
Now you are changing the semantics of the function, so that we cannot
clobber intermediate symbolic links when we check out a path. It may
probably be a good change.
Can we rename this function to fix the naming regression introduced in
f66caaf, by the way? "check_leading_path()" is a horrible name for a
function that takes some parameters and returns a boolean, as the boolness
of the function already says enough that it is about "check", giving the
first part of the name 0-bit of information, and the remainder of the name
doesn't say much either: what aspect of leading-path is the function
about? Should the pathcomponents exist, should they not exist, why should
the caller care?
A name that explains for what purpose the caller is expected to call it is
probably the best kind of name. As long as the purpose does not change,
even though the implementation and the semantics are changed later, the
name can stay the same without losing its meaning. The second best kind
is a name that explains what it does. The old name of this function was
of this kind, until f66caaf renamed it to a meaningless name.
Perhaps can-clobber-to-checkout would be a good candidate.
From: Clemens Buchacher <hidden> Date: 2016-06-15 22:50:32
On Wed, Feb 09, 2011 at 03:48:12PM -0800, Junio C Hamano wrote:
Perhaps can-clobber-to-checkout would be a good candidate.
How about leading_path_in_use() instead? Whether files in the path
can be clobbered or not is checked in a separate step, which is
currently called ok_to_remove().
Clemens
From: Johannes Sixt <hidden> Date: 2016-06-15 22:50:34
I forgot to test the patch on Windows.. Would you please squash this
into js/checkout-untracked-symlink~1 ?
Thanks a lot!
--- 8< ---
From: Johannes Sixt <redacted>
Subject: [PATCH] fixup! Make test case number unique, mark tests with SYMLINKS prerequisite
Signed-off-by: Johannes Sixt <redacted>
---
...ut-overwrite.sh => t2021-checkout-overwrite.sh} | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
rename t/{t2019-checkout-overwrite.sh => t2021-checkout-overwrite.sh} (83%)
diff --git a/t/t2019-checkout-overwrite.sh b/t/t2021-checkout-overwrite.shsimilarity index 83%rename from t/t2019-checkout-overwrite.shrename to t/t2021-checkout-overwrite.shindex e4e529d..27db2ad 100755--- a/t/t2019-checkout-overwrite.sh+++ b/t/t2021-checkout-overwrite.sh
@@ -29,7 +29,7 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' 'test-fa/b'-test_expect_success'create a commit where dir a/b changed to symlink''+test_expect_successSYMLINKS'create a commit where dir a/b changed to symlink''rm-rfa/b&&# cleanup if previous test failedgitcheckout-f-bsymlinkstart&&
@@ -39,7 +39,7 @@ test_expect_success 'create a commit where dir a/b changed to symlink' 'gitcommit-m"dir to symlink"'-test_expect_failure'checkout commit with dir must not remove untracked a/b''+test_expect_failureSYMLINKS'checkout commit with dir must not remove untracked a/b''gitrm--cacheda/b&&gitcommit-m"un-track the symlink"&&
From: Clemens Buchacher <hidden> Date: 2016-06-15 22:50:37
Git traditionally overwrites untracked symlinks silently. This will
generally not cause massive data loss, but it is inconsistent with
the behavior for regular files, which are not silently overwritten.
With this change, git refuses to overwrite untracked symlinks by
default. If the user really wants to overwrite the untracked
symlink, he has git-clean and git-checkout -f at his disposal.
Signed-off-by: Clemens Buchacher <redacted>
---
I checked and there are no undesireable side-effects. One test had
to be modified slightly because it does overwrite an untracked
symlink.
symlinks.c | 2 +-
t/t6035-merge-dir-to-symlink.sh | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
@@ -223,7 +223,7 @@ int check_leading_path(const char *name, int len)intflags;intmatch_len=lstat_cache_matchlen(cache,name,len,&flags,FL_SYMLINK|FL_NOENT|FL_DIR,USE_ONLY_LSTAT);-if(flags&(FL_SYMLINK|FL_NOENT))+if(flags&FL_NOENT)return0;elseif(flags&FL_DIR)return-1;