{"thread":{"id":"56618","subject":"[PATCH v7 0/4] difftool: dir-diff improvements and refactoring","startedAt":"2021-10-01T01:38:02Z","lastAt":"2021-10-01T01:38:09Z","messageCount":5,"participants":["David Aguilar"],"isPatch":true,"patchVersion":7,"patchTotal":4},"messages":[{"id":"437591","messageId":"20211001013756.37586-1-davvid@gmail.com","threadId":"56618","inReplyTo":null,"subject":"[PATCH v7 0/4] difftool: dir-diff improvements and refactoring","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2021-10-01T01:37:52Z","receivedAt":"2021-10-01T01:38:02Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Changes since v6:\n\n- avoid returning -1 to cmd_main() by adjusting the return site in\n  \"create a tmpdir path without repeated slashes\".\n\n- \"refactor dir-diff to write files using helper functions\" was\n  reworked to add two helper functions instead of one so that the\n  common checks for *entry->{left,right} can be handled in a single place.\n\n- write_entry() was renamed to write_file_in_directory() and its\n  signature was adjusted to match how write_file() takes its parameters.\n\n- write_file_in_directory() gets called from the newly added\n  write_standin_files() helper which encompases the guts of\n  the symlinks and submodules hashmap loops.\n\n- Comments were added describing the purpose of the helper functions.\n\nDavid Aguilar (4):\n  difftool: create a tmpdir path without repeated slashes\n  difftool: refactor dir-diff to write files using helper functions\n  difftool: remove an unnecessary call to strbuf_release()\n  difftool: add a missing space to the run_dir_diff() comments\n\n builtin/difftool.c  | 104 ++++++++++++++++++++++----------------------\n t/t7800-difftool.sh |   7 +++\n 2 files changed, 60 insertions(+), 51 deletions(-)\n\nRange-diff against v6:\n1:  121186ca0f ! 1:  14b5618945 difftool: create a tmpdir path without repeated slashes\n    @@ Commit message\n         Strip trailing slashes from the value read from TMPDIR to avoid\n         repeated slashes in the generated paths.\n     \n    -    Adjust the error handling to avoid leaking strbufs.\n    +    Adjust the error handling to avoid leaking strbufs and to avoid\n    +    returning -1 to cmd_main().\n     \n         Signed-off-by: David Aguilar <davvid@gmail.com>\n     \n    @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, co\n      \tstrbuf_release(&buf);\n     +\tstrbuf_release(&tmpdir);\n      \n    - \treturn ret;\n    +-\treturn ret;\n    ++\treturn (ret < 0) ? 1 : ret;\n      }\n    + \n    + static int run_file_diff(int prompt, const char *prefix,\n     \n      ## t/t7800-difftool.sh ##\n     @@ t/t7800-difftool.sh: run_dir_diff_test 'difftool --dir-diff' '\n4:  8e7d54616f ! 2:  0824321eb9 difftool: refactor dir-diff to write files using a helper function\n    @@ Metadata\n     Author: David Aguilar <davvid@gmail.com>\n     \n      ## Commit message ##\n    -    difftool: refactor dir-diff to write files using a helper function\n    +    difftool: refactor dir-diff to write files using helper functions\n     \n    -    Add a write_entry() helper function to handle the unlinking and writing\n    +    Add a helpers function to handle the unlinking and writing\n         of the dir-diff submodule and symlink stand-in files.\n     \n    -    Use write_entry() inside of the hashmap loops to eliminate duplicate\n    -    code and to safeguard the submodules hashmap loop against the\n    -    symlink-chasing behavior that 5bafb3576a (difftool: fix symlink-file\n    -    writing in dir-diff mode, 2021-09-22) addressed.\n    +    Use the helpers to implement the guts of the hashmap loops.\n    +    This eliminate duplicate code and safeguards the submodules\n    +    hashmap loop against the symlink-chasing behavior that 5bafb3576a\n    +    (difftool: fix symlink-file writing in dir-diff mode, 2021-09-22)\n    +    addressed.\n     \n         The submodules loop should not strictly require the unlink() call that\n         this is introducing to them, but it does not necessarily hurt them\n    @@ builtin/difftool.c: static int checkout_path(unsigned mode, struct object_id *oi\n      \treturn ret;\n      }\n      \n    -+static void write_entry(const char *path, const char *content,\n    -+\t\t\tstruct strbuf *buf, size_t len)\n    ++static void write_file_in_directory(struct strbuf *dir, size_t dir_len,\n    ++\t\t\tconst char *path, const char *content)\n     +{\n    -+\tif (!*content)\n    -+\t\treturn;\n    -+\tadd_path(buf, len, path);\n    -+\tensure_leading_directories(buf->buf);\n    -+\tunlink(buf->buf);\n    -+\twrite_file(buf->buf, \"%s\", content);\n    ++\tadd_path(dir, dir_len, path);\n    ++\tensure_leading_directories(dir->buf);\n    ++\tunlink(dir->buf);\n    ++\twrite_file(dir->buf, \"%s\", content);\n    ++}\n    ++\n    ++/* Write the file contents for the left and right sides of the difftool\n    ++ * dir-diff representation for submodules and symlinks. Symlinks and submodules\n    ++ * are written as regular text files so that external diff tools can diff them\n    ++ * as text files, resulting in behavior that is analogous to to what \"git diff\"\n    ++ * displays for symlink and submodule diffs.\n    ++ */\n    ++static void write_standin_files(struct pair_entry *entry,\n    ++\t\t\tstruct strbuf *ldir, size_t ldir_len,\n    ++\t\t\tstruct strbuf *rdir, size_t rdir_len)\n    ++{\n    ++\tif (*entry->left)\n    ++\t\twrite_file_in_directory(ldir, ldir_len, entry->path, entry->left);\n    ++\tif (*entry->right)\n    ++\t\twrite_file_in_directory(rdir, rdir_len, entry->path, entry->right);\n     +}\n     +\n      static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n    @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, co\n     -\t\t\tensure_leading_directories(rdir.buf);\n     -\t\t\twrite_file(rdir.buf, \"%s\", entry->right);\n     -\t\t}\n    -+\t\twrite_entry(entry->path, entry->left, &ldir, ldir_len);\n    -+\t\twrite_entry(entry->path, entry->right, &rdir, rdir_len);\n    ++\t\twrite_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);\n      \t}\n      \n      \t/*\n    @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, co\n     -\t\t\twrite_file(rdir.buf, \"%s\", entry->right);\n     -\t\t}\n     +\n    -+\t\twrite_entry(entry->path, entry->left, &ldir, ldir_len);\n    -+\t\twrite_entry(entry->path, entry->right, &rdir, rdir_len);\n    ++\t\twrite_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);\n      \t}\n      \n      \tstrbuf_release(&buf);\n5:  8db6ae3373 ! 3:  94ad86157e difftool: remove an unnecessary call to strbuf_release()\n    @@ Commit message\n     \n      ## builtin/difftool.c ##\n     @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n    - \t\twrite_entry(entry->path, entry->right, &rdir, rdir_len);\n    + \t\twrite_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);\n      \t}\n      \n     -\tstrbuf_release(&buf);\n2:  080a113917 = 4:  5b6dfe5e5c difftool: add a missing space to the run_dir_diff() comments\n3:  1fbc47a58d < -:  ---------- difftool: avoid returning -1 to cmd_main() from run_dir_diff()\n-- \n2.33.0.886.g5b6dfe5e5c\n\n"},{"id":"437592","messageId":"20211001013756.37586-2-davvid@gmail.com","threadId":"56618","inReplyTo":"20211001013756.37586-1-davvid@gmail.com","subject":"[PATCH v7 1/4] difftool: create a tmpdir path without repeated slashes","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2021-10-01T01:37:53Z","receivedAt":"2021-10-01T01:38:06Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"The paths generated by difftool are passed to user-facing diff tools.\nUsing paths with repeated slashes in them is a cosmetic blemish that\nis exposed to users and can be avoided.\n\nUse a strbuf to create the buffer used for the dir-diff tmpdir.\nStrip trailing slashes from the value read from TMPDIR to avoid\nrepeated slashes in the generated paths.\n\nAdjust the error handling to avoid leaking strbufs and to avoid\nreturning -1 to cmd_main().\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\n builtin/difftool.c  | 50 ++++++++++++++++++++++-----------------------\n t/t7800-difftool.sh |  7 +++++++\n 2 files changed, 31 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 210da03908..0e24421682 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -252,16 +252,6 @@ static void changed_files(struct hashmap *result, const char *index_path,\n \tstrbuf_release(&buf);\n }\n \n-static NORETURN void exit_cleanup(const char *tmpdir, int exit_code)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addstr(&buf, tmpdir);\n-\tremove_dir_recursively(&buf, 0);\n-\tif (exit_code)\n-\t\twarning(_(\"failed: %d\"), exit_code);\n-\texit(exit_code);\n-}\n-\n static int ensure_leading_directories(char *path)\n {\n \tswitch (safe_create_leading_directories(path)) {\n@@ -333,16 +323,16 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\tstruct child_process *child)\n {\n-\tchar tmpdir[PATH_MAX];\n \tstruct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;\n \tstruct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;\n \tstruct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;\n \tstruct strbuf wtdir = STRBUF_INIT;\n-\tchar *lbase_dir, *rbase_dir;\n+\tstruct strbuf tmpdir = STRBUF_INIT;\n+\tchar *lbase_dir = NULL, *rbase_dir = NULL;\n \tsize_t ldir_len, rdir_len, wtdir_len;\n \tconst char *workdir, *tmp;\n \tint ret = 0, i;\n-\tFILE *fp;\n+\tFILE *fp = NULL;\n \tstruct hashmap working_tree_dups = HASHMAP_INIT(working_tree_entry_cmp,\n \t\t\t\t\t\t\tNULL);\n \tstruct hashmap submodules = HASHMAP_INIT(pair_cmp, NULL);\n@@ -351,7 +341,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \tstruct pair_entry *entry;\n \tstruct index_state wtindex;\n \tstruct checkout lstate, rstate;\n-\tint rc, flags = RUN_GIT_CMD, err = 0;\n+\tint flags = RUN_GIT_CMD, err = 0;\n \tconst char *helper_argv[] = { \"difftool--helper\", NULL, NULL, NULL };\n \tstruct hashmap wt_modified, tmp_modified;\n \tint indices_loaded = 0;\n@@ -360,11 +350,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \n \t/* Setup temp directories */\n \ttmp = getenv(\"TMPDIR\");\n-\txsnprintf(tmpdir, sizeof(tmpdir), \"%s/git-difftool.XXXXXX\", tmp ? tmp : \"/tmp\");\n-\tif (!mkdtemp(tmpdir))\n-\t\treturn error(\"could not create '%s'\", tmpdir);\n-\tstrbuf_addf(&ldir, \"%s/left/\", tmpdir);\n-\tstrbuf_addf(&rdir, \"%s/right/\", tmpdir);\n+\tstrbuf_add_absolute_path(&tmpdir, tmp ? tmp : \"/tmp\");\n+\tstrbuf_trim_trailing_dir_sep(&tmpdir);\n+\tstrbuf_addstr(&tmpdir, \"/git-difftool.XXXXXX\");\n+\tif (!mkdtemp(tmpdir.buf)) {\n+\t\tret = error(\"could not create '%s'\", tmpdir.buf);\n+\t\tgoto finish;\n+\t}\n+\tstrbuf_addf(&ldir, \"%s/left/\", tmpdir.buf);\n+\tstrbuf_addf(&rdir, \"%s/right/\", tmpdir.buf);\n \tstrbuf_addstr(&wtdir, workdir);\n \tif (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1]))\n \t\tstrbuf_addch(&wtdir, '/');\n@@ -580,7 +574,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\tflags = 0;\n \t} else\n \t\tsetenv(\"GIT_DIFFTOOL_DIRDIFF\", \"true\", 1);\n-\trc = run_command_v_opt(helper_argv, flags);\n+\tret = run_command_v_opt(helper_argv, flags);\n \n \t/* TODO: audit for interaction with sparse-index. */\n \tensure_full_index(&wtindex);\n@@ -614,7 +608,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\tif (!indices_loaded) {\n \t\t\tstruct lock_file lock = LOCK_INIT;\n \t\t\tstrbuf_reset(&buf);\n-\t\t\tstrbuf_addf(&buf, \"%s/wtindex\", tmpdir);\n+\t\t\tstrbuf_addf(&buf, \"%s/wtindex\", tmpdir.buf);\n \t\t\tif (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||\n \t\t\t    write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {\n \t\t\t\tret = error(\"could not write %s\", buf.buf);\n@@ -644,11 +638,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t}\n \n \tif (err) {\n-\t\twarning(_(\"temporary files exist in '%s'.\"), tmpdir);\n+\t\twarning(_(\"temporary files exist in '%s'.\"), tmpdir.buf);\n \t\twarning(_(\"you may want to cleanup or recover these.\"));\n-\t\texit(1);\n-\t} else\n-\t\texit_cleanup(tmpdir, rc);\n+\t\tret = 1;\n+\t} else {\n+\t\tremove_dir_recursively(&tmpdir, 0);\n+\t\tif (ret)\n+\t\t\twarning(_(\"failed: %d\"), ret);\n+\t}\n \n finish:\n \tif (fp)\n@@ -660,8 +657,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \tstrbuf_release(&rdir);\n \tstrbuf_release(&wtdir);\n \tstrbuf_release(&buf);\n+\tstrbuf_release(&tmpdir);\n \n-\treturn ret;\n+\treturn (ret < 0) ? 1 : ret;\n }\n \n static int run_file_diff(int prompt, const char *prefix,\ndiff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh\nindex 528e0dabf0..096456292c 100755\n--- a/t/t7800-difftool.sh\n+++ b/t/t7800-difftool.sh\n@@ -453,6 +453,13 @@ run_dir_diff_test 'difftool --dir-diff' '\n \tgrep \"^file$\" output\n '\n \n+run_dir_diff_test 'difftool --dir-diff avoids repeated slashes in TMPDIR' '\n+\tTMPDIR=\"${TMPDIR:-/tmp}////\" \\\n+\t\tgit difftool --dir-diff $symlinks --extcmd echo branch >output &&\n+\tgrep -v // output >actual &&\n+\ttest_line_count = 1 actual\n+'\n+\n run_dir_diff_test 'difftool --dir-diff ignores --prompt' '\n \tgit difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&\n \tgrep \"^sub$\" output &&\n-- \n2.33.0.886.g5b6dfe5e5c\n\n"},{"id":"437593","messageId":"20211001013756.37586-3-davvid@gmail.com","threadId":"56618","inReplyTo":"20211001013756.37586-1-davvid@gmail.com","subject":"[PATCH v7 2/4] difftool: refactor dir-diff to write files using helper functions","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2021-10-01T01:37:54Z","receivedAt":"2021-10-01T01:38:07Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Add a helpers function to handle the unlinking and writing\nof the dir-diff submodule and symlink stand-in files.\n\nUse the helpers to implement the guts of the hashmap loops.\nThis eliminate duplicate code and safeguards the submodules\nhashmap loop against the symlink-chasing behavior that 5bafb3576a\n(difftool: fix symlink-file writing in dir-diff mode, 2021-09-22)\naddressed.\n\nThe submodules loop should not strictly require the unlink() call that\nthis is introducing to them, but it does not necessarily hurt them\neither beyond the cost of the extra unlink().\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\n builtin/difftool.c | 50 ++++++++++++++++++++++++++--------------------\n 1 file changed, 28 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 0e24421682..f3cd1e5b53 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -320,6 +320,31 @@ static int checkout_path(unsigned mode, struct object_id *oid,\n \treturn ret;\n }\n \n+static void write_file_in_directory(struct strbuf *dir, size_t dir_len,\n+\t\t\tconst char *path, const char *content)\n+{\n+\tadd_path(dir, dir_len, path);\n+\tensure_leading_directories(dir->buf);\n+\tunlink(dir->buf);\n+\twrite_file(dir->buf, \"%s\", content);\n+}\n+\n+/* Write the file contents for the left and right sides of the difftool\n+ * dir-diff representation for submodules and symlinks. Symlinks and submodules\n+ * are written as regular text files so that external diff tools can diff them\n+ * as text files, resulting in behavior that is analogous to to what \"git diff\"\n+ * displays for symlink and submodule diffs.\n+ */\n+static void write_standin_files(struct pair_entry *entry,\n+\t\t\tstruct strbuf *ldir, size_t ldir_len,\n+\t\t\tstruct strbuf *rdir, size_t rdir_len)\n+{\n+\tif (*entry->left)\n+\t\twrite_file_in_directory(ldir, ldir_len, entry->path, entry->left);\n+\tif (*entry->right)\n+\t\twrite_file_in_directory(rdir, rdir_len, entry->path, entry->right);\n+}\n+\n static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\t\tstruct child_process *child)\n {\n@@ -529,16 +554,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t */\n \thashmap_for_each_entry(&submodules, &iter, entry,\n \t\t\t\tentry /* member name */) {\n-\t\tif (*entry->left) {\n-\t\t\tadd_path(&ldir, ldir_len, entry->path);\n-\t\t\tensure_leading_directories(ldir.buf);\n-\t\t\twrite_file(ldir.buf, \"%s\", entry->left);\n-\t\t}\n-\t\tif (*entry->right) {\n-\t\t\tadd_path(&rdir, rdir_len, entry->path);\n-\t\t\tensure_leading_directories(rdir.buf);\n-\t\t\twrite_file(rdir.buf, \"%s\", entry->right);\n-\t\t}\n+\t\twrite_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);\n \t}\n \n \t/*\n@@ -548,18 +564,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t */\n \thashmap_for_each_entry(&symlinks2, &iter, entry,\n \t\t\t\tentry /* member name */) {\n-\t\tif (*entry->left) {\n-\t\t\tadd_path(&ldir, ldir_len, entry->path);\n-\t\t\tensure_leading_directories(ldir.buf);\n-\t\t\tunlink(ldir.buf);\n-\t\t\twrite_file(ldir.buf, \"%s\", entry->left);\n-\t\t}\n-\t\tif (*entry->right) {\n-\t\t\tadd_path(&rdir, rdir_len, entry->path);\n-\t\t\tensure_leading_directories(rdir.buf);\n-\t\t\tunlink(rdir.buf);\n-\t\t\twrite_file(rdir.buf, \"%s\", entry->right);\n-\t\t}\n+\n+\t\twrite_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);\n \t}\n \n \tstrbuf_release(&buf);\n-- \n2.33.0.886.g5b6dfe5e5c\n\n"},{"id":"437594","messageId":"20211001013756.37586-4-davvid@gmail.com","threadId":"56618","inReplyTo":"20211001013756.37586-1-davvid@gmail.com","subject":"[PATCH v7 3/4] difftool: remove an unnecessary call to strbuf_release()","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2021-10-01T01:37:55Z","receivedAt":"2021-10-01T01:38:08Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"The `buf` strbuf is reused again later in the same function, so there\nis no benefit to calling strbuf_release(). The subsequent usage is\nalready using strbuf_reset() to reset the buffer, so releasing it\nearly is only going to lead to a wasteful reallocation.\n\nRemove the early call to strbuf_release(). The same strbuf is already\ncleaned up in the \"finish:\" section so nothing is leaked, either.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\n builtin/difftool.c | 2 --\n 1 file changed, 2 deletions(-)\n\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex f3cd1e5b53..437474fea0 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -568,8 +568,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t\twrite_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);\n \t}\n \n-\tstrbuf_release(&buf);\n-\n \tstrbuf_setlen(&ldir, ldir_len);\n \thelper_argv[1] = ldir.buf;\n \tstrbuf_setlen(&rdir, rdir_len);\n-- \n2.33.0.886.g5b6dfe5e5c\n\n"},{"id":"437595","messageId":"20211001013756.37586-5-davvid@gmail.com","threadId":"56618","inReplyTo":"20211001013756.37586-1-davvid@gmail.com","subject":"[PATCH v7 4/4] difftool: add a missing space to the run_dir_diff() comments","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2021-10-01T01:37:56Z","receivedAt":"2021-10-01T01:38:09Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Signed-off-by: David Aguilar <davvid@gmail.com>\n---\n builtin/difftool.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex 437474fea0..4931c10845 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -558,7 +558,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t}\n \n \t/*\n-\t * Symbolic links require special treatment.The standard \"git diff\"\n+\t * Symbolic links require special treatment. The standard \"git diff\"\n \t * shows only the link itself, not the contents of the link target.\n \t * This loop replicates that behavior.\n \t */\n-- \n2.33.0.886.g5b6dfe5e5c\n\n"}]}