git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] Allow git-diff exit with codes similar to diff(1)

From
Alex Riesen <raa.lkml@gmail.com>
Date
Mar 14, 2007, 00:17 UTC
Message-ID
<81b0412b0703131717k7106ee1cg964628f0bda2c83e@mail.gmail.com>

This introduces a new command-line option: --exit-code. The diff programs will return 1 for differences, return 0 for equality, and something else for errors.

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
Still working on my e-mail problems. Sorry for duplications.

As promised on irc. I'm somewhat confused about diff_tree: it used to unconditionally return 0, yet every caller of it saves and passes the value!

 Documentation/diff-options.txt |    5 ++++
 builtin-diff-tree.c            |   12 +++++----
 builtin-diff.c                 |    5 ++-
 diff-lib.c                     |   12 +++++++--
 diff.c                         |    2 +
 diff.h                         |    3 +-
 t/t4017-diff-retval.sh         |   51 ++++++++++++++++++++++++++++++++++++++++
 tree-diff.c                    |   11 +++++++-
 8 files changed, 88 insertions(+), 13 deletions(-)
 create mode 100755 t/t4017-diff-retval.sh
From 2309f82f88274a0ddac0d5b06c5df580f5cb7d81 Mon Sep 17 00:00:00 2001
From: Alex Riesen <raa.lkml@gmail.com>
Date: Tue, 13 Mar 2007 18:06:08 +0100
Subject: [PATCH] Allow git-diff exit with codes similar to diff(1)

This introduces a new command-line option: --exit-code. The diff programs will return 1 for differences, return 0 for equality, and something else for errors.

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
 Documentation/diff-options.txt |    5 ++++
 builtin-diff-tree.c            |   12 +++++----
 builtin-diff.c                 |    5 ++-
 diff-lib.c                     |   12 +++++++--
 diff.c                         |    2 +
 diff.h                         |    3 +-
 t/t4017-diff-retval.sh         |   51 ++++++++++++++++++++++++++++++++++++++++
 tree-diff.c                    |   11 +++++++-
 8 files changed, 88 insertions(+), 13 deletions(-)
 create mode 100755 t/t4017-diff-retval.sh
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index d8696b7..77a3f78 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -159,5 +159,10 @@
 -w::
 	Shorthand for "--ignore-all-space".
 
+--exit-code::
+	Make the program exit with codes similar to diff(1).
+	That is, it exits with 1 if there were differences and
+	0 means no differences.
+
 For more detailed explanation on these common options, see also
 link:diffcore.html[diffcore documentation].
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 24cb2d7..d293a5e 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -61,6 +61,7 @@ COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 {
+	int result = 0;
 	int nr_sha1;
 	char line[1000];
 	struct object *tree1, *tree2;
@@ -110,7 +111,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 			tree2 = tree1;
 			tree1 = tmp;
 		}
-		diff_tree_sha1(tree1->sha1,
+		result = diff_tree_sha1(tree1->sha1,
 			       tree2->sha1,
 			       "", &opt->diffopt);
 		log_tree_diff_flush(opt);
@@ -118,7 +119,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 	}
 
 	if (!read_stdin)
-		return 0;
+		return opt->diffopt.diff_exit_code ? result: 0;
 
 	if (opt->diffopt.detect_rename)
 		opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
@@ -130,8 +131,9 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 			fputs(line, stdout);
 			fflush(stdout);
 		}
-		else
-			diff_tree_stdin(line);
+		else if (diff_tree_stdin(line)) {
+			result = 1;
+		}
 	}
-	return 0;
+	return opt->diffopt.diff_exit_code ? result: 0;
 }
