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

Re: [PATCH 1/2] difftool: add the builtin

From
David Aguilar <davvid@gmail.com>
Date
Nov 23, 2016, 08:08 UTC
Message-ID
<20161123080850.GA23742@gmail.com>
In-Reply-To
<7aec571e1b0773ca80ea25453d2650af6a18e095.1479834051.git.johannes.schindelin@gmx.de>
On Tue, Nov 22, 2016 at 06:01:23PM +0100, Johannes Schindelin wrote:
Show 10 quoted lines
> This adds a builtin difftool that represents a conversion of the current
> Perl script version of the difftool.
> 
> The motivation is that Perl scripts are not at all native on Windows,
> and that `git difftool` therefore is pretty slow on that platform, when
> there is no good reason for it to be slow.
> 
> In addition, Perl does not really have access to Git's internals. That
> means that any script will always have to jump through unnecessary
> hoops.
Nice!
Show 9 quoted lines
> The current version of the builtin difftool does not, however, make full
> use of the internals but instead chooses to spawn a couple of Git
> processes, still, to make for an easier conversion. There remains a lot
> of room for improvement, left for a later date.
> 
> Note: the original difftool is still called by `git difftool`. To get the
> new, experimental version, call `git builtin-difftool`. The reason: this
> new, experimental, builtin difftool will be shipped as part of Git for
> Windows v2.11.0, to allow for easier large-scale testing.

I like this plan. I was going to ask for an environment variable (to preset in git-cola) but since Git for Windows is handling it then everyone benefits.

Show 34 quoted lines
> diff --git a/builtin/builtin-difftool.c b/builtin/builtin-difftool.c
> new file mode 100644
> index 0000000..9feefcd
> --- /dev/null
> +++ b/builtin/builtin-difftool.c
> @@ -0,0 +1,680 @@
> +/*
> + * "git difftool" builtin command
> + *
> + * This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
> + * git-difftool--helper script.
> + *
> + * This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
> + * The GIT_DIFF* variables are exported for use by git-difftool--helper.
> + *
> + * Any arguments that are unknown to this script are forwarded to 'git diff'.
> + *
> + * Copyright (C) 2016 Johannes Schindelin
> + */
> +#include "cache.h"
> +#include "builtin.h"
> +#include "parse-options.h"
> +#include "run-command.h"
> +#include "argv-array.h"
> +#include "strbuf.h"
> +#include "lockfile.h"
> +
> +static char *diff_gui_tool;
> +static int trust_exit_code;
> +
> +static const char * const builtin_difftool_usage[] = {
> +	N_("git add [<options>] [--] <pathspec>..."),
> +	NULL
> +};
The usage should probably say "difftool" (or "builtin-difftool").
Show 8 quoted lines
> [...]
> +static void changed_files(struct hashmap *result, const char *index_path,
> +			  const char *workdir)
> +{
> +[...]
> +}
> +
> +#include "dir.h"
Can this mid-file #include go to the top of the file?
Show 32 quoted lines
> +static int run_dir_diff(const char *extcmd, int symlinks,
> +			int argc, const char **argv)
> +{
> +	char tmpdir[PATH_MAX];
> +	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
> +	struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;
> +	struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
> +	struct strbuf wtdir = STRBUF_INIT;
> +	size_t ldir_len, rdir_len, wtdir_len;
> +	struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1);
> +	const char *workdir, *tmp;
> +	int ret = 0, i;
> +	FILE *fp;
> +	struct hashmap working_tree_dups, submodules, symlinks2;
> +	struct hashmap_iter iter;
> +	struct pair_entry *entry;
> +	enum object_type type;
> +	unsigned long size;
> +	struct index_state wtindex;
> +	struct checkout lstate, rstate;
> +	int rc, flags = RUN_GIT_CMD, err = 0;
> +	struct child_process child = CHILD_PROCESS_INIT;
> +	const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL };
> +	struct hashmap wt_modified, tmp_modified;
> +	int indices_loaded = 0;
> +
> +	setup_work_tree();
> +	workdir = get_git_work_tree();
> +
> +	/* Setup temp directories */
> +	tmp = getenv("TMPDIR");
> +	sprintf(tmpdir, "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp");
Maybe snprintf instead?

getenv() won't return anything longer than PATH_MAX for most users, but users are weird.

> +	if (!mkdtemp(tmpdir))
> +		return error("could not create temporary directory");
Mention the tmpdir here?
Show 7 quoted lines
> +	strbuf_addf(&ldir, "%s/left/", tmpdir);
> +	strbuf_addf(&rdir, "%s/right/", tmpdir);
> +	strbuf_addstr(&wtdir, workdir);
> +	if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1]))
> +		strbuf_addch(&wtdir, '/');
> +	mkdir(ldir.buf, 0777);
> +	mkdir(rdir.buf, 0777);

Seeing the perl mkpath() default 0777 spelled out this way makes me wonder whether 0700 would be safer.

The mkdtemp() above is already using 0700 so it's ok, but it might be worth making it consistent (later, perhaps).

