Skip to contentSkip to conversation

diff: Add diff.orderfile configuration variable

PATCH In review Anders Waldenborg 5 participants 35 messages Jun 15, 2016 Documentation

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 diff: Add diff.orderfile configuration variable

diff.orderfile acts as a default for the -O command line option.

---

 Documentation/diff-config.txt |  4 +++
 diff.c                        |  5 +++
 t/t4056-diff-order.sh         | 74 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+)
 create mode 100755 t/t4056-diff-order.sh
Documentation/diff-config.txt +4 -0
index 223b931..51f9190 100644
@@ -98,6 +98,10 @@ diff.mnemonicprefix::
 diff.noprefix::
  If set, 'git diff' does not show any source or destination prefix.
 
+diff.orderfile::
+ Path to file to use for ordering the files in the diff, each line
+ is a shell glob pattern; equivalent to the 'git diff' option '-O'.
+
 diff.renameLimit::
  The number of files to consider when performing the copy/rename
  detection; equivalent to the 'git diff' option '-l'.
diff.c +1 -0
index a04a34d..e66f031 100644
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
 static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char

*value, void *cb)
return git_config_string(&external_diff_cmd_cfg, var, value); if (!strcmp(var, "diff.wordregex"))
return git_config_string(&diff_word_regex_cfg, var, value);
+ if (!strcmp(var, "diff.orderfile"))
+ return git_config_string(&diff_order_file_cfg, var, value);

if (!strcmp(var, "diff.ignoresubmodules")) handle_ignore_submodules_arg(&default_diff_options, value);
@@ -3207,6 +3210,8 @@ void diff_setup(struct diff_options *options)
options->detect_rename = diff_detect_rename_default; options->xdl_opts |= diff_algorithm;

+ options->orderfile = diff_order_file_cfg;
+
if (diff_no_prefix) {
options->a_prefix = options->b_prefix = "";
} else if (!diff_mnemonic_prefix) {

t/t4056-diff-order.sh new file +67 -0

67 lines not on this page · raw message

Quoted 1 line

actual_diff_headers &&

+ test_debug actual_diff_headers
+ test_cmp expect_diff_headers_1 actual_diff_headers &&
+ git -c diff.orderfile=order_file_2 diff HEAD^..HEAD | grep ^diff

Quoted 1 line

actual_diff_headers &&

+ test_debug actual_diff_headers
+ test_cmp expect_diff_headers_2 actual_diff_headers' +
+test_done

Signature · 1 line
1.8.4.1.559.gdb9bdfb.dirty
#1 lore raw

Hi,

Quoted 3 lines · Anders Waldenborg

diff.orderfile acts as a default for the -O command line option.

Thanks.

[...]

Documentation/diff-config.txt diff.mnemonicprefix:: · line 99

Quoted 5 lines
Documentation/diff-config.txt +0 -0
@@ -98,6 +98,10 @@ diff.mnemonicprefix::
 diff.noprefix::
  If set, 'git diff' does not show any source or destination prefix.

It looks like your mailer is corrupting tabs and converting them into spaces. See the "Discussion" section of git-format-patch(1) for hints on checking a patch by mailing it to yourself and applying with git-am(1).

Documentation/diff-config.txt diff.mnemonicprefix:: · line 103

Quoted 3 lines
Documentation/diff-config.txt +3 -0
+diff.orderfile::
+ Path to file to use for ordering the files in the diff, each line
+ is a shell glob pattern; equivalent to the 'git diff' option '-O'.

Nits:

* "Path to" could be left out, since a path is the only way to specify a file :)
* Comma splice.
* What happens if both [diff] orderfile and the -O option are used?

How about something like the following?

diff.orderfile::
File indicating how to order files within a diff, using one shell glob pattern per line.
Can be overridden by the '-O' option to linkgit:git-diff[1].

Should the git-diff(1) manpage get a note about this setting as well (perhaps in a new CONFIGURATION section)?

[...]

Quoted 21 lines
diff.c +3 -0
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
 static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char
 *value, void *cb)
  return git_config_string(&external_diff_cmd_cfg, var, value);
  if (!strcmp(var, "diff.wordregex"))
  return git_config_string(&diff_word_regex_cfg, var, value);
+ if (!strcmp(var, "diff.orderfile"))
+ return git_config_string(&diff_order_file_cfg, var, value);
 
  if (!strcmp(var, "diff.ignoresubmodules"))
  handle_ignore_submodules_arg(&default_diff_options, value);

diff.c void diff_setup(struct diff_options *options) · line 3214

Quoted 5 lines
diff.c +2 -0
@@ -3207,6 +3210,8 @@ void diff_setup(struct diff_options *options)
  options->detect_rename = diff_detect_rename_default;
  options->xdl_opts |= diff_algorithm;
 
+ options->orderfile = diff_order_file_cfg;
+

Should Documentation/technical/api-diff.txt be tweaked to mention that the options set by diff_setup() depend on configuration now?