diff --git a/builtin-diff.c b/builtin-diff.c
index 4efbb82..5e6265f 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -130,6 +130,7 @@ static int builtin_diff_tree(struct rev_info *revs,
 {
 	const unsigned char *(sha1[2]);
 	int swap = 0;
+	int result = 0;
 
 	if (argc > 1)
 		usage(builtin_diff_usage);
@@ -141,9 +142,9 @@ static int builtin_diff_tree(struct rev_info *revs,
 		swap = 1;
 	sha1[swap] = ent[0].item->sha1;
 	sha1[1-swap] = ent[1].item->sha1;
-	diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
+	result = diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
 	log_tree_diff_flush(revs);
-	return 0;
+	return result;
 }
 
 static int builtin_diff_combined(struct rev_info *revs,
diff --git a/diff-lib.c b/diff-lib.c
index 6abb981..f943b6f 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -170,8 +170,10 @@ static int handle_diff_files_args(struct rev_info *revs,
 		else if (!strcmp(argv[1], "--theirs"))
 			revs->max_count = 3;
 		else if (!strcmp(argv[1], "-n") ||
-				!strcmp(argv[1], "--no-index"))
+				!strcmp(argv[1], "--no-index")) {
 			revs->max_count = -2;
+			revs->diffopt.diff_exit_code = 1;
+		}
 		else if (!strcmp(argv[1], "-q"))
 			*silent = 1;
 		else
@@ -237,6 +239,7 @@ int setup_diff_no_index(struct rev_info *revs,
 			break;
 		} else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
 			i = argc - 3;
+			revs->diffopt.diff_exit_code = 1;
 			break;
 		}
 	if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
@@ -309,6 +312,7 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
 
 int run_diff_files(struct rev_info *revs, int silent_on_removed)
 {
+	int result = 0;
 	int entries, i;
 	int diff_unmerged_stage = revs->max_count;
 
@@ -433,8 +437,9 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
 
 	}
 	diffcore_std(&revs->diffopt);
+	result = revs->diffopt.diff_exit_code && diff_queued_diff.nr ? 1: 0;
 	diff_flush(&revs->diffopt);
-	return 0;
+	return result;
 }
 
 /*
@@ -664,9 +669,10 @@ int run_diff_index(struct rev_info *revs, int cached)
 		return error("bad tree object %s", tree_name);
 	if (read_tree(tree, 1, revs->prune_data))
 		return error("unable to read tree object %s", tree_name);
-	ret = diff_cache(revs, active_cache, active_nr, revs->prune_data,
+	diff_cache(revs, active_cache, active_nr, revs->prune_data,
 			 cached, match_missing);
 	diffcore_std(&revs->diffopt);
+	ret = revs->diffopt.diff_exit_code && diff_queued_diff.nr ? 1: 0;
 	diff_flush(&revs->diffopt);
 	return ret;
 }
diff --git a/diff.c b/diff.c
index 954ca83..e2f91ed 100644
--- a/diff.c
+++ b/diff.c
@@ -2134,6 +2134,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 		options->color_diff = options->color_diff_words = 1;
 	else if (!strcmp(arg, "--no-renames"))
 		options->detect_rename = 0;
+	else if (!strcmp(arg, "--exit-code"))
+		options->diff_exit_code = 1;
 	else
 		return 0;
 	return 1;
diff --git a/diff.h b/diff.h
index 4b435e8..cea61b5 100644
--- a/diff.h
+++ b/diff.h
@@ -56,7 +56,8 @@ struct diff_options {
 		 silent_on_remove:1,
 		 find_copies_harder:1,
 		 color_diff:1,
-		 color_diff_words:1;
+		 color_diff_words:1,
+		 diff_exit_code:1;
 	int context;
 	int break_opt;
 	int detect_rename;
diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh
new file mode 100755
index 0000000..81a9393
--- /dev/null
+++ b/t/t4017-diff-retval.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='Return value of diffs'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	echo 1 >a &&
+	git add . &&
+	git commit -m first &&
+	echo 2 >b &&
+	git add . &&
+	git commit -a -m second
+'
+
+test_expect_failure 'git diff-tree HEAD^ HEAD' '
+	git diff-tree --exit-code HEAD^ HEAD
+'
+test_expect_failure 'echo HEAD | git diff-tree --stdin' '
+	echo $(git rev-parse HEAD) | git diff-tree --exit-code --stdin
+'
+test_expect_success 'git diff-tree HEAD HEAD' '
+	git diff-tree --exit-code HEAD HEAD
+'
+
+test_expect_success 'git diff-files' '
+	git diff-files --exit-code
+'
+
+test_expect_success 'git diff-index --cached HEAD' '
+	git diff-index --exit-code --cached HEAD
+'
+test_expect_failure 'git diff-index --cached HEAD^' '
+	git diff-index --exit-code --cached HEAD^
+'
+test_expect_failure 'git diff-index --cached HEAD^' '
+	echo 3 >c &&
+	git add . &&
+	git diff-index --exit-code --cached HEAD^
+'
+git commit -m 'third' >/dev/null
+test_expect_failure 'git diff-files' '
+	echo 3 >>c &&
+	git diff-files --exit-code
+'
+test_expect_failure 'git diff-index --cached HEAD' '
+	git update-index c &&
+	git diff-index --exit-code --cached HEAD
+'
+
+test_done
diff --git a/tree-diff.c b/tree-diff.c
index c827582..47c516f 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -160,6 +160,8 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
 
 int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
 {
+	int result = 0;
+
 	while (t1->size | t2->size) {
 		if (opt->nr_paths && t1->size && !interesting(t1, base, opt)) {
 			update_tree_entry(t1);
@@ -170,29 +172,34 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
 			continue;
 		}
 		if (!t1->size) {
+			result = 1;
 			show_entry(opt, "+", t2, base);
 			update_tree_entry(t2);
 			continue;
 		}
 		if (!t2->size) {
+			result = 1;
 			show_entry(opt, "-", t1, base);
 			update_tree_entry(t1);
 			continue;
 		}
 		switch (compare_tree_entry(t1, t2, base, opt)) {
 		case -1:
+			result = 1;
 			update_tree_entry(t1);
 			continue;
 		case 0:
 			update_tree_entry(t1);
-			/* Fallthrough */
+			update_tree_entry(t2);
+			continue;
 		case 1:
+			result = 1;
 			update_tree_entry(t2);
 			continue;
 		}
 		die("git-diff-tree: internal error");
 	}