Show 69 quoted lines
> [...]
> +int cmd_builtin_difftool(int argc, const char ** argv, const char * prefix)
> +{
> +	int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0,
> +	    tool_help = 0;
> +	static char *difftool_cmd = NULL, *extcmd = NULL;
> +
> +	struct option builtin_difftool_options[] = {
> +		OPT_BOOL('g', "gui", &use_gui_tool,
> +			 N_("use `diff.guitool` instead of `diff.tool`")),
> +		OPT_BOOL('d', "dir-diff", &dir_diff,
> +			 N_("perform a full-directory diff")),
> +		{ OPTION_SET_INT, 'y', "no-prompt", &prompt, NULL,
> +			N_("do not prompt before launching a diff tool"),
> +			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
> +		{ OPTION_SET_INT, 0, "prompt", &prompt, NULL, NULL,
> +			PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN,
> +			NULL, 1 },
> +		OPT_BOOL(0, "symlinks", &symlinks,
> +			 N_("use symlinks in dir-diff mode")),
> +		OPT_STRING('t', "tool", &difftool_cmd, N_("<tool>"),
> +			   N_("use the specified diff tool")),
> +		OPT_BOOL(0, "tool-help", &tool_help,
> +			 N_("print a list of diff tools that may be used with "
> +			    "`--tool`")),
> +		OPT_BOOL(0, "trust-exit-code", &trust_exit_code,
> +			 N_("make 'git-difftool' exit when an invoked diff "
> +			    "tool returns a non - zero exit code")),
> +		OPT_STRING('x', "extcmd", &extcmd, N_("<command>"),
> +			   N_("specify a custom command for viewing diffs")),
> +		OPT_END()
> +	};
> +
> +	symlinks = has_symlinks;
> +
> +	git_config(difftool_config, NULL);
> +
> +	argc = parse_options(argc, argv, prefix, builtin_difftool_options,
> +			     builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
> +			     PARSE_OPT_KEEP_DASHDASH);
> +
> +	if (tool_help)
> +		return print_tool_help();
> +
> +	if (use_gui_tool && diff_gui_tool && *diff_gui_tool)
> +		setenv("GIT_DIFF_TOOL", diff_gui_tool, 1);
> +	else if (difftool_cmd) {
> +		if (*difftool_cmd)
> +			setenv("GIT_DIFF_TOOL", difftool_cmd, 1);
> +		else
> +			die(_("no <tool> given for --tool=<tool>"));
> +	}
> +
> +	if (extcmd) {
> +		if (*extcmd)
> +			setenv("GIT_DIFFTOOL_EXTCMD", extcmd, 1);
> +		else
> +			die(_("no <cmd> given for --extcmd=<cmd>"));
> +	}
> +
> +	setenv("GIT_DIFFTOOL_TRUST_EXIT_CODE",
> +	       trust_exit_code ? "true" : "false", 1);
> +
> +	/*
> +	 * In directory diff mode, 'git-difftool--helper' is called once
> +	 * to compare the a / b directories.In file diff mode, 'git diff'
> +	 * will invoke a separate instance of 'git-difftool--helper' for
> +	 * each file that changed.
> +	 */
Missing space after "." in the comment above.
Show 16 quoted lines
> +	if (dir_diff)
> +		return run_dir_diff(extcmd, symlinks, argc, argv);
> +	return run_file_diff(prompt, argc, argv);
> +}
> diff --git a/git.c b/git.c
> index efa1059..eaa0f67 100644
> --- a/git.c
> +++ b/git.c
> @@ -424,6 +424,7 @@ static struct cmd_struct commands[] = {
>  	{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
>  	{ "diff-index", cmd_diff_index, RUN_SETUP },
>  	{ "diff-tree", cmd_diff_tree, RUN_SETUP },
> +	{ "builtin-difftool", cmd_builtin_difftool, RUN_SETUP | NEED_WORK_TREE },
>  	{ "fast-export", cmd_fast_export, RUN_SETUP },
>  	{ "fetch", cmd_fetch, RUN_SETUP },
>  	{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },

This isn't alphabetical anymore, but it actually is if you consider that the final plan is to change "builtin-difftool" to "difftool".

If we want to minimize that future diff we could name cmd_builtin_difftool() as cmd_difftool() for consistency now so that the future commit only needs to tweak the string here.

-- 
David
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 3 of 86 in “Show Git Mailing List: a builtin difftool”
  1. 0/2 Show Git Mailing List: a builtin difftoolJohannes Schindelin, Nov 22, 2016
  2. 1/2 difftool: add the builtinJohannes Schindelin, Nov 22, 2016
  3. David AguilarNov 23, 2016
  4. Johannes SchindelinNov 23, 2016
  5. 2/2 difftool: add a feature flag for the builtin vs scripted versionJohannes Schindelin, Nov 22, 2016
  6. Dennis KaarsemakerNov 23, 2016
  7. Johannes SchindelinNov 23, 2016
  8. Junio C HamanoNov 23, 2016
  9. Junio C HamanoNov 23, 2016
  10. Johannes SchindelinNov 23, 2016
  11. Junio C HamanoNov 23, 2016
  12. Johannes SchindelinNov 23, 2016
  13. 0/1 Show Git Mailing List: a builtin difftoolJohannes Schindelin, Nov 23, 2016
  14. 1/1 difftool: add the builtinJohannes Schindelin, Nov 23, 2016
  15. Junio C HamanoNov 23, 2016
  16. Junio C HamanoNov 23, 2016
  17. Johannes SchindelinNov 24, 2016
  18. 0/2 Show Git Mailing List: a builtin difftoolJohannes Schindelin, Nov 24, 2016
  19. 1/2 difftool: add a skeleton for the upcoming builtinJohannes Schindelin, Nov 24, 2016
  20. Jeff KingNov 24, 2016
  21. Johannes SchindelinNov 24, 2016
  22. Jeff KingNov 25, 2016
  23. Johannes SchindelinNov 25, 2016
  24. Jeff KingNov 25, 2016
  25. Johannes SchindelinNov 25, 2016
  26. Jeff KingNov 25, 2016
  27. Johannes SchindelinNov 26, 2016
  28. Jeff KingNov 26, 2016
  29. Johannes SchindelinNov 26, 2016
  30. Jeff KingNov 27, 2016
  31. Junio C HamanoNov 28, 2016
  32. Johannes SchindelinNov 28, 2016
  33. Junio C HamanoNov 28, 2016
  34. Johannes SchindelinNov 29, 2016
  35. Jeff KingNov 29, 2016
  36. Johannes SchindelinNov 30, 2016
  37. Jeff KingNov 30, 2016
  38. Junio C HamanoNov 29, 2016
  39. Johannes SchindelinNov 30, 2016
  40. Junio C HamanoDec 1, 2016
  41. Johannes SchindelinDec 5, 2016
  42. Junio C HamanoDec 5, 2016
  43. Johannes SchindelinDec 6, 2016
  44. Jeff KingDec 6, 2016
  45. Johannes SchindelinDec 6, 2016
  46. Jeff KingDec 6, 2016
  47. Stefan BellerDec 6, 2016
  48. Jeff KingDec 6, 2016
  49. Brandon WilliamsJan 18, 2017
  50. Jakub NarębskiNov 30, 2016
  51. Junio C HamanoNov 30, 2016
  52. 2/2 difftool: implement the functionality in the builtinJohannes Schindelin, Nov 24, 2016
  53. Jakub NarębskiNov 25, 2016
  54. Johannes SchindelinNov 27, 2016
  55. Jakub NarębskiNov 27, 2016
  56. 0/4 Show Git Mailing List: a builtin difftoolJohannes Schindelin, Jan 2, 2017
  57. 2/4 difftool: add a skeleton for the upcoming builtinJohannes Schindelin, Jan 2, 2017
  58. 3/4 difftool: implement the functionality in the builtinJohannes Schindelin, Jan 2, 2017
  59. 1/4 Avoid Coverity warning about unfree()d git_exec_path()Johannes Schindelin, Jan 2, 2017
  60. Stefan BellerJan 3, 2017
  61. Jeff KingJan 4, 2017
  62. Johannes SchindelinJan 3, 2017
  63. Stefan BellerJan 4, 2017
  64. Junio C HamanoJan 9, 2017
  65. Jeff KingJan 9, 2017
  66. Johannes SchindelinJan 9, 2017
  67. Stefan BellerJan 9, 2017
  68. 4/4 t7800: run both builtin and scripted difftool, for nowJohannes Schindelin, Jan 2, 2017
  69. Junio C HamanoJan 9, 2017
  70. Johannes SchindelinJan 9, 2017
  71. Junio C HamanoJan 9, 2017
  72. 0/3 Turn the difftool into a builtinJohannes Schindelin, Jan 17, 2017
  73. 3/3 Retire the scripted difftoolJohannes Schindelin, Jan 17, 2017
  74. Junio C HamanoJan 17, 2017
  75. Johannes SchindelinJan 18, 2017
  76. Junio C HamanoJan 18, 2017
  77. Johannes SchindelinJan 19, 2017
  78. Junio C HamanoJan 19, 2017
  79. Johannes SchindelinJan 19, 2017
  80. 1/3 difftool: add a skeleton for the upcoming builtinJohannes Schindelin, Jan 17, 2017
  81. 2/3 difftool: implement the functionality in the builtinJohannes Schindelin, Jan 17, 2017
  82. Junio C HamanoJan 17, 2017
  83. 0/3 Turn the difftool into a builtinJohannes Schindelin, Jan 19, 2017
  84. 1/3 difftool: add a skeleton for the upcoming builtinJohannes Schindelin, Jan 19, 2017
  85. 2/3 difftool: implement the functionality in the builtinJohannes Schindelin, Jan 19, 2017
  86. 3/3 Retire the scripted difftoolJohannes Schindelin, Jan 19, 2017

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.