If a caller wants to parse diff config and also wants to make a diff without using the config (the example I'm imagining is an alternative implemention fo "git log -p --cherry-pick"), can they do that? It's tempting to move handling of configuration into a separate function. (Perhaps it's not worth worrying about that until someone needs the flexibility, though.)

t/t4056-diff-order.sh line 7

Quoted 10 lines
t/t4056-diff-order.sh new file +7 -0
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+test_description='diff order'
+
+. ./test-lib.sh
+
+_test_create_files () {

Why the leading underscore?

[...]

t/t4056-diff-order.sh line 51

Quoted 1 line
t/t4056-diff-order.sh new file +1 -0
+test_expect_success "setup" '_test_create_files 1 && _test_create_files 2'

Usual style is to put each command on its own line:

	test_expect_success 'setup' '
		_test_create_files 1 &&
		_test_create_files 2
	'

t/t4056-diff-order.sh line 54

Quoted 3 lines
t/t4056-diff-order.sh new file +3 -0
+
+test_expect_success "no order (=tree object order)" '
+ git diff HEAD^..HEAD | grep ^diff >actual_diff_headers &&

This loses the exit code from "git diff", which loses a chance to notice if "git diff" starts to segfault now and then. How about:

git diff HEAD^..HEAD >patch &&
grep ^diff patch >actual_diff_headers test_cmp expect_diff_headers_non actual_diff_headers

t/t4056-diff-order.sh line 12

Quoted 1 line
t/t4056-diff-order.sh new file +1 -0
+ test_debug actual_diff_headers

test_debug runs its argument as a command, which is not what I think you want here. :) Probably you wanted to write the diff header out when testing with "--verbose" so if it fails it is clear how it failed?

t/t4056-diff-order.sh line 56

Quoted 1 line
t/t4056-diff-order.sh new file +1 -0
+ test_cmp expect_diff_headers_none actual_diff_headers'

Luckily test_cmp already takes care of that, by printing a diff.

Hope that helps,
Jonathan

#2 lore raw

(Jonathan, sorry if you got this multiple times, it seems I forgot to Cc list)

Quoted 2 lines · Jonathan Nieder

Should the git-diff(1) manpage get a note about this setting as well (perhaps in a new CONFIGURATION section)?

I'll add a reference to the documentation for the -O option at least. That is how --check, --color, --dirstat and others do it, I guess that could be moved to a CONFIGURATION section later?

Quoted 2 lines

Should Documentation/technical/api-diff.txt be tweaked to mention that the options set by diff_setup() depend on configuration now?

It already did, didn't it? At least diff.context, diff.renames and diff.color seems to affect diff_setup(), no?

Quoted 6 lines

If a caller wants to parse diff config and also wants to make a diff without using the config (the example I'm imagining is an alternative implemention fo "git log -p --cherry-pick"), can they do that? It's tempting to move handling of configuration into a separate function. (Perhaps it's not worth worrying about that until someone needs the flexibility, though.)

Right, patch-ids are not stable wrt ordering. That might be a problem if some tool stores patch-ids. But maybe that even is a separate bug? Should patch-id always reorder the files internally? Is it expected that "git diff -Oorder1 | git patch-id" and "git diff -Oorder2 | git patch-id" gives same patch id?

It gets very interesting in an imaginative "git log -p --cherry-pick" which caches patch-ids on disk, one would want one stable ordering for calculating the patchid, while the displayed patch should respect the user requested order.

I guess that in most cases one would want to respect user configured ordering. Should diff_setup grow an argument "ignore_config"? Or should we maybe add an --no-order-file option that easily be set as a flag in diff_options in those cases?

Quoted 1 line

Hope that helps,

It does. Thanks! I have updated patch as per your other comments.

anders

#3 lore raw

PATCH v2 1/1 diff: Add diff.orderfile configuration variable

In reply to Anders Waldenborg

From: Anders Waldenborg <[email protected]>

diff.orderfile acts as a default for the -O command line option.

[sb: fixed testcases & revised docs based on Jonathan Nieder's suggestions]

Thanks-to: Jonathan Nieder <[email protected]>

---
*I* even verified that the tests do fail properly when the feature is sabotaged.

 Documentation/diff-config.txt  |  5 +++
 Documentation/diff-options.txt |  2 ++
 diff.c                         |  5 +++
 t/t4056-diff-order.sh          | 79 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100755 t/t4056-diff-order.sh
Documentation/diff-config.txt +5 -0
index 223b931..f07b451 100644
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
 diff.noprefix::
 	If set, 'git diff' does not show any source or destination prefix.
 
+diff.orderfile::
+	File indicating how to order files within a diff, using
+	one shell glob pattern per line.
+	Can be overridden by the '-O' option to linkgit:git-diff[1].
+
 diff.renameLimit::
 	The number of files to consider when performing the copy/rename
 	detection; equivalent to the 'git diff' option '-l'.
Documentation/diff-options.txt +2 -0
index bbed2cd..1af5a5e 100644
@@ -432,6 +432,8 @@ endif::git-format-patch[]
 -O<orderfile>::
 	Output the patch in the order specified in the
 	<orderfile>, which has one shell glob pattern per line.
+	This overrides the `diff.orderfile' configuration variable
+	((see linkgit:git-config[1]).
 
 ifndef::git-format-patch[]
 -R::
diff.c +5 -0
index e34bf97..a92b570 100644
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
 static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
 		return git_config_string(&external_diff_cmd_cfg, var, value);
 	if (!strcmp(var, "diff.wordregex"))
 		return git_config_string(&diff_word_regex_cfg, var, value);
+	if (!strcmp(var, "diff.orderfile"))
+		return git_config_string(&diff_order_file_cfg, var, value);
 
 	if (!strcmp(var, "diff.ignoresubmodules"))
 		handle_ignore_submodules_arg(&default_diff_options, value);
@@ -3207,6 +3210,8 @@ void diff_setup(struct diff_options *options)
 	options->detect_rename = diff_detect_rename_default;
 	options->xdl_opts |= diff_algorithm;
 
+	options->orderfile = diff_order_file_cfg;
+
 	if (diff_no_prefix) {
 		options->a_prefix = options->b_prefix = "";
 	} else if (!diff_mnemonic_prefix) {
t/t4056-diff-order.sh new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
1.8.4.3
#4 lore raw
Quoted 9 lines · Samuel Bronson

From: Anders Waldenborg <[email protected]>

diff.orderfile acts as a default for the -O command line option.

[sb: fixed testcases & revised docs based on Jonathan Nieder's suggestions]

Thanks-to: Jonathan Nieder <[email protected]>

Thanks for reviving a stalled topic.

Quoted 3 lines

---
*I* even verified that the tests do fail properly when the feature is sabotaged.

Sabotaged in what way?

Quoted 28 lines
 Documentation/diff-config.txt  |  5 +++
 Documentation/diff-options.txt |  2 ++
 diff.c                         |  5 +++
 t/t4056-diff-order.sh          | 79 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100755 t/t4056-diff-order.sh
Documentation/diff-config.txt +5 -0
index 223b931..f07b451 100644
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
 diff.noprefix::
 	If set, 'git diff' does not show any source or destination prefix.
 
+diff.orderfile::
+	File indicating how to order files within a diff, using
+	one shell glob pattern per line.
+	Can be overridden by the '-O' option to linkgit:git-diff[1].
+
 diff.renameLimit::
 	The number of files to consider when performing the copy/rename
 	detection; equivalent to the 'git diff' option '-l'.
Documentation/diff-options.txt +0 -0
index bbed2cd..1af5a5e 100644

Documentation/diff-options.txt endif::git-format-patch[] · line 436

Quoted 5 lines
Documentation/diff-options.txt +2 -0
@@ -432,6 +432,8 @@ endif::git-format-patch[]
 -O<orderfile>::
 	Output the patch in the order specified in the
 	<orderfile>, which has one shell glob pattern per line.
+	This overrides the `diff.orderfile' configuration variable
+	((see linkgit:git-config[1]).

Double opening parenthesis?

If somebody has diff.orderfile configuration that points at a custom ordering, and wants to send out a patch (or show a diff) with the standard order, how would the "overriding" command line look like? Would it be "git diff -O/dev/null"?

Quoted 11 lines
t/t4056-diff-order.sh new file +5 -0
new file mode 100755
index 0000000..a756b34
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+test_description='diff order'
+
+. ./test-lib.sh

t/t4056-diff-order.sh line 15

Quoted 10 lines
t/t4056-diff-order.sh new file +10 -0
+
+create_files () {
+	echo "$1" >a.h &&
+	echo "$1" >b.c &&
+	echo "$1" >c/Makefile &&
+	echo "$1" >d.txt &&
+	git add a.h b.c c/Makefile d.txt &&
+	git commit -m"$1"
+	return $?
+}

That return looks somewhat strange. Does it even need to be there?

t/t4056-diff-order.sh line 17

Quoted 1 line
t/t4056-diff-order.sh new file +1 -0
+test_expect_success "setup" '

Makes readers wonder why dq is used here, I think.

Quoted 28 lines
t/t4056-diff-order.sh new file +28 -0
+	mkdir c &&
+	create_files 1 &&
+	create_files 2
+'
+
+cat >order_file_1 <<EOF
+*Makefile
+*.txt
+*.h
+*
+EOF
+cat >order_file_2 <<EOF
+*Makefile
+*.h
+*.c
+*
+EOF
+
+cat >expect_diff_headers_none <<EOF
+diff --git a/a.h b/a.h
+diff --git a/b.c b/b.c
+diff --git a/c/Makefile b/c/Makefile
+diff --git a/d.txt b/d.txt
+EOF
+
+cat >expect_diff_headers_1 <<EOF
+diff --git a/c/Makefile b/c/Makefile
+diff --git a/d.txt b/d.txt

t/t4056-diff-order.sh line 55

Quoted 10 lines
t/t4056-diff-order.sh new file +10 -0
+diff --git a/a.h b/a.h
+diff --git a/b.c b/b.c
+EOF
+
+cat >expect_diff_headers_2 <<EOF
+diff --git a/c/Makefile b/c/Makefile
+diff --git a/a.h b/a.h
+diff --git a/b.c b/b.c
+diff --git a/d.txt b/d.txt
+EOF

All of these "cat" outside the test_expect_* are better be inside the 'setup' section, I think. I.e.

	test_expect_success setup '
        	mkdir c &&
                create_files 1 &&
                create_files 2 &&
                cat >order_file_1 <<-\EOF &&
                *Makefile
                *.txt
                *.h
                *
                EOF
                cat >order_file_2 <<-\EOF &&
		...
		cat >expect_diff_headers_2 <<EOF
                ...
                EOF
	'

Quoting the EOF like the above will help the readers by signaling them that they do not have to wonder if there is some substitution going on in the here text.

t/t4056-diff-order.sh line 61

Quoted 5 lines
t/t4056-diff-order.sh new file +5 -0
+test_expect_success "no order (=tree object order)" '
+	git diff HEAD^..HEAD >patch &&
+	grep ^diff patch >actual_diff_headers &&
+	test_cmp expect_diff_headers_none actual_diff_headers
+'

Instead of grepping, "git diff --name-only" would be far easier to check, no?

Quoted 4 lines
t/t4056-diff-order.sh new file +4 -0
+for i in 1 2; do
+	test_expect_success "orderfile using option ($i)" "
+	git diff -Oorder_file_$i HEAD^..HEAD >patch &&
+	grep ^diff patch >actual_diff_headers &&

t/t4056-diff-order.sh line 77

Quoted 10 lines
t/t4056-diff-order.sh new file +10 -0
+	test_cmp expect_diff_headers_$i actual_diff_headers
+"
+done
+for i in 1 2; do
+	test_expect_success "orderfile using config ($i)" "
+	git -c diff.orderfile=order_file_$i diff HEAD^..HEAD >patch &&
+	grep ^diff patch >actual_diff_headers &&
+	test_cmp expect_diff_headers_$i actual_diff_headers
+"
+done

I'd probably write the above like so:

	for i in 1 2
        do
		test_expect_success "orderfile using option ($i)" '
                	git diff -Oorder_file_$i --name-only HEAD^ >actual &&
			test_cmp expect_$i actual
		'
		test_expect_success "orderfile using config ($i)" '
			test_config diff.orderfile order_file_$i &&
                	git diff --name-only HEAD^ >actual &&
			test_cmp expect_$i actual
		'
	done

Points to note:

* We eval the scriptlets inside test framework, so using $i as a variable inside the single quotes will have the expected result. You do not have to worry about extra quoting inside dq pair.

* We do _not_ substitute variables in the test title (perhaps we should have designed the test framework to do so, in hindsight), so unfortunately the title need to be in dq.

* Use line-breaks instead of semicolons when writing compound syntax structures such as "for/do/done", "if/then/elif/else/fi", etc.

#5 lore raw
Quoted 3 lines · Junio C Hamano

Samuel Bronson <[email protected]> writes:

Thanks for reviving a stalled topic.

I was asking about such a feature in #git and jrnieder was nice enough to point me at the stalled patch.

Quoted 4 lines
Quoted 2 lines

*I* even verified that the tests do fail properly when the feature is sabotaged.

Sabotaged in what way?

I commented out the "options->orderfile = diff_order_file_cfg;" line.

Quoted 8 lines

Documentation/diff-options.txt endif::git-format-patch[] · line 436

Quoted 6 lines
Documentation/diff-options.txt +2 -0
@@ -432,6 +432,8 @@ endif::git-format-patch[]
 -O<orderfile>::
      Output the patch in the order specified in the
      <orderfile>, which has one shell glob pattern per line.
+     This overrides the `diff.orderfile' configuration variable
+     ((see linkgit:git-config[1]).

Double opening parenthesis?

Oops, and it looks like I messed up the quoting on diff.orderfile too ...

Quoted 4 lines

If somebody has diff.orderfile configuration that points at a custom ordering, and wants to send out a patch (or show a diff) with the standard order, how would the "overriding" command line look like? Would it be "git diff -O/dev/null"?

It looks like that works ... and so do files that don't exist. What do you think should happen with -O file-that-does-not-exist, and how do you suppose it should be tested?

After having fixed this, will /dev/null still work everywhere, or will we want a new diff flag to unset the option? (I see that "git diff /dev/null some-file" works fine with msysgit, which doesn't seem to actually be linked with MSYS, but I don't know *why* it works, and I don't know what other non-POSIXoid ports exist.)

For the moment, I've added this to "for" loop (after some changes based on some of your other suggestions):

# I don't think this should just pretend the orderfile was empty? test_expect_failure "override with bogus orderfile ($i)" ' test_might_fail git -c diff.orderfile=order_file_$i diff
-Obogus_file --name-only HEAD^..HEAD >actual_diff_filenames &&
! test_cmp expect_diff_filenames_none actual_diff_filenames
'

Does this look (modulo gmail's stupid indentation) anything like a reasonable approach to testing that? (Of course, you can't actually test it because it depends on other changes I haven't posted yet ...)

Also, I'm starting to wonder if I shouldn't split this into two patches:

1. diff: Add tests for -O flag
2. diff: Add diff.orderfile configuration variable

(If so, I would obviously want to rewrite the above test to avoid the configuration option.)

Quoted 4 lines

t/t4056-diff-order.sh line 15

Quoted 2 lines
t/t4056-diff-order.sh new file +2 -0
+     return $?
+}

That return looks somewhat strange. Does it even need to be there?

I'm certainly no great expert at shell functions, so I expect it isn't. I'm not really sure what possessed me to think it might be needed.

Quoted 2 lines
                EOF
                cat >order_file_2 <<-\EOF &&

I'd kind of prefer to keep a blank line between one EOF and the next cat, if that's okay with you.

Quoted 4 lines

Quoting the EOF like the above will help the readers by signaling them that they do not have to wonder if there is some substitution going on in the here text.

Perhaps, but probably only after they've scrutinized their shell manuals to figure out what the - and the \ are for. (I had to check
two: dash(1) wasn't clear enough for me about the quoting ...)

Quoted 8 lines

t/t4056-diff-order.sh line 61

Quoted 5 lines
t/t4056-diff-order.sh new file +5 -0
+test_expect_success "no order (=tree object order)" '
+     git diff HEAD^..HEAD >patch &&
+     grep ^diff patch >actual_diff_headers &&
+     test_cmp expect_diff_headers_none actual_diff_headers
+'

Instead of grepping, "git diff --name-only" would be far easier to check, no?

It certainly makes for less-cluttered expected output. (I guess jrnieder didn't know about that trick when he suggested using the intermediate file?)

Quoted 5 lines

Points to note:

* We eval the scriptlets inside test framework, so using $i as a variable inside the single quotes will have the expected result. You do not have to worry about extra quoting inside dq pair.

Hmm. I'm obviously not used to things getting eval'd in the same shell instance as my script ...

(Thanks for the review!)

#6 lore raw
Quoted 8 lines · Samuel Bronson
Quoted 4 lines

If somebody has diff.orderfile configuration that points at a custom ordering, and wants to send out a patch (or show a diff) with the standard order, how would the "overriding" command line look like? Would it be "git diff -O/dev/null"?

It looks like that works ... and so do files that don't exist. What do you think should happen with -O file-that-does-not-exist, and how do you suppose it should be tested?

I think the original code is too loose on diagnosing errors. Perhaps something like this is needed.

diffcore-order.c +4 -1
index 23e9385..dd103e3 100644
@@ -20,8 +20,11 @@ static void prepare_order(const char *orderfile)
 		return;
 
 	fd = open(orderfile, O_RDONLY);
-	if (fd < 0)
+	if (fd < 0) {
+		if (errno != ENOENT || errno != ENOTDIR)
+			die(_("orderfile '%s' does not exist."));
 		return;
+	}
 	if (fstat(fd, &st)) {
 		close(fd);
 		return;
Quoted 5 lines

After having fixed this, will /dev/null still work everywhere, or will we want a new diff flag to unset the option? (I see that "git diff /dev/null some-file" works fine with msysgit, which doesn't seem to actually be linked with MSYS, but I don't know *why* it works, and I don't know what other non-POSIXoid ports exist.)

I *think* it should be OK to use "-O/dev/null" for that purpose, but the primary thing I was hinting at with the rhetoric question was that it probably needs to be documented there.

Quoted 7 lines

Also, I'm starting to wonder if I shouldn't split this into two patches:

1. diff: Add tests for -O flag
2. diff: Add diff.orderfile configuration variable

(If so, I would obviously want to rewrite the above test to avoid the configuration option.)

Surely, and thanks.

Quoted 5 lines
Quoted 2 lines
                EOF
                cat >order_file_2 <<-\EOF &&

I'd kind of prefer to keep a blank line between one EOF and the next cat, if that's okay with you.

Alright. Making it easier to spot the grouping, it would make it easier to read.

Quoted 7 lines
Quoted 3 lines

Quoting the EOF like the above will help the readers by signaling them that they do not have to wonder if there is some substitution going on in the here text.

Perhaps, but probably only after they've scrutinized their shell manuals to figure out what the - and the \ are for. (I had to check
two: dash(1) wasn't clear enough for me about the quoting ...)

Yes and no. The no primarily comes from that nobody will stay to be novice forever.

#7 lore raw

v3 cover diff: Add diff.orderfile configuration variable

In reply to Anders Waldenborg

The original purpose of this patch [series] was to allow specifying the "-O" option for "git diff" in the config, but I need help with the relative path handling [RFC 3].

It also added tests for "git diff -O", which I have split out because they are independantly useful [PATCH 1].

I also noticed that -O had terrible error handling and could only read mmappable files, so I fixed that [PATCH 2].

Samuel Bronson (3):
diff: Tests for "git diff -O"
diff: Let "git diff -O" read orderfile from any file, failing when
appropriate
diff: Add diff.orderfile configuration variable

 Documentation/diff-config.txt  |   5 ++
 Documentation/diff-options.txt |   3 ++
 diff.c                         |   5 ++
 diffcore-order.c               |  23 ++++-----
 t/t4056-diff-order.sh          | 105 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 126 insertions(+), 15 deletions(-)
 create mode 100755 t/t4056-diff-order.sh
Signature · 1 line
1.8.4.3
#8 lore raw

PATCH v3 1/3 diff: Tests for "git diff -O"

Heavily adapted from Anders' patch:
"diff: Add diff.orderfile configuration variable"

---
 t/t4056-diff-order.sh | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100755 t/t4056-diff-order.sh
t/t4056-diff-order.sh new file +72 -0
new file mode 100755
index 0000000..398b3f6
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='diff order'
+
+. ./test-lib.sh
+
+create_files () {
+	echo "$1" >a.h &&
+	echo "$1" >b.c &&
+	echo "$1" >c/Makefile &&
+	echo "$1" >d.txt &&
+	git add a.h b.c c/Makefile d.txt &&
+	git commit -m"$1"
+}
+
+test_expect_success 'setup' '
+	mkdir c &&
+	create_files 1 &&
+	create_files 2 &&
+
+	cat >order_file_1 <<-\EOF &&
+	*Makefile
+	*.txt
+	*.h
+	*
+	EOF
+
+	cat >order_file_2 <<-\EOF &&
+	*Makefile
+	*.h
+	*.c
+	*
+	EOF
+
+	cat >expect_none <<-\EOF &&
+	a.h
+	b.c
+	c/Makefile
+	d.txt
+	EOF
+
+	cat >expect_1 <<-\EOF &&
+	c/Makefile
+	d.txt
+	a.h
+	b.c
+	EOF
+
+	cat >expect_2 <<-\EOF &&
+	c/Makefile
+	a.h
+	b.c
+	d.txt
+	EOF
+
+	true	# end chain of &&
+'
+
+test_expect_success "no order (=tree object order)" '
+	git diff --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_none actual
+'
+
+for i in 1 2
+do
+	test_expect_success "orderfile using option ($i)" '
+	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
+done
+
+test_done
Signature · 1 line
1.8.4.3
#9 lore raw

PATCH v3 2/3 diff: Let "git diff -O" read orderfile from any file, failing when appropriate

In reply to Samuel Bronson

The -O flag really shouldn't silently fail to do anything when given a path that it can't read from.

However, it should be able to read from un-mappable files, such as pipes/fifos, /dev/null (as we document in the next patch), or in fact *any* empty file (since Linux 2.6.12). (Especially since we will be documenting "-O/dev/null" to override "diff.orderfile" when we add that.)

(Note: "-O/dev/null" did have the right effect, since the existing error handling essentially worked out to "silently ignore the orderfile".)

So lets toss all of that logic to get the file mmapped and just use strbuf_read_file() instead, which gives us decent error handling practically for free.

---
 diffcore-order.c      | 23 ++++++++---------------
 t/t4056-diff-order.sh | 23 +++++++++++++++++++++++
 2 files changed, 31 insertions(+), 15 deletions(-)
diffcore-order.c +8 -15
index 23e9385..a63f332 100644
@@ -10,28 +10,21 @@ static int order_cnt;
 
 static void prepare_order(const char *orderfile)
 {
-	int fd, cnt, pass;
+	int cnt, pass;
+	struct strbuf sb = STRBUF_INIT;
 	void *map;
 	char *cp, *endp;
-	struct stat st;
-	size_t sz;
+	ssize_t sz;
 
 	if (order)
 		return;
 
-	fd = open(orderfile, O_RDONLY);
-	if (fd < 0)
-		return;
-	if (fstat(fd, &st)) {
-		close(fd);
-		return;
-	}
-	sz = xsize_t(st.st_size);
-	map = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	close(fd);
-	if (map == MAP_FAILED)
-		return;
+	sz = strbuf_read_file(&sb, orderfile, 0);
+	if (sz < 0)
+		die_errno(_("failed to read orderfile '%s'"), orderfile);
+	map = strbuf_detach(&sb, NULL);
 	endp = (char *) map + sz;
+
 	for (pass = 0; pass < 2; pass++) {
 		cnt = 0;
 		cp = map;
t/t4056-diff-order.sh +23 -0
index 398b3f6..eb471e7 100755
@@ -61,12 +61,35 @@ test_expect_success "no order (=tree object order)" '
 	test_cmp expect_none actual
 '
 
+test_expect_success 'missing orderfile' '
+	rm -f bogus_file &&
+	test_must_fail git diff -Obogus_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'unreadable orderfile' '
+	touch unreadable_file &&
+	chmod -r unreadable_file &&
+	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'orderfile is a directory' '
+	test_must_fail git diff -O/ --name-only HEAD^..HEAD
+'
+
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
 	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '
+
+	test_expect_success PIPE "orderfile is fifo ($i)" '
+	rm -f order_fifo &&
+	mkfifo order_fifo &&
+	cat order_file_$i >order_fifo &
+	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
 done
 
 test_done
Signature · 1 line
1.8.4.3
#10 lore raw

Re: [PATCH v3 2/3] diff: Let "git diff -O" read orderfile from any file, failing when appropriate

Quoted 6 lines · Samuel Bronson

The -O flag really shouldn't silently fail to do anything when given a path that it can't read from.

However, it should be able to read from un-mappable files, such as pipes/fifos, /dev/null (as we document in the next patch), or in fact *any* empty file (since Linux 2.6.12).

Could you enlighten the commit log readers a bit better here? Those who know the change in 2.6.12 (i.e. "'mmapping with length 0 must fail', says SUSv3, so we fail") you have in mind would know what you mean by "in fact any empty file" even if you did not have "(since Linux 2.6.12)", but those who do not know it would not be helped with just "(since Linux 2.6.12)".

Quoted 9 lines

(Especially since we will be
documenting "-O/dev/null" to override "diff.orderfile" when we add that.)

(Note: "-O/dev/null" did have the right effect, since the existing error handling essentially worked out to "silently ignore the orderfile".)

So lets toss all of that logic to get the file mmapped and just use strbuf_read_file() instead, which gives us decent error handling practically for free.

Sounds good. In the longer term, we may want to move this file-scope static to per-infocation "struct diff_options" and clean up the storage used to hold the list of path patterns after we are done with the diff, but that is outside the scope of this series.

Thanks.

Quoted 87 lines
---
 diffcore-order.c      | 23 ++++++++---------------
 t/t4056-diff-order.sh | 23 +++++++++++++++++++++++
 2 files changed, 31 insertions(+), 15 deletions(-)
diffcore-order.c +8 -15
index 23e9385..a63f332 100644
@@ -10,28 +10,21 @@ static int order_cnt;
 
 static void prepare_order(const char *orderfile)
 {
-	int fd, cnt, pass;
+	int cnt, pass;
+	struct strbuf sb = STRBUF_INIT;
 	void *map;
 	char *cp, *endp;
-	struct stat st;
-	size_t sz;
+	ssize_t sz;
 
 	if (order)
 		return;
 
-	fd = open(orderfile, O_RDONLY);
-	if (fd < 0)
-		return;
-	if (fstat(fd, &st)) {
-		close(fd);
-		return;
-	}
-	sz = xsize_t(st.st_size);
-	map = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	close(fd);
-	if (map == MAP_FAILED)
-		return;
+	sz = strbuf_read_file(&sb, orderfile, 0);
+	if (sz < 0)
+		die_errno(_("failed to read orderfile '%s'"), orderfile);
+	map = strbuf_detach(&sb, NULL);
 	endp = (char *) map + sz;
+
 	for (pass = 0; pass < 2; pass++) {
 		cnt = 0;
 		cp = map;
t/t4056-diff-order.sh +23 -0
index 398b3f6..eb471e7 100755
@@ -61,12 +61,35 @@ test_expect_success "no order (=tree object order)" '
 	test_cmp expect_none actual
 '
 
+test_expect_success 'missing orderfile' '
+	rm -f bogus_file &&
+	test_must_fail git diff -Obogus_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'unreadable orderfile' '
+	touch unreadable_file &&
+	chmod -r unreadable_file &&
+	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'orderfile is a directory' '
+	test_must_fail git diff -O/ --name-only HEAD^..HEAD
+'
+
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
 	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '
+
+	test_expect_success PIPE "orderfile is fifo ($i)" '
+	rm -f order_fifo &&
+	mkfifo order_fifo &&
+	cat order_file_$i >order_fifo &
+	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
 done
 
 test_done
#11 lore raw

RFC v3 3/3 diff: Add diff.orderfile configuration variable

In reply to Samuel Bronson

diff.orderfile acts as a default for the -O command line option.

[sb: split up aw's original patch; reworked tests and docs]

[FIXME: Relative paths should presumably be interpreted relative to repository root; how should this be accomplished?]

---
 Documentation/diff-config.txt  |  5 +++++
 Documentation/diff-options.txt |  3 +++
 diff.c                         |  5 +++++
 t/t4056-diff-order.sh          | 10 ++++++++++
 4 files changed, 23 insertions(+)
Documentation/diff-config.txt +5 -0
index 223b931..f07b451 100644
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
 diff.noprefix::
 	If set, 'git diff' does not show any source or destination prefix.
 
+diff.orderfile::
+	File indicating how to order files within a diff, using
+	one shell glob pattern per line.
+	Can be overridden by the '-O' option to linkgit:git-diff[1].
+
 diff.renameLimit::
 	The number of files to consider when performing the copy/rename
 	detection; equivalent to the 'git diff' option '-l'.
Documentation/diff-options.txt +3 -0
index bbed2cd..9b37b2a 100644
@@ -432,6 +432,9 @@ endif::git-format-patch[]
 -O<orderfile>::
 	Output the patch in the order specified in the
 	<orderfile>, which has one shell glob pattern per line.
+	This overrides the `diff.orderfile` configuration variable
+	(see linkgit:git-config[1]).  To cancel `diff.orderfile`,
+	use `-O/dev/null`.
 
 ifndef::git-format-patch[]
 -R::
diff.c +5 -0
index 3950e01..b336aef 100644
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
 static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
 		return git_config_string(&external_diff_cmd_cfg, var, value);
 	if (!strcmp(var, "diff.wordregex"))
 		return git_config_string(&diff_word_regex_cfg, var, value);
+	if (!strcmp(var, "diff.orderfile"))
+		return git_config_string(&diff_order_file_cfg, var, value);
 
 	if (!strcmp(var, "diff.ignoresubmodules"))
 		handle_ignore_submodules_arg(&default_diff_options, value);
@@ -3207,6 +3210,8 @@ void diff_setup(struct diff_options *options)
 	options->detect_rename = diff_detect_rename_default;
 	options->xdl_opts |= diff_algorithm;
 
+	options->orderfile = diff_order_file_cfg;
+
 	if (diff_no_prefix) {
 		options->a_prefix = options->b_prefix = "";
 	} else if (!diff_mnemonic_prefix) {
t/t4056-diff-order.sh +10 -0
index eb471e7..50689d1 100755
@@ -90,6 +90,16 @@ do
 	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '
+
+	test_expect_success "orderfile using config ($i)" '
+	git -c diff.orderfile=order_file_$i diff --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
+
+	test_expect_success "cancelling configured orderfile ($i)" '
+	git -c diff.orderfile=order_file_$i diff -O/dev/null --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_none actual
+'
 done
 
 test_done
Signature · 1 line
1.8.4.3
#12 lore raw
Quoted 6 lines · Samuel Bronson

diff.orderfile acts as a default for the -O command line option.

[sb: split up aw's original patch; reworked tests and docs]

[FIXME: Relative paths should presumably be interpreted relative to repository root; how should this be accomplished?]

Do you mean something like this?

    $ cd docs
    $ edit orderfile
    $ git diff -Oordefile
    $ cd subdir
    $ git diff -O../orderfile

Path-like parameters and values given by the end user should be relative to the directory where the end user is (i.e. both -O parameters in the above example name docs/orderfile). All Git processes, even the ones that are capable of being run from a subdirectory, are supposed to first chdir to the top level of the working tree before doing anything else, and adjust the path-like things they get from the end user from the command line accordingly. By the time diffcore_order() to prepare_order() callchain is called, we certainly should have passed that chdir already, so the value of the option needs to be prepended with the "prefix" when parsed.

The value specified for the diff.orderfile configuration can just be a path relative to the top level of the working tree, I think.

#13 lore raw
Quoted 13 lines · Junio C Hamano

Samuel Bronson <[email protected]> writes:

Path-like parameters and values given by the end user should be relative to the directory where the end user is (i.e. both -O parameters in the above example name docs/orderfile). All Git processes, even the ones that are capable of being run from a subdirectory, are supposed to first chdir to the top level of the working tree before doing anything else, and adjust the path-like things they get from the end user from the command line accordingly. By the time diffcore_order() to prepare_order() callchain is called, we certainly should have passed that chdir already, so the value of the option needs to be prepended with the "prefix" when parsed.

Quoted 2 lines

The value specified for the diff.orderfile configuration can just be a path relative to the top level of the working tree, I think.

Oh, cool. So I'll just change the git_config_string() call to use git_config_pathname(), since the user might easily want to use ~ notation there, especially in a user-level setting ...

#14 lore raw

v4 cover diff: Add diff.orderfile configuration variable

In reply to Anders Waldenborg

The original purpose of this patch [series] was to allow specifying the "-O" option for "git diff" in the config.

In this version, I've revised the commit message for patch 2, changed patch 3 to use git_config_pathname() instead of git_config_string(), and removed the FIXME from patch 3's commit message.

Samuel Bronson (3):
diff: Tests for "git diff -O"
diff: Let "git diff -O" read orderfile from any file, fail properly
diff: Add diff.orderfile configuration variable

 Documentation/diff-config.txt  |   5 ++
 Documentation/diff-options.txt |   3 ++
 diff.c                         |   5 ++
 diffcore-order.c               |  23 ++++-----
 t/t4056-diff-order.sh          | 105 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 126 insertions(+), 15 deletions(-)
 create mode 100755 t/t4056-diff-order.sh
Signature · 1 line
1.8.4.3
#15 lore raw

PATCH v4 1/3 diff: Tests for "git diff -O"

Heavily adapted from Anders' patch:
"diff: Add diff.orderfile configuration variable"

---
 t/t4056-diff-order.sh | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100755 t/t4056-diff-order.sh
t/t4056-diff-order.sh new file +72 -0
new file mode 100755
index 0000000..398b3f6
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='diff order'
+
+. ./test-lib.sh
+
+create_files () {
+	echo "$1" >a.h &&
+	echo "$1" >b.c &&
+	echo "$1" >c/Makefile &&
+	echo "$1" >d.txt &&
+	git add a.h b.c c/Makefile d.txt &&
+	git commit -m"$1"
+}
+
+test_expect_success 'setup' '
+	mkdir c &&
+	create_files 1 &&
+	create_files 2 &&
+
+	cat >order_file_1 <<-\EOF &&
+	*Makefile
+	*.txt
+	*.h
+	*
+	EOF
+
+	cat >order_file_2 <<-\EOF &&
+	*Makefile
+	*.h
+	*.c
+	*
+	EOF
+
+	cat >expect_none <<-\EOF &&
+	a.h
+	b.c
+	c/Makefile
+	d.txt
+	EOF
+
+	cat >expect_1 <<-\EOF &&
+	c/Makefile
+	d.txt
+	a.h
+	b.c
+	EOF
+
+	cat >expect_2 <<-\EOF &&
+	c/Makefile
+	a.h
+	b.c
+	d.txt
+	EOF
+
+	true	# end chain of &&
+'
+
+test_expect_success "no order (=tree object order)" '
+	git diff --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_none actual
+'
+
+for i in 1 2
+do
+	test_expect_success "orderfile using option ($i)" '
+	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
+done
+
+test_done
Signature · 1 line
1.8.4.3
#16 lore raw

PATCH v4 2/3 diff: Let "git diff -O" read orderfile from any file, fail properly

In reply to Samuel Bronson

The -O flag really shouldn't silently fail to do anything when given a path that it can't read from.

However, it should be able to read from un-mmappable files, such as:

* pipes/fifos

* /dev/null: It's a character device (at least on Linux)

* ANY empty file:

Quoting Linux mmap(2), "SUSv3 specifies that mmap() should fail if length is 0. However, in kernels before 2.6.12, mmap() succeeded in this case: no mapping was created and the call returned addr. Since kernel 2.6.12, mmap() fails with the error EINVAL for this case."

We especially want "-O/dev/null" to work, since we will be documenting it as the way to cancel "diff.orderfile" when we add that.

(Note: "-O/dev/null" did have the right effect, since the existing error handling essentially worked out to "silently ignore the orderfile". But this was probably more coincidence than anything else.)

So, lets toss all of that logic to get the file mmapped and just use strbuf_read_file() instead, which gives us decent error handling practically for free.

---
 diffcore-order.c      | 23 ++++++++---------------
 t/t4056-diff-order.sh | 23 +++++++++++++++++++++++
 2 files changed, 31 insertions(+), 15 deletions(-)
diffcore-order.c +8 -15
index 23e9385..a63f332 100644
@@ -10,28 +10,21 @@ static int order_cnt;
 
 static void prepare_order(const char *orderfile)
 {
-	int fd, cnt, pass;
+	int cnt, pass;
+	struct strbuf sb = STRBUF_INIT;
 	void *map;
 	char *cp, *endp;
-	struct stat st;
-	size_t sz;
+	ssize_t sz;
 
 	if (order)
 		return;
 
-	fd = open(orderfile, O_RDONLY);
-	if (fd < 0)
-		return;
-	if (fstat(fd, &st)) {
-		close(fd);
-		return;
-	}
-	sz = xsize_t(st.st_size);
-	map = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	close(fd);
-	if (map == MAP_FAILED)
-		return;
+	sz = strbuf_read_file(&sb, orderfile, 0);
+	if (sz < 0)
+		die_errno(_("failed to read orderfile '%s'"), orderfile);
+	map = strbuf_detach(&sb, NULL);
 	endp = (char *) map + sz;
+
 	for (pass = 0; pass < 2; pass++) {
 		cnt = 0;
 		cp = map;
t/t4056-diff-order.sh +23 -0
index 398b3f6..eb471e7 100755
@@ -61,12 +61,35 @@ test_expect_success "no order (=tree object order)" '
 	test_cmp expect_none actual
 '
 
+test_expect_success 'missing orderfile' '
+	rm -f bogus_file &&
+	test_must_fail git diff -Obogus_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'unreadable orderfile' '
+	touch unreadable_file &&
+	chmod -r unreadable_file &&
+	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'orderfile is a directory' '
+	test_must_fail git diff -O/ --name-only HEAD^..HEAD
+'
+
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
 	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '
+
+	test_expect_success PIPE "orderfile is fifo ($i)" '
+	rm -f order_fifo &&
+	mkfifo order_fifo &&
+	cat order_file_$i >order_fifo &
+	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
 done
 
 test_done
Signature · 1 line
1.8.4.3
#17 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 6 lines · Samuel Bronson
t/t4056-diff-order.sh +0 -0
index 398b3f6..eb471e7 100755
@@ -61,12 +61,35 @@ test_expect_success "no order (=tree object order)" '
 	test_cmp expect_none actual

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" ' · line 71

Quoted 10 lines
t/t4056-diff-order.sh +8 -0
 '
 
+test_expect_success 'missing orderfile' '
+	rm -f bogus_file &&
+	test_must_fail git diff -Obogus_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'unreadable orderfile' '
+	touch unreadable_file &&
+	chmod -r unreadable_file &&

Two points:

- Unless your primary interest is to change the file timestamp, do not use "touch"; using ">unreadable_file" or something instead would tell the readers that you only want to make sure it exists and do not care about the file timestamp.

- this test probably needs restricted to people with sane filesystems; I think POSIXPERM prerequisite and also SANITY prerequisite are needed, at least.

Quoted 24 lines
t/t4056-diff-order.sh +15 -0
+	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'orderfile is a directory' '
+	test_must_fail git diff -O/ --name-only HEAD^..HEAD
+'
+
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
 	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '
+
+	test_expect_success PIPE "orderfile is fifo ($i)" '
+	rm -f order_fifo &&
+	mkfifo order_fifo &&
+	cat order_file_$i >order_fifo &
+	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
 done
 
 test_done
#18 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 9 lines · Junio C Hamano

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" ' · line 71

Quoted 3 lines · Samuel Bronson
t/t4056-diff-order.sh +3 -0
+test_expect_success 'unreadable orderfile' '
+     touch unreadable_file &&
+     chmod -r unreadable_file &&

- this test probably needs restricted to people with sane filesystems; I think POSIXPERM prerequisite and also SANITY prerequisite are needed, at least.

Hmm, yeah, you've got a point; now that I think more carefully, the most FAT can do is something like "chmod -w", nothing with the "r" permissions. Oops.

#19 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

In reply to Samuel Bronson

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" ' · line 84

Quoted 6 lines · Samuel Bronson

for i in 1 2
do

t/t4056-diff-order.sh +0 -0
 	test_expect_success "orderfile using option ($i)" '
 	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '

This funny indentation in the previous step needs to be fixed, and the added block below should match.

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" '

Quoted 7 lines
t/t4056-diff-order.sh +6 -0
+
+	test_expect_success PIPE "orderfile is fifo ($i)" '
+	rm -f order_fifo &&
 
+	mkfifo order_fifo &&
+	cat order_file_$i >order_fifo &
+	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&

I think this part can be racy depending on which between cat and "git diff" are scheduled first, no? Try running this test under load and I think you will see it deadlocked.

Besides, the above breaks && chain; even if mkfifo breaks (hence not allowing cat to run), "git diff" will go ahead and run, no?

Quoted 5 lines
t/t4056-diff-order.sh +2 -0
+	test_cmp expect_$i actual
+'
 done
 
 test_done
#20 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 11 lines · Junio C Hamano
Quoted 6 lines · Samuel Bronson

for i in 1 2
do
test_expect_success "orderfile using option ($i)" ' git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual && test_cmp expect_$i actual
'

This funny indentation in the previous step needs to be fixed, and the added block below should match.

Even though this results in oddly-indented --verbose output?

Quoted 11 lines

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" ' · line 90

Quoted 4 lines
t/t4056-diff-order.sh +4 -0
+     rm -f order_fifo &&
+     mkfifo order_fifo &&
+     cat order_file_$i >order_fifo &
+     git diff -O order_fifo --name-only HEAD^..HEAD >actual &&

I think this part can be racy depending on which between cat and "git diff" are scheduled first, no? Try running this test under load and I think you will see it deadlocked.

Besides, the above breaks && chain; even if mkfifo breaks (hence not allowing cat to run), "git diff" will go ahead and run, no?

Hmm. Well, what I really wanted to put here was a "process substitution":

    git diff -O <(cat order_file_$i) --name-only HEAD^..HEAD >actual &&

but I did not see this feature listed in the dash(1) manpage, so I assumed it wasn't allowed by POSIX. And, having looked, I indeed don't see it mentioned in POSIX either.

I'm not terribly surprised that I screwed up the translation to FIFOs; how would I really want to do it?

#21 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 29 lines · Samuel Bronson
Quoted 11 lines · Junio C Hamano
Quoted 6 lines · Samuel Bronson

for i in 1 2
do
test_expect_success "orderfile using option ($i)" ' git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual && test_cmp expect_$i actual
'

This funny indentation in the previous step needs to be fixed, and the added block below should match.

Even though this results in oddly-indented --verbose output?

Quoted 11 lines

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" ' · line 90

Quoted 4 lines
t/t4056-diff-order.sh +4 -0
+     rm -f order_fifo &&
+     mkfifo order_fifo &&
+     cat order_file_$i >order_fifo &
+     git diff -O order_fifo --name-only HEAD^..HEAD >actual &&

I think this part can be racy depending on which between cat and "git diff" are scheduled first, no? Try running this test under load and I think you will see it deadlocked.

Besides, the above breaks && chain; even if mkfifo breaks (hence not allowing cat to run), "git diff" will go ahead and run, no?

Hmm. Well, what I really wanted to put here was a "process substitution":

Quoted 8 lines
    git diff -O <(cat order_file_$i) --name-only HEAD^..HEAD >actual &&

but I did not see this feature listed in the dash(1) manpage, so I assumed it wasn't allowed by POSIX. And, having looked, I indeed don't see it mentioned in POSIX either.

I'm not terribly surprised that I screwed up the translation to FIFOs; how would I really want to do it?

How about not doing a fifo?

#22 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 33 lines · Junio C Hamano
Quoted 31 lines · Samuel Bronson
Quoted 11 lines · Junio C Hamano
Quoted 6 lines · Samuel Bronson

for i in 1 2
do
test_expect_success "orderfile using option ($i)" ' git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual && test_cmp expect_$i actual
'

This funny indentation in the previous step needs to be fixed, and the added block below should match.

Even though this results in oddly-indented --verbose output?

Quoted 11 lines

t/t4056-diff-order.sh test_expect_success "no order (=tree object order)" ' · line 90

Quoted 4 lines
t/t4056-diff-order.sh +4 -0
+     rm -f order_fifo &&
+     mkfifo order_fifo &&
+     cat order_file_$i >order_fifo &
+     git diff -O order_fifo --name-only HEAD^..HEAD >actual &&

I think this part can be racy depending on which between cat and "git diff" are scheduled first, no? Try running this test under load and I think you will see it deadlocked.

Besides, the above breaks && chain; even if mkfifo breaks (hence not allowing cat to run), "git diff" will go ahead and run, no?

Hmm. Well, what I really wanted to put here was a "process substitution":

    git diff -O <(cat order_file_$i) --name-only HEAD^..HEAD >actual &&
Quoted 8 lines
Quoted 6 lines

but I did not see this feature listed in the dash(1) manpage, so I assumed it wasn't allowed by POSIX. And, having looked, I indeed don't see it mentioned in POSIX either.

I'm not terribly surprised that I screwed up the translation to FIFOs; how would I really want to do it?

How about not doing a fifo?

That would certainly defeat the purpose of the test, which is to test against a fifo :-)
I'm not sure about the deadlock though. Both read and write will wait for each other to start operating on the fifo.

You can probably fix the &&-chain by doing something like:

    mkfifo order_fifo && {
        cat order_file_$i >order_fifo &
        git diff -O order_fifo --name-only HEAD^..HEAD >actual
    } && ...

Also, "rm -f order_fifo" should probably be done in test_when_finished rather than at the beginning of the test.

Antoine,

#23 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 4 lines · Antoine Pelisse
Quoted 1 line

How about not doing a fifo?

That would certainly defeat the purpose of the test, which is to test against a fifo :-)

My point was that I did not see much value in reading the orderfile data from anything but a file. At that point, you are not testing the "diff -O" orderfile option, but if strbuf_readline() reads from a non-regular file.

#24 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 4 lines · Junio C Hamano

My point was that I did not see much value in reading the orderfile data from anything but a file. At that point, you are not testing the "diff -O" orderfile option, but if strbuf_readline() reads from a non-regular file.

Oh, good point, now that you state it explicitly. I'll remove it.

#25 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

Quoted 7 lines · Samuel Bronson
Quoted 4 lines · Junio C Hamano

My point was that I did not see much value in reading the orderfile data from anything but a file. At that point, you are not testing the "diff -O" orderfile option, but if strbuf_readline() reads from a non-regular file.

Oh, good point, now that you state it explicitly. I'll remove it.

Or you can study the fix-up I (tentatively) queued on top of your series in 'pu'. Also see $gmane/239409.

Thanks.

24331790 (FIXUP! tests, 2013-12-17)

t/t4056-diff-order.sh +18 -17
index f906dea..db0e427 100755
@@ -22,14 +22,12 @@ test_expect_success 'setup' '
 	*Makefile
 	*.txt
 	*.h
-	*
 	EOF
 
 	cat >order_file_2 <<-\EOF &&
 	*Makefile
 	*.h
 	*.c
-	*
 	EOF
 
 	cat >expect_none <<-\EOF &&
@@ -77,27 +75,30 @@ test_expect_success 'orderfile is a directory' '
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
-	git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
-	test_cmp expect_$i actual
-'
+		git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
+		test_cmp expect_$i actual
+	'
 
 	test_expect_success PIPE "orderfile is fifo ($i)" '
-	rm -f order_fifo &&
-	mkfifo order_fifo &&
-	cat order_file_$i >order_fifo &
-	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
-	test_cmp expect_$i actual
-'
+		rm -f order_fifo &&
+		mkfifo order_fifo &&
+		{
+			cat order_file_$i >order_fifo &
+		} &&
+		git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
+		wait &&
+		test_cmp expect_$i actual
+	'
 
 	test_expect_success "orderfile using config ($i)" '
-	git -c diff.orderfile=order_file_$i diff --name-only HEAD^..HEAD >actual &&
-	test_cmp expect_$i actual
-'
+		git -c diff.orderfile=order_file_$i diff --name-only HEAD^..HEAD >actual &&
+		test_cmp expect_$i actual
+	'
 
 	test_expect_success "cancelling configured orderfile ($i)" '
-	git -c diff.orderfile=order_file_$i diff -O/dev/null --name-only HEAD^..HEAD >actual &&
-	test_cmp expect_none actual
-'
+		git -c diff.orderfile=order_file_$i diff -O/dev/null --name-only HEAD^..HEAD >actual &&
+		test_cmp expect_none actual
+	'
 done
 
 test_done
Signature · 1 line
1.8.5.2-297-g3e57c29
#26 lore raw

Re: [PATCH v4 2/3] diff: Let "git diff -O" read orderfile from any file, fail properly

In reply to Antoine Pelisse
Quoted 2 lines · Antoine Pelisse

I'm not sure about the deadlock though. Both read and write will wait for each other to start operating on the fifo.

It is true only if the fifo already exists. That is, if you did this:

	a lot of &&
        commands &&
        before &&
        mkfifo fifo &&
        feed >fifo &

	git diff -Ofifo

the consumer may attempt to open and read fifo when the other process is still running a lot of commands, no?

Quoted 12 lines

You can probably fix the &&-chain by doing something like:

    mkfifo order_fifo && {
        cat order_file_$i >order_fifo &
        git diff -O order_fifo --name-only HEAD^..HEAD >actual
    } && ...

Also, "rm -f order_fifo" should probably be done in test_when_finished rather than at the beginning of the test.

Antoine,

#27 lore raw

PATCH v4 3/3 diff: Add diff.orderfile configuration variable

In reply to Samuel Bronson

diff.orderfile acts as a default for the -O command line option.

[sb: split up aw's original patch; reworked tests and docs, treat option as pathname]

---
 Documentation/diff-config.txt  |  5 +++++
 Documentation/diff-options.txt |  3 +++
 diff.c                         |  5 +++++
 t/t4056-diff-order.sh          | 10 ++++++++++
 4 files changed, 23 insertions(+)
Documentation/diff-config.txt +5 -0
index 223b931..f07b451 100644
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
 diff.noprefix::
 	If set, 'git diff' does not show any source or destination prefix.
 
+diff.orderfile::
+	File indicating how to order files within a diff, using
+	one shell glob pattern per line.
+	Can be overridden by the '-O' option to linkgit:git-diff[1].
+
 diff.renameLimit::
 	The number of files to consider when performing the copy/rename
 	detection; equivalent to the 'git diff' option '-l'.
Documentation/diff-options.txt +3 -0
index bbed2cd..9b37b2a 100644
@@ -432,6 +432,9 @@ endif::git-format-patch[]
 -O<orderfile>::
 	Output the patch in the order specified in the
 	<orderfile>, which has one shell glob pattern per line.
+	This overrides the `diff.orderfile` configuration variable
+	(see linkgit:git-config[1]).  To cancel `diff.orderfile`,
+	use `-O/dev/null`.
 
 ifndef::git-format-patch[]
 -R::
diff.c +5 -0
index 3950e01..0099b99 100644
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
 static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
 		return git_config_string(&external_diff_cmd_cfg, var, value);
 	if (!strcmp(var, "diff.wordregex"))
 		return git_config_string(&diff_word_regex_cfg, var, value);
+	if (!strcmp(var, "diff.orderfile"))
+		return git_config_pathname(&diff_order_file_cfg, var, value);
 
 	if (!strcmp(var, "diff.ignoresubmodules"))
 		handle_ignore_submodules_arg(&default_diff_options, value);
@@ -3207,6 +3210,8 @@ void diff_setup(struct diff_options *options)
 	options->detect_rename = diff_detect_rename_default;
 	options->xdl_opts |= diff_algorithm;
 
+	options->orderfile = diff_order_file_cfg;
+
 	if (diff_no_prefix) {
 		options->a_prefix = options->b_prefix = "";
 	} else if (!diff_mnemonic_prefix) {
t/t4056-diff-order.sh +10 -0
index eb471e7..50689d1 100755
@@ -90,6 +90,16 @@ do
 	git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
 	test_cmp expect_$i actual
 '
+
+	test_expect_success "orderfile using config ($i)" '
+	git -c diff.orderfile=order_file_$i diff --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_$i actual
+'
+
+	test_expect_success "cancelling configured orderfile ($i)" '
+	git -c diff.orderfile=order_file_$i diff -O/dev/null --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_none actual
+'
 done
 
 test_done
Signature · 1 line
1.8.4.3
#28 lore raw

v5 cover diff: Add diff.orderfile configuration variable

In reply to Anders Waldenborg

I expect you've figured out what this patch series is about by now. In this version, I've applied Junio's suggestions from the last version, and also the stuff from the FIXUP commit he made after my stuff in the branch he merged into 'pu'.

Samuel Bronson (3):
diff: Tests for "git diff -O"
diff: Let "git diff -O" read orderfile from any file, fail properly
diff: Add diff.orderfile configuration variable

 Documentation/diff-config.txt  |   5 ++
 Documentation/diff-options.txt |   3 ++
 diff.c                         |   5 ++
 diffcore-order.c               |  23 ++++-----
 t/t4056-diff-order.sh          | 106 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 127 insertions(+), 15 deletions(-)
 create mode 100755 t/t4056-diff-order.sh
Signature · 1 line
1.8.4.3
#29 lore raw

PATCH v5 1/3 diff: Tests for "git diff -O"

Heavily adapted from Anders' patch:
"diff: Add diff.orderfile configuration variable"

---
 t/t4056-diff-order.sh | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100755 t/t4056-diff-order.sh
t/t4056-diff-order.sh new file +70 -0
new file mode 100755
index 0000000..218f171
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+test_description='diff order'
+
+. ./test-lib.sh
+
+create_files () {
+	echo "$1" >a.h &&
+	echo "$1" >b.c &&
+	echo "$1" >c/Makefile &&
+	echo "$1" >d.txt &&
+	git add a.h b.c c/Makefile d.txt &&
+	git commit -m"$1"
+}
+
+test_expect_success 'setup' '
+	mkdir c &&
+	create_files 1 &&
+	create_files 2 &&
+
+	cat >order_file_1 <<-\EOF &&
+	*Makefile
+	*.txt
+	*.h
+	EOF
+
+	cat >order_file_2 <<-\EOF &&
+	*Makefile
+	*.h
+	*.c
+	EOF
+
+	cat >expect_none <<-\EOF &&
+	a.h
+	b.c
+	c/Makefile
+	d.txt
+	EOF
+
+	cat >expect_1 <<-\EOF &&
+	c/Makefile
+	d.txt
+	a.h
+	b.c
+	EOF
+
+	cat >expect_2 <<-\EOF &&
+	c/Makefile
+	a.h
+	b.c
+	d.txt
+	EOF
+
+	true	# end chain of &&
+'
+
+test_expect_success "no order (=tree object order)" '
+	git diff --name-only HEAD^..HEAD >actual &&
+	test_cmp expect_none actual
+'
+
+for i in 1 2
+do
+	test_expect_success "orderfile using option ($i)" '
+		git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
+		test_cmp expect_$i actual
+	'
+done
+
+test_done
Signature · 1 line
1.8.4.3
#30 lore raw

PATCH v5 2/3 diff: Let "git diff -O" read orderfile from any file, fail properly

In reply to Samuel Bronson

The -O flag really shouldn't silently fail to do anything when given a path that it can't read from.

However, it should be able to read from un-mmappable files, such as:

* pipes/fifos

* /dev/null: It's a character device (at least on Linux)

* ANY empty file:

Quoting Linux mmap(2), "SUSv3 specifies that mmap() should fail if length is 0. However, in kernels before 2.6.12, mmap() succeeded in this case: no mapping was created and the call returned addr. Since kernel 2.6.12, mmap() fails with the error EINVAL for this case."

We especially want "-O/dev/null" to work, since we will be documenting it as the way to cancel "diff.orderfile" when we add that.

(Note: "-O/dev/null" did have the right effect, since the existing error handling essentially worked out to "silently ignore the orderfile". But this was probably more coincidence than anything else.)

So, lets toss all of that logic to get the file mmapped and just use strbuf_read_file() instead, which gives us decent error handling practically for free.

---
 diffcore-order.c      | 23 ++++++++---------------
 t/t4056-diff-order.sh | 26 ++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 15 deletions(-)
diffcore-order.c +8 -15
index 23e9385..a63f332 100644
@@ -10,28 +10,21 @@ static int order_cnt;
 
 static void prepare_order(const char *orderfile)
 {
-	int fd, cnt, pass;
+	int cnt, pass;
+	struct strbuf sb = STRBUF_INIT;
 	void *map;
 	char *cp, *endp;
-	struct stat st;
-	size_t sz;
+	ssize_t sz;
 
 	if (order)
 		return;
 
-	fd = open(orderfile, O_RDONLY);
-	if (fd < 0)
-		return;
-	if (fstat(fd, &st)) {
-		close(fd);
-		return;
-	}
-	sz = xsize_t(st.st_size);
-	map = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	close(fd);
-	if (map == MAP_FAILED)
-		return;
+	sz = strbuf_read_file(&sb, orderfile, 0);
+	if (sz < 0)
+		die_errno(_("failed to read orderfile '%s'"), orderfile);
+	map = strbuf_detach(&sb, NULL);
 	endp = (char *) map + sz;
+
 	for (pass = 0; pass < 2; pass++) {
 		cnt = 0;
 		cp = map;
t/t4056-diff-order.sh +26 -0
index 218f171..0ac1b95 100755
@@ -59,12 +59,38 @@ test_expect_success "no order (=tree object order)" '
 	test_cmp expect_none actual
 '
 
+test_expect_success 'missing orderfile' '
+	rm -f bogus_file &&
+	test_must_fail git diff -Obogus_file --name-only HEAD^..HEAD
+'
+
+test_expect_success POSIXPERM,SANITY 'unreadable orderfile' '
+	>unreadable_file &&
+	chmod -r unreadable_file &&
+	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
+'
+
+test_expect_success 'orderfile is a directory' '
+	test_must_fail git diff -O/ --name-only HEAD^..HEAD
+'
+
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
 		git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual &&
 		test_cmp expect_$i actual
 	'
+
+	test_expect_success PIPE "orderfile is fifo ($i)" '
+		rm -f order_fifo &&
+		mkfifo order_fifo &&
+		{
+			cat order_file_$i >order_fifo &
+		} &&
+		git diff -O order_fifo --name-only HEAD^..HEAD >actual &&
+		wait &&
+		test_cmp expect_$i actual
+	'
 done
 
 test_done
Signature · 1 line
1.8.4.3
#31 lore raw

PATCH 1/1 diff test: reading a directory as a file need not error out

There is no guarantee that strbuf_read_file must error out for directories. On some operating systems (e.g., Debian GNU/kFreeBSD wheezy), reading a directory gives its raw content:

	$ head -c5 < / | cat -A
	^AM-|^_^@^L$

As a result, 'git diff -O/' succeeds instead of erroring out on these systems, causing t4056.5 "orderfile is a directory" to fail.

On some weird OS it might even make sense to pass a directory to the -O option and this is not a common user mistake that needs catching. Remove the test.

---
Hi,

t4056 is failing on systems using glibc with the kernel of FreeBSD[1]:

| expecting success: 
| 	test_must_fail git diff -O/ --name-only HEAD^..HEAD
|
| a.h
| b.c
| c/Makefile
| d.txt
| test_must_fail: command succeeded: git diff -O/ --name-only HEAD^..HEAD
| not ok 5 - orderfile is a directory

How about this patch?

Thanks,
Jonathan

[1] https://buildd.debian.org/status/fetch.php?pkg=git&arch=kfreebsd-amd64&ver=1%3A2.0~next.20140107-1&stamp=1389379274

 t/t4056-diff-order.sh | 4 ----
 1 file changed, 4 deletions(-)
t/t4056-diff-order.sh +0 -4
index 1ddd226..9e2b29e 100755
@@ -68,10 +68,6 @@ test_expect_success POSIXPERM,SANITY 'unreadable orderfile' '
 	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
 '
 
-test_expect_success 'orderfile is a directory' '
-	test_must_fail git diff -O/ --name-only HEAD^..HEAD
-'
-
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
Signature · 1 line
1.8.5.1
#32 lore raw

Re: [PATCH sb/diff-orderfile-config] diff test: reading a directory as a file need not error out

Quoted 30 lines · Jonathan Nieder

There is no guarantee that strbuf_read_file must error out for directories. On some operating systems (e.g., Debian GNU/kFreeBSD wheezy), reading a directory gives its raw content:

	$ head -c5 < / | cat -A
	^AM-|^_^@^L$

As a result, 'git diff -O/' succeeds instead of erroring out on these systems, causing t4056.5 "orderfile is a directory" to fail.

On some weird OS it might even make sense to pass a directory to the -O option and this is not a common user mistake that needs catching. Remove the test.

---
Hi,

t4056 is failing on systems using glibc with the kernel of FreeBSD[1]:

| expecting success: 
| 	test_must_fail git diff -O/ --name-only HEAD^..HEAD
|
| a.h
| b.c
| c/Makefile
| d.txt
| test_must_fail: command succeeded: git diff -O/ --name-only HEAD^..HEAD
| not ok 5 - orderfile is a directory
Quoted 1 line

How about this patch?

Sounds sensible. Thanks.

Quoted 23 lines

Thanks,
Jonathan

[1] https://buildd.debian.org/status/fetch.php?pkg=git&arch=kfreebsd-amd64&ver=1%3A2.0~next.20140107-1&stamp=1389379274

 t/t4056-diff-order.sh | 4 ----
 1 file changed, 4 deletions(-)
t/t4056-diff-order.sh +0 -4
index 1ddd226..9e2b29e 100755
@@ -68,10 +68,6 @@ test_expect_success POSIXPERM,SANITY 'unreadable orderfile' '
 	test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
 '
 
-test_expect_success 'orderfile is a directory' '
-	test_must_fail git diff -O/ --name-only HEAD^..HEAD
-'
-
 for i in 1 2
 do
 	test_expect_success "orderfile using option ($i)" '
#33 lore raw

PATCH v5 3/3 diff: Add diff.orderfile configuration variable

In reply to Samuel Bronson

diff.orderfile acts as a default for the -O command line option.

[sb: split up aw's original patch; rework tests and docs, treat option as pathname]

---
 Documentation/diff-config.txt  |  5 +++++
 Documentation/diff-options.txt |  3 +++
 diff.c                         |  5 +++++
 t/t4056-diff-order.sh          | 10 ++++++++++
 4 files changed, 23 insertions(+)
Documentation/diff-config.txt +5 -0
index 223b931..f07b451 100644
@@ -98,6 +98,11 @@ diff.mnemonicprefix::
 diff.noprefix::
 	If set, 'git diff' does not show any source or destination prefix.
 
+diff.orderfile::
+	File indicating how to order files within a diff, using
+	one shell glob pattern per line.
+	Can be overridden by the '-O' option to linkgit:git-diff[1].
+
 diff.renameLimit::
 	The number of files to consider when performing the copy/rename
 	detection; equivalent to the 'git diff' option '-l'.
Documentation/diff-options.txt +3 -0
index bbed2cd..9b37b2a 100644
@@ -432,6 +432,9 @@ endif::git-format-patch[]
 -O<orderfile>::
 	Output the patch in the order specified in the
 	<orderfile>, which has one shell glob pattern per line.
+	This overrides the `diff.orderfile` configuration variable
+	(see linkgit:git-config[1]).  To cancel `diff.orderfile`,
+	use `-O/dev/null`.
 
 ifndef::git-format-patch[]
 -R::
diff.c +5 -0
index b79432b..f35c83b 100644
@@ -30,6 +30,7 @@ static int diff_use_color_default = -1;
 static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
+static const char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
@@ -201,6 +202,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
 		return git_config_string(&external_diff_cmd_cfg, var, value);
 	if (!strcmp(var, "diff.wordregex"))
 		return git_config_string(&diff_word_regex_cfg, var, value);
+	if (!strcmp(var, "diff.orderfile"))
+		return git_config_pathname(&diff_order_file_cfg, var, value);
 
 	if (!strcmp(var, "diff.ignoresubmodules"))
 		handle_ignore_submodules_arg(&default_diff_options, value);
@@ -3207,6 +3210,8 @@ void diff_setup(struct diff_options *options)
 	options->detect_rename = diff_detect_rename_default;
 	options->xdl_opts |= diff_algorithm;
 
+	options->orderfile = diff_order_file_cfg;
+
 	if (diff_no_prefix) {
 		options->a_prefix = options->b_prefix = "";
 	} else if (!diff_mnemonic_prefix) {
t/t4056-diff-order.sh +10 -0
index 0ac1b95..acd7683 100755
@@ -91,6 +91,16 @@ do
 		wait &&
 		test_cmp expect_$i actual
 	'
+
+	test_expect_success "orderfile using config ($i)" '
+		git -c diff.orderfile=order_file_$i diff --name-only HEAD^..HEAD >actual &&
+		test_cmp expect_$i actual
+	'
+
+	test_expect_success "cancelling configured orderfile ($i)" '
+		git -c diff.orderfile=order_file_$i diff -O/dev/null --name-only HEAD^..HEAD >actual &&
+		test_cmp expect_none actual
+	'
 done
 
 test_done
Signature · 1 line
1.8.4.3