-	return 0;
+	return opt->diff_exit_code ? result: 0;
 }
 
 int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)
-- 
1.5.0.3.545.g5d3ba
Next: Johannes Schindelin
Message 1 of 32 in “Allow git-diff exit with codes similar to diff(1)”
  1. Allow git-diff exit with codes similar to diff(1)Alex Riesen, Mar 14, 2007
  2. Johannes SchindelinMar 14, 2007
  3. Linus TorvaldsMar 14, 2007
  4. Junio C HamanoMar 14, 2007
  5. Linus TorvaldsMar 14, 2007
  6. Johannes SchindelinMar 14, 2007
  7. Linus TorvaldsMar 14, 2007
  8. Johannes SchindelinMar 14, 2007
  9. Alex RiesenMar 14, 2007
  10. Johannes SchindelinMar 14, 2007
  11. Alex RiesenMar 14, 2007
  12. Johannes SchindelinMar 14, 2007
  13. Simon 'corecode' SchubertMar 15, 2007
  14. Alex RiesenMar 15, 2007
  15. Junio C HamanoMar 14, 2007
  16. Alex RiesenMar 14, 2007
  17. Junio C HamanoMar 14, 2007
  18. Junio C HamanoMar 14, 2007
  19. Alex RiesenMar 14, 2007
  20. Junio C HamanoMar 14, 2007
  21. Alex RiesenMar 14, 2007
  22. Junio C HamanoMar 14, 2007
  23. Alex RiesenMar 14, 2007
  24. Junio C HamanoMar 14, 2007
  25. Allow git-diff exit with codes similar to diff(1)Alex Riesen, Mar 14, 2007
  26. Junio C HamanoMar 14, 2007
  27. Alex RiesenMar 14, 2007
  28. Junio C HamanoMar 14, 2007
  29. Allow git-diff exit with codes similar to diff(1)Alex Riesen, Mar 14, 2007
  30. Junio C HamanoMar 14, 2007
  31. Junio C HamanoMar 14, 2007
  32. Alex RiesenMar 14, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.