git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Jeff King <peff@peff.net>
To: Daniel Sommermann <dcsommer@gmail.com>
Cc: git@vger.kernel.org, Junio C Hamano <gitster@pobox.com>,
	Christian Couder <chriscool@tuxfamily.org>,
	Stefan Beller <stefanbeller@gmail.com>
Subject: Re: [RFC PATCH] git-apply: Permit change of file mode when filename does not change
Date: Wed, 25 Mar 2020 02:11:02 -0400	[thread overview]
Message-ID: <20200325061102.GD651138@coredump.intra.peff.net> (raw)
In-Reply-To: <20200324160054.1535824-1-dcsommer@gmail.com>

On Tue, Mar 24, 2020 at 09:00:54AM -0700, Daniel Sommermann wrote:

> The documentation for git's diff format does not expressly disallow
> changing the mode of a file without splitting it into a delete and
> create. Mercurial's `hg diff --git` in fact produces git diffs with such
> format. When applying such patches in Git, this assert can be hit. The check
> preventing this type of diff has been around since 2005 in
> 3cca928d4aae691572ef9a73dcc29a04f66900a1.

This description confused me for a moment, because in Git we generally
refer to "mode changes" as flipping the executable bit. And anything
further is a "type change" (and this isn't just academic; options like
--diff-filter distinguish the two).

And we do indeed allow a simple mode change like:

  $ git show c9d4999155700651a37f4eb577cec1f4b5b8d6be --format=
  diff --git a/t/perf/p0004-lazy-init-name-hash.sh b/t/perf/p0004-lazy-init-name-hash.sh
  old mode 100644
  new mode 100755

But you're talking about typechanges here, and we do always represent
those as a deletion/addition pair:

  $ git show --format= -D 2efbb7f5218d5ca9d50cbcb86a365a08b2981d77 RelNotes
  diff --git a/RelNotes b/RelNotes
  deleted file mode 100644
  index 007bc065dd..0000000000
  diff --git a/RelNotes b/RelNotes
  new file mode 120000
  index 0000000000..8d0b1654d2
  --- /dev/null
  +++ b/RelNotes
  @@ -0,0 +1 @@
  +Documentation/RelNotes/2.20.0.txt
  \ No newline at end of file

I don't think we'd want to switch how we generate these diffs, but I
can't offhand think of a reason why it would be a bad idea to accept
such a patch converting a file to a symlink or vice versa.

But...

> Simply deleting the check that prevents changing the mode when not
> renaming allows such diffs to work out of the box, as the attached test
> case shows.

What about other more exotic typechanges, like a directory becoming a
file?  Or a file to a gitlink? I guess we'd never mention a directory in
--patch format anyway, but I wonder to what degree these lines in
check_patch() are protecting downstream code from doing something
stupid.

If I fake a diff like:

  diff --git a/file b/file
  old mode 100644
  new mode 040000

we seem to silently accept it but not write any mode change (we do write
a content change to the file). Swapping 040000 (a tree) out for 160000
(a gitlink) seems to delete file but not apply any content-level change.

Also, I'm not sure your patch works for the reverse case: a symlink
becoming a file. If I add this to your test:

diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index 593e6142b4..acd94a07a7 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -67,4 +67,20 @@ test_expect_success 'apply file-to-symlink patch' '
 
 '
 
+test_expect_success 'apply symlink-to-file patch' '
+
+	cat >reverse-patch <<-\EOF &&
+	diff --git a/file_to_be_link b/file_to_be_link
+	new mode 120000
+	old mode 100644
+	--- a/file_to_be_link
+	+++ b/file_to_be_link
+	@@ -1,1 +1,1 @@
+	-target
+	+file
+	EOF
+
+	git apply reverse-patch
+'
+
 test_done

it fails with "error: file_to_be_link: wrong type".

> diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
> index 872fcda6cb..593e6142b4 100755
> --- a/t/t4115-apply-symlink.sh
> +++ b/t/t4115-apply-symlink.sh

If we do go this route, two small fixes for the tests:

> @@ -44,4 +44,27 @@ test_expect_success 'apply --index symlink patch' '
>  
>  '
>  
> +cat >move_patch <<\EOF
> +diff --git a/file_to_be_link b/file_to_be_link
> +old mode 100644
> +new mode 120000
> +--- a/file_to_be_link
> ++++ b/file_to_be_link
> +@@ -0,0 +1,1 @@
> ++target
> +\ No newline at end of file
> +EOF

We prefer this kind of setup to go inside the test_expect_success block
(you can use "<<-\EOF" to strip leading tabs and get nice indentation).

Some older tests haven't been updated yet, so you may have picked this
up from a bad example, but we try to follow it when writing new ones.

> +test_expect_success 'apply file-to-symlink patch' '
> +
> +	git checkout -f master &&
> +	touch file_to_be_link &&
> +	git add file_to_be_link &&
> +	git commit -m initial &&
> +
> +	git apply move_patch &&
> +	test target = $(readlink file_to_be_link)
> +
> +'

This probably needs a SYMLINKS prerequisite, since we'd write the actual
symlink to the filesystem. We could work around that with "apply
--index", but I think it's important to test the full patch application.

-Peff

  reply	other threads:[~2020-03-25  6:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-24 16:00 [RFC PATCH] git-apply: Permit change of file mode when filename does not change Daniel Sommermann
2020-03-25  6:11 ` Jeff King [this message]
2020-03-25  6:52   ` Junio C Hamano

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=20200325061102.GD651138@coredump.intra.peff.net \
    --to=peff@peff.net \
    --cc=chriscool@tuxfamily.org \
    --cc=dcsommer@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=stefanbeller@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).