{"thread":{"id":"20565","subject":"For review: git add --ignore-unmatch","startedAt":"2009-08-12T22:26:51Z","lastAt":"2009-10-10T17:23:32Z","messageCount":21,"participants":["Luke-Jr","Thomas Rast","Luke Dashjr","Junio C Hamano","Alex Riesen","Nanako Shiraishi"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"120460","messageId":"200908121726.52121.luke-jr@utopios.org","threadId":"20565","inReplyTo":null,"subject":"For review: git add --ignore-unmatch","fromName":"Luke-Jr","fromEmail":"luke-jr@utopios.org","sentAt":"2009-08-12T22:26:51Z","receivedAt":"2009-08-12T22:26:51Z","isPatch":false,"sender":{"key":"luke-jr@utopios.org","avatar":null},"body":"\n\n\nFrom 54768360aa7b1882dd2b76211661abb6014cbf23 Mon Sep 17 00:00:00 2001\nFrom: Luke Dashjr <luke-jr+git@utopios.org>\nDate: Wed, 12 Aug 2009 16:26:31 -0500\nSubject: [PATCH 1/3] port --ignore-unmatch from \"git rm\" to \"git add\"\n\n---\n builtin-add.c |    7 +++++--\n 1 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 581a2a1..0597fb9 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -19,6 +19,7 @@ static const char * const builtin_add_usage[] = {\n };\n static int patch_interactive, add_interactive, edit_interactive;\n static int take_worktree_changes;\n+static int ignore_unmatch = 0;\n \n static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n {\n@@ -63,7 +64,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n \tfill_pathspec_matches(pathspec, seen, specs);\n \n \tfor (i = 0; i < specs; i++) {\n-\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))\n+\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]) && !ignore_unmatch)\n \t\t\tdie(\"pathspec '%s' did not match any files\",\n \t\t\t\t\tpathspec[i]);\n \t}\n@@ -108,7 +109,7 @@ static void refresh(int verbose, const char **pathspec)\n \trefresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,\n \t\t      pathspec, seen);\n \tfor (i = 0; i < specs; i++) {\n-\t\tif (!seen[i])\n+\t\tif (!seen[i] && !ignore_unmatch)\n \t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n \t}\n         free(seen);\n@@ -226,6 +227,8 @@ static struct option builtin_add_options[] = {\n \tOPT_BOOLEAN('A', \"all\", &addremove, \"add all, noticing removal of tracked files\"),\n \tOPT_BOOLEAN( 0 , \"refresh\", &refresh_only, \"don't add, only refresh the index\"),\n \tOPT_BOOLEAN( 0 , \"ignore-errors\", &ignore_add_errors, \"just skip files which cannot be added because of errors\"),\n+\tOPT_BOOLEAN( 0 , \"ignore-unmatch\", &ignore_unmatch,\n+\t\t\t\t\"exit with a zero status even if nothing matched\"),\n \tOPT_END(),\n };\n \n-- \n1.6.3.3\n\n\n\nFrom c6cd06db8ab3b198eafffd5b0e94d2f338f10072 Mon Sep 17 00:00:00 2001\nFrom: Luke Dashjr <luke-jr+git@utopios.org>\nDate: Wed, 12 Aug 2009 16:31:37 -0500\nSubject: [PATCH 2/3] fix \"git add --ignore-errors\" to ignore pathspec errors\n\n---\n builtin-add.c |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 0597fb9..e3132c8 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -280,6 +280,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\tadd_interactive = 1;\n \tif (add_interactive)\n \t\texit(interactive_add(argc - 1, argv + 1, prefix));\n+\tif (ignore_add_errors)\n+\t\tignore_unmatch = 1;\n \n \tif (edit_interactive)\n \t\treturn(edit_patch(argc, argv, prefix));\n-- \n1.6.3.3\n\n\n\nFrom 410a93cb61669304a0b1d10b8013d1635432e8a0 Mon Sep 17 00:00:00 2001\nFrom: Luke Dashjr <luke-jr+git@utopios.org>\nDate: Wed, 12 Aug 2009 17:23:44 -0500\nSubject: [PATCH 3/3] Document --ignore-unmatch in git-add.txt\n\n---\n Documentation/git-add.txt |    6 +++++-\n 1 files changed, 5 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex ab1943c..6b93b4e 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n [verse]\n 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]\n \t  [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]\n-\t  [--refresh] [--ignore-errors] [--] <filepattern>...\n+\t  [--refresh] [--ignore-errors] [--ignore-unmatch] [--]\n+\t  <filepattern>...\n \n DESCRIPTION\n -----------\n@@ -119,6 +120,9 @@ apply.\n \tthem, do not abort the operation, but continue adding the\n \tothers. The command shall still exit with non-zero status.\n \n+--ignore-unmatch::\n+\tExit with a zero status even if no files matched.\n+\n \\--::\n \tThis option can be used to separate command-line options from\n \tthe list of files, (useful when filenames might be mistaken\n-- \n1.6.3.3\n\n"},{"id":"120463","messageId":"200908130057.22646.trast@student.ethz.ch","threadId":"20565","inReplyTo":"200908121726.52121.luke-jr@utopios.org","subject":"Re: For review: git add --ignore-unmatch","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-12T22:57:21Z","receivedAt":"2009-08-12T22:57:21Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Luke-Jr wrote:\n> \n> [0001-port-ignore-unmatch-from-git-rm-to-git-add.patch]\n> [0002-fix-git-add-ignore-errors-to-ignore-pathspec-errors.patch]\n> [0003-Document-ignore-unmatch-in-git-add.txt.patch]\n\nI've already told you on IRC how to go about this, so please:\n\n* send one patch per mail, inline\n* write real commit messages\n* sign off\n* write tests\n\n[Yeah, I'm tired and grumpy, but I'm also trying to save others the\nwork of saying this again more politely...]\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"120475","messageId":"1250133624-2272-1-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"200908121726.52121.luke-jr@utopios.org","subject":"[PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T03:20:20Z","receivedAt":"2009-08-13T03:20:20Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"\"git rm\" has a --ignore-unmatch option that is also applicable to \"git add\"\nand may be useful for persons wanting to ignore unmatched arguments, but not\nall errors.\n\nSigned-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n builtin-add.c |    7 +++++--\n 1 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 581a2a1..0597fb9 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -19,6 +19,7 @@ static const char * const builtin_add_usage[] = {\n };\n static int patch_interactive, add_interactive, edit_interactive;\n static int take_worktree_changes;\n+static int ignore_unmatch = 0;\n \n static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n {\n@@ -63,7 +64,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n \tfill_pathspec_matches(pathspec, seen, specs);\n \n \tfor (i = 0; i < specs; i++) {\n-\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))\n+\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]) && !ignore_unmatch)\n \t\t\tdie(\"pathspec '%s' did not match any files\",\n \t\t\t\t\tpathspec[i]);\n \t}\n@@ -108,7 +109,7 @@ static void refresh(int verbose, const char **pathspec)\n \trefresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,\n \t\t      pathspec, seen);\n \tfor (i = 0; i < specs; i++) {\n-\t\tif (!seen[i])\n+\t\tif (!seen[i] && !ignore_unmatch)\n \t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n \t}\n         free(seen);\n@@ -226,6 +227,8 @@ static struct option builtin_add_options[] = {\n \tOPT_BOOLEAN('A', \"all\", &addremove, \"add all, noticing removal of tracked files\"),\n \tOPT_BOOLEAN( 0 , \"refresh\", &refresh_only, \"don't add, only refresh the index\"),\n \tOPT_BOOLEAN( 0 , \"ignore-errors\", &ignore_add_errors, \"just skip files which cannot be added because of errors\"),\n+\tOPT_BOOLEAN( 0 , \"ignore-unmatch\", &ignore_unmatch,\n+\t\t\t\t\"exit with a zero status even if nothing matched\"),\n \tOPT_END(),\n };\n \n-- \n1.6.3.3\n"},{"id":"120476","messageId":"1250133624-2272-2-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"1250133624-2272-1-git-send-email-luke-jr+git@utopios.org","subject":"[PATCH 2/5] fix \"git add --ignore-errors\" to ignore pathspec errors","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T03:20:21Z","receivedAt":"2009-08-13T03:20:21Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"Unmatched files are errors, and should be ignored with the rest of them.\n\nSigned-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n builtin-add.c |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 0597fb9..e3132c8 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -280,6 +280,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\tadd_interactive = 1;\n \tif (add_interactive)\n \t\texit(interactive_add(argc - 1, argv + 1, prefix));\n+\tif (ignore_add_errors)\n+\t\tignore_unmatch = 1;\n \n \tif (edit_interactive)\n \t\treturn(edit_patch(argc, argv, prefix));\n-- \n1.6.3.3\n"},{"id":"120474","messageId":"1250133624-2272-3-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"1250133624-2272-2-git-send-email-luke-jr+git@utopios.org","subject":"[PATCH 3/5] Document --ignore-unmatch in git-add.txt","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T03:20:22Z","receivedAt":"2009-08-13T03:20:22Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n Documentation/git-add.txt |    6 +++++-\n 1 files changed, 5 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex ab1943c..6b93b4e 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n [verse]\n 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]\n \t  [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]\n-\t  [--refresh] [--ignore-errors] [--] <filepattern>...\n+\t  [--refresh] [--ignore-errors] [--ignore-unmatch] [--]\n+\t  <filepattern>...\n \n DESCRIPTION\n -----------\n@@ -119,6 +120,9 @@ apply.\n \tthem, do not abort the operation, but continue adding the\n \tothers. The command shall still exit with non-zero status.\n \n+--ignore-unmatch::\n+\tExit with a zero status even if no files matched.\n+\n \\--::\n \tThis option can be used to separate command-line options from\n \tthe list of files, (useful when filenames might be mistaken\n-- \n1.6.3.3\n"},{"id":"120477","messageId":"1250133624-2272-4-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"1250133624-2272-3-git-send-email-luke-jr+git@utopios.org","subject":"[PATCH 4/5] implement error_errno and warning_errno","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T03:20:23Z","receivedAt":"2009-08-13T03:20:23Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"This allows for easier conversion of code that currently does a (fatal)\ndie_errno to a safer error (which can be ignored), or perhaps even warning\nstatus.\n\nSigned-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n git-compat-util.h |    2 +\n usage.c           |   66 ++++++++++++++++++++++++-----------------------------\n 2 files changed, 32 insertions(+), 36 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 9f941e4..25d4c1e 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -181,7 +181,9 @@ extern void usage(const char *err) NORETURN;\n extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));\n extern void die_errno(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));\n extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern int error_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));\n extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));\n+extern void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));\n \n extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);\n \ndiff --git a/usage.c b/usage.c\nindex b6aea45..dce90dc 100644\n--- a/usage.c\n+++ b/usage.c\n@@ -39,7 +39,7 @@ static void warn_builtin(const char *warn, va_list params)\n static void (*usage_routine)(const char *err) NORETURN = usage_builtin;\n static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin;\n static void (*error_routine)(const char *err, va_list params) = error_builtin;\n-static void (*warn_routine)(const char *err, va_list params) = warn_builtin;\n+static void (*warning_routine)(const char *err, va_list params) = warn_builtin;\n \n void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN)\n {\n@@ -51,19 +51,8 @@ void usage(const char *err)\n \tusage_routine(err);\n }\n \n-void die(const char *err, ...)\n+static void _e_errno(const char *fmt, char *fmt_with_err, size_t sizeof_fmt_with_err)\n {\n-\tva_list params;\n-\n-\tva_start(params, err);\n-\tdie_routine(err, params);\n-\tva_end(params);\n-}\n-\n-void die_errno(const char *fmt, ...)\n-{\n-\tva_list params;\n-\tchar fmt_with_err[1024];\n \tchar str_error[256], *err;\n \tint i, j;\n \n@@ -81,28 +70,33 @@ void die_errno(const char *fmt, ...)\n \t\t}\n \t}\n \tstr_error[j] = 0;\n-\tsnprintf(fmt_with_err, sizeof(fmt_with_err), \"%s: %s\", fmt, str_error);\n-\n-\tva_start(params, fmt);\n-\tdie_routine(fmt_with_err, params);\n-\tva_end(params);\n-}\n-\n-int error(const char *err, ...)\n-{\n-\tva_list params;\n-\n-\tva_start(params, err);\n-\terror_routine(err, params);\n-\tva_end(params);\n-\treturn -1;\n+\tsnprintf(fmt_with_err, sizeof_fmt_with_err, \"%s: %s\", fmt, str_error);\n }\n \n-void warning(const char *warn, ...)\n-{\n-\tva_list params;\n-\n-\tva_start(params, warn);\n-\twarn_routine(warn, params);\n-\tva_end(params);\n-}\n+#define BUILD_E(RTYPE, NAME, CODE)  \\\n+RTYPE NAME(const char *err, ...)  \\\n+{  \\\n+\tva_list params;  \\\n+  \\\n+\tva_start(params, err);  \\\n+\tNAME ## _routine(err, params);  \\\n+\tva_end(params);  \\\n+\tCODE  \\\n+}  \\\n+  \\\n+RTYPE NAME ## _errno(const char *fmt, ...)  \\\n+{  \\\n+\tva_list params;  \\\n+\tstatic char fmt_with_err[1024];  \\\n+  \\\n+\tva_start(params, fmt);  \\\n+\t_e_errno(fmt, fmt_with_err, sizeof(fmt_with_err));  \\\n+\tNAME ## _routine(fmt_with_err, params);  \\\n+\tva_end(params);  \\\n+\tCODE  \\\n+}  \\\n+// END OF BUILD_E MACRO\n+\n+BUILD_E(void, die, )\n+BUILD_E(int, error, return -1;)\n+BUILD_E(void, warning, )\n-- \n1.6.3.3\n"},{"id":"120478","messageId":"1250133624-2272-5-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"1250133624-2272-4-git-send-email-luke-jr+git@utopios.org","subject":"[PATCH 5/5] Convert add_file_to_index's lstat failure from a die to an error","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T03:20:24Z","receivedAt":"2009-08-13T03:20:24Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"In order to make --ignore-errors able to ignore a lstat failure in\nadd_file_to_index, it needs to raise an error, NOT a fatal die.\n\nSigned-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n read-cache.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex 4e3e272..074e6b8 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -638,7 +638,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n {\n \tstruct stat st;\n \tif (lstat(path, &st))\n-\t\tdie_errno(\"unable to stat '%s'\", path);\n+\t\treturn error_errno(\"unable to stat '%s'\", path);\n \treturn add_to_index(istate, path, &st, flags);\n }\n \n-- \n1.6.3.3\n"},{"id":"120567","messageId":"7vy6pna4lu.fsf@alter.siamese.dyndns.org","threadId":"20565","inReplyTo":"1250133624-2272-1-git-send-email-luke-jr+git@utopios.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-13T19:36:13Z","receivedAt":"2009-08-13T19:36:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Luke Dashjr <luke-jr+git@utopios.org> writes:\n\n> \"git rm\" has a --ignore-unmatch option that is also applicable to \"git add\"\n> and may be useful for persons wanting to ignore unmatched arguments, but not\n> all errors.\n>\n> Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n\nChould you refresh my memory a bit?\n\nIn what circumstance is \"rm --ignore-unmatch\" useful to begin with?\nA similar question for \"add --ignore-unmatch\".\n\nNow the obligatory design level question is behind us, let's take a brief\nlook at the codde.\n\n> +static int ignore_unmatch = 0;\n\nDrop \" = 0\" and let the language initialize this to zero.\n\n>  static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n>  {\n> @@ -63,7 +64,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n>  \tfill_pathspec_matches(pathspec, seen, specs);\n>  \n>  \tfor (i = 0; i < specs; i++) {\n> -\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))\n> +\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]) && !ignore_unmatch)\n>  \t\t\tdie(\"pathspec '%s' did not match any files\",\n>  \t\t\t\t\tpathspec[i]);\n>  \t}\n> @@ -108,7 +109,7 @@ static void refresh(int verbose, const char **pathspec)\n>  \trefresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,\n>  \t\t      pathspec, seen);\n>  \tfor (i = 0; i < specs; i++) {\n> -\t\tif (!seen[i])\n> +\t\tif (!seen[i] && !ignore_unmatch)\n>  \t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n>  \t}\n>          free(seen);\n\nWhat's the point of these two loops if under ignore_unmatch everything\nbecomes no-op?\n\nThat is, wouldn't it be much more clear if you wrote like this?\n\n builtin-add.c |   25 ++++++++++++++++++-------\n 1 files changed, 18 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 581a2a1..49576b4 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -41,16 +41,25 @@ static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n \t}\n }\n \n+static char *alloc_seen(const char **pathspec, int *specs_)\n+{\n+\tint specs;\n+\n+\tif (ignore_unmatch)\n+\t\treturn NULL;\n+\tfor (specs = 0; pathspec[specs];  specs++)\n+\t\t; /* nothing */\n+\t*specs_ = specs;\n+\treturn xcalloc(specs, 1);\n+}\n+\n static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)\n {\n \tchar *seen;\n \tint i, specs;\n \tstruct dir_entry **src, **dst;\n \n-\tfor (specs = 0; pathspec[specs];  specs++)\n-\t\t/* nothing */;\n-\tseen = xcalloc(specs, 1);\n-\n+\tseen = alloc_seen(pathspec, &specs);\n \tsrc = dst = dir->entries;\n \ti = dir->nr;\n \twhile (--i >= 0) {\n@@ -60,6 +69,8 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n \t\t\t*dst++ = entry;\n \t}\n \tdir->nr = dst - dir->entries;\n+\tif (!seen)\n+\t\treturn;\n \tfill_pathspec_matches(pathspec, seen, specs);\n \n \tfor (i = 0; i < specs; i++) {\n@@ -102,11 +113,11 @@ static void refresh(int verbose, const char **pathspec)\n \tchar *seen;\n \tint i, specs;\n \n-\tfor (specs = 0; pathspec[specs];  specs++)\n-\t\t/* nothing */;\n-\tseen = xcalloc(specs, 1);\n+\tseen = alloc_seen(pathspec, &specs);\n \trefresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,\n \t\t      pathspec, seen);\n+\tif (!seen)\n+\t\treturn;\n \tfor (i = 0; i < specs; i++) {\n \t\tif (!seen[i])\n \t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n"},{"id":"120568","messageId":"7vr5vfa4ha.fsf@alter.siamese.dyndns.org","threadId":"20565","inReplyTo":"1250133624-2272-2-git-send-email-luke-jr+git@utopios.org","subject":"Re: [PATCH 2/5] fix \"git add --ignore-errors\" to ignore pathspec errors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-13T19:38:57Z","receivedAt":"2009-08-13T19:38:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Luke Dashjr <luke-jr+git@utopios.org> writes:\n\n> Unmatched files are errors, and should be ignored with the rest of them.\n\nWhy is this a \"fix\"?\n\nI would understand if it were \"Make --ignore-errors imply --ignore-unmatch\nunconditionally\".  But then I do not think I would necessarily agree it is\na good change.\n\nThe user may know that some files in the work tree are unreadable and\ncannot be indexed (hence he gives --ignore-errors) but he still may want\nto catch a typo on the command line.\n\nI do not think it is wise to make --ignore-errors imply --ignore-unmatch\nunconditionally like this patch does without any escape hatch.\n\n> Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n> ---\n>  builtin-add.c |    2 ++\n>  1 files changed, 2 insertions(+), 0 deletions(-)\n>\n> diff --git a/builtin-add.c b/builtin-add.c\n> index 0597fb9..e3132c8 100644\n> --- a/builtin-add.c\n> +++ b/builtin-add.c\n> @@ -280,6 +280,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n>  \t\tadd_interactive = 1;\n>  \tif (add_interactive)\n>  \t\texit(interactive_add(argc - 1, argv + 1, prefix));\n> +\tif (ignore_add_errors)\n> +\t\tignore_unmatch = 1;\n>  \n>  \tif (edit_interactive)\n>  \t\treturn(edit_patch(argc, argv, prefix));\n> -- \n> 1.6.3.3\n"},{"id":"120578","messageId":"200908131540.49701.luke@dashjr.org","threadId":"20565","inReplyTo":"7vy6pna4lu.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Luke-Jr","fromEmail":"luke@dashjr.org","sentAt":"2009-08-13T20:40:47Z","receivedAt":"2009-08-13T20:40:47Z","isPatch":true,"sender":{"key":"luke@dashjr.org","avatar":null},"body":"On Thursday 13 August 2009 02:36:13 pm Junio C Hamano wrote:\n> Luke Dashjr <luke-jr+git@utopios.org> writes:\n> > \"git rm\" has a --ignore-unmatch option that is also applicable to \"git\n> > add\" and may be useful for persons wanting to ignore unmatched arguments,\n> > but not all errors.\n>\n> Chould you refresh my memory a bit?\n>\n> In what circumstance is \"rm --ignore-unmatch\" useful to begin with?\n> A similar question for \"add --ignore-unmatch\".\n\nNot sure on its purpose for \"rm\", but for \"add\"...\nAvoiding a race condition in automation. In particular, if the file is deleted \nbetween the time the argument list is built until git scans for matches.\n\n> Now the obligatory design level question is behind us, let's take a brief\n> look at the codde.\n>\n> > +static int ignore_unmatch = 0;\n>\n> Drop \" = 0\" and let the language initialize this to zero.\n\nDoes C define a default initialisation of zero? My understanding was that \nuninitialised variables are always undefined until explicitly assigned a \nvalue.\n\n> >  static void fill_pathspec_matches(const char **pathspec, char *seen, int\n> > specs) {\n> > @@ -63,7 +64,7 @@ static void prune_directory(struct dir_struct *dir,\n> > const char **pathspec, int p fill_pathspec_matches(pathspec, seen,\n> > specs);\n> >\n> >  \tfor (i = 0; i < specs; i++) {\n> > -\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))\n> > +\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]) &&\n> > !ignore_unmatch) die(\"pathspec '%s' did not match any files\",\n> >  \t\t\t\t\tpathspec[i]);\n> >  \t}\n> > @@ -108,7 +109,7 @@ static void refresh(int verbose, const char\n> > **pathspec) refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED :\n> > REFRESH_QUIET, pathspec, seen);\n> >  \tfor (i = 0; i < specs; i++) {\n> > -\t\tif (!seen[i])\n> > +\t\tif (!seen[i] && !ignore_unmatch)\n> >  \t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n> >  \t}\n> >          free(seen);\n>\n> What's the point of these two loops if under ignore_unmatch everything\n> becomes no-op?\n>\n> That is, wouldn't it be much more clear if you wrote like this?\n\nI'm not overly familiar with the git codebase, but wouldn't a null 'seen' \nvariable break the refresh_index call? The loops themselves can be avoided, I \nsuppose. I'll submit a new patch to optimise the changes (and rebase)...\n"},{"id":"120579","messageId":"200908131542.23971.luke@dashjr.org","threadId":"20565","inReplyTo":"7vr5vfa4ha.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/5] fix \"git add --ignore-errors\" to ignore pathspec errors","fromName":"Luke-Jr","fromEmail":"luke@dashjr.org","sentAt":"2009-08-13T20:42:23Z","receivedAt":"2009-08-13T20:42:23Z","isPatch":true,"sender":{"key":"luke@dashjr.org","avatar":null},"body":"On Thursday 13 August 2009 02:38:57 pm Junio C Hamano wrote:\n> Luke Dashjr <luke-jr+git@utopios.org> writes:\n> > Unmatched files are errors, and should be ignored with the rest of them.\n>\n> Why is this a \"fix\"?\n>\n> I would understand if it were \"Make --ignore-errors imply --ignore-unmatch\n> unconditionally\".  But then I do not think I would necessarily agree it is\n> a good change.\n>\n> The user may know that some files in the work tree are unreadable and\n> cannot be indexed (hence he gives --ignore-errors) but he still may want\n> to catch a typo on the command line.\n>\n> I do not think it is wise to make --ignore-errors imply --ignore-unmatch\n> unconditionally like this patch does without any escape hatch.\n\nAre unmatched files not errors? Perhaps the old flag should be renamed to\n--ignore-read-errors and a new --ignore-errors that implies both added. Or \nmaybe just a documentation change to preserve compatibility with anything that \nmight assume that...\n"},{"id":"120580","messageId":"1250197365-23720-1-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"7vr5vfa4ha.fsf@alter.siamese.dyndns.org","subject":"[PATCH] port --ignore-unmatch to \"git add\"","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T21:02:45Z","receivedAt":"2009-08-13T21:02:45Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"\"git rm\" has a --ignore-unmatch option that is also applicable to \"git add\"\nand may be useful for persons wanting to ignore unmatched arguments, but not\nall errors.\n\nSigned-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n builtin-add.c |   27 +++++++++++++++++++--------\n 1 files changed, 19 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 581a2a1..3882482 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -19,6 +19,7 @@ static const char * const builtin_add_usage[] = {\n };\n static int patch_interactive, add_interactive, edit_interactive;\n static int take_worktree_changes;\n+static int ignore_unmatch = 0;\n \n static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n {\n@@ -60,13 +61,18 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n \t\t\t*dst++ = entry;\n \t}\n \tdir->nr = dst - dir->entries;\n-\tfill_pathspec_matches(pathspec, seen, specs);\n \n-\tfor (i = 0; i < specs; i++) {\n-\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))\n-\t\t\tdie(\"pathspec '%s' did not match any files\",\n-\t\t\t\t\tpathspec[i]);\n+\tif (!ignore_unmatch)\n+\t{\n+\t\tfill_pathspec_matches(pathspec, seen, specs);\n+\n+\t\tfor (i = 0; i < specs; i++) {\n+\t\t\tif (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))\n+\t\t\t\tdie(\"pathspec '%s' did not match any files\",\n+\t\t\t\t\t\tpathspec[i]);\n+\t\t}\n \t}\n+\n         free(seen);\n }\n \n@@ -107,9 +113,12 @@ static void refresh(int verbose, const char **pathspec)\n \tseen = xcalloc(specs, 1);\n \trefresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,\n \t\t      pathspec, seen);\n-\tfor (i = 0; i < specs; i++) {\n-\t\tif (!seen[i])\n-\t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n+\tif (!ignore_unmatch)\n+\t{\n+\t\tfor (i = 0; i < specs; i++) {\n+\t\t\tif (!seen[i])\n+\t\t\t\tdie(\"pathspec '%s' did not match any files\", pathspec[i]);\n+\t\t}\n \t}\n         free(seen);\n }\n@@ -226,6 +235,8 @@ static struct option builtin_add_options[] = {\n \tOPT_BOOLEAN('A', \"all\", &addremove, \"add all, noticing removal of tracked files\"),\n \tOPT_BOOLEAN( 0 , \"refresh\", &refresh_only, \"don't add, only refresh the index\"),\n \tOPT_BOOLEAN( 0 , \"ignore-errors\", &ignore_add_errors, \"just skip files which cannot be added because of errors\"),\n+\tOPT_BOOLEAN( 0 , \"ignore-unmatch\", &ignore_unmatch,\n+\t\t\t\t\"exit with a zero status even if nothing matched\"),\n \tOPT_END(),\n };\n \n-- \n1.6.3.3\n"},{"id":"120581","messageId":"1250197399-23761-1-git-send-email-luke-jr+git@utopios.org","threadId":"20565","inReplyTo":"7vr5vfa4ha.fsf@alter.siamese.dyndns.org","subject":"[PATCH] Document --ignore-unmatch in git-add.txt","fromName":"Luke Dashjr","fromEmail":"luke-jr+git@utopios.org","sentAt":"2009-08-13T21:03:19Z","receivedAt":"2009-08-13T21:03:19Z","isPatch":true,"sender":{"key":"luke-jr+git@utopios.org","avatar":"https://gravatar.com/avatar/2efd46f1634c4c2e4f806782acfe41cc552fc296a03136e49b47555c4c0ed18d?d=mp&s=160"},"body":"Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>\n---\n Documentation/git-add.txt |    6 +++++-\n 1 files changed, 5 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex e67b7e8..6e30ee9 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n [verse]\n 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]\n \t  [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]\n-\t  [--refresh] [--ignore-errors] [--] [<filepattern>...]\n+\t  [--refresh] [--ignore-errors] [--ignore-unmatch] [--]\n+\t  [<filepattern>...]\n \n DESCRIPTION\n -----------\n@@ -119,6 +120,9 @@ apply.\n \tthem, do not abort the operation, but continue adding the\n \tothers. The command shall still exit with non-zero status.\n \n+--ignore-unmatch::\n+\tExit with a zero status even if no files matched.\n+\n \\--::\n \tThis option can be used to separate command-line options from\n \tthe list of files, (useful when filenames might be mistaken\n-- \n1.6.3.3\n"},{"id":"120582","messageId":"200908132306.37947.trast@student.ethz.ch","threadId":"20565","inReplyTo":"7vy6pna4lu.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-13T21:06:36Z","receivedAt":"2009-08-13T21:06:36Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> \n> Chould you refresh my memory a bit?\n> \n> In what circumstance is \"rm --ignore-unmatch\" useful to begin with?\n\nNot sure about add --ignore-unmatch myself, but there's even an\nexample of rm --ignore-unmatch in man git-filter-branch, along the\nlines of\n\n  git filter-branch --index-filter '\n    rm --ignore-unmach some_file_that_shouldnt_be_in_history\n  ' -- --all\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"120589","messageId":"81b0412b0908131451q651b40a5q187257b7bda93b0a@mail.gmail.com","threadId":"20565","inReplyTo":"200908131540.49701.luke@dashjr.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-13T21:51:33Z","receivedAt":"2009-08-13T21:51:33Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Thu, Aug 13, 2009 at 22:40, Luke-Jr<luke@dashjr.org> wrote:\n> On Thursday 13 August 2009 02:36:13 pm Junio C Hamano wrote:\n>> Now the obligatory design level question is behind us, let's take a brief\n>> look at the codde.\n>>\n>> > +static int ignore_unmatch = 0;\n>>\n>> Drop \" = 0\" and let the language initialize this to zero.\n>\n> Does C define a default initialisation of zero? My understanding was that\n> uninitialised variables are always undefined until explicitly assigned a\n> value.\n\nYes. For statics.\n"},{"id":"120649","messageId":"7vws56i35q.fsf@alter.siamese.dyndns.org","threadId":"20565","inReplyTo":"200908132306.37947.trast@student.ethz.ch","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-14T19:52:33Z","receivedAt":"2009-08-14T19:52:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> Junio C Hamano wrote:\n>> \n>> Chould you refresh my memory a bit?\n>> \n>> In what circumstance is \"rm --ignore-unmatch\" useful to begin with?\n>\n> Not sure about add --ignore-unmatch myself, but there's even an\n> example of rm --ignore-unmatch in man git-filter-branch, along the\n> lines of\n>\n>   git filter-branch --index-filter '\n>     rm --ignore-unmach some_file_that_shouldnt_be_in_history\n>   ' -- --all\n\nAh, that makes sense.  I am not sure about \"add --ignore-unmatch\" myself\neither, and an example similar to the above filter-branch would not apply\nvery easily (i.e. \"add a file that should have been in history\" would not\nneed --ignore-unmatch).\n"},{"id":"120657","messageId":"200908141539.18087.luke@dashjr.org","threadId":"20565","inReplyTo":"7vws56i35q.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Luke-Jr","fromEmail":"luke@dashjr.org","sentAt":"2009-08-14T20:39:14Z","receivedAt":"2009-08-14T20:39:14Z","isPatch":true,"sender":{"key":"luke@dashjr.org","avatar":null},"body":"On Friday 14 August 2009 02:52:33 pm Junio C Hamano wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> > Junio C Hamano wrote:\n> >> Chould you refresh my memory a bit?\n> >>\n> >> In what circumstance is \"rm --ignore-unmatch\" useful to begin with?\n> >\n> > Not sure about add --ignore-unmatch myself, but there's even an\n> > example of rm --ignore-unmatch in man git-filter-branch, along the\n> > lines of\n> >\n> >   git filter-branch --index-filter '\n> >     rm --ignore-unmach some_file_that_shouldnt_be_in_history\n> >   ' -- --all\n>\n> Ah, that makes sense.  I am not sure about \"add --ignore-unmatch\" myself\n> either, and an example similar to the above filter-branch would not apply\n> very easily (i.e. \"add a file that should have been in history\" would not\n> need --ignore-unmatch).\n\nThe purpose of \"add --ignore-unmatch\" is to ignore race conditions where one \nof the files to be added has been deleted after git is executed, but before \ngit scans it.\n"},{"id":"120659","messageId":"200908141547.09814.luke@dashjr.org","threadId":"20565","inReplyTo":"200908141539.18087.luke@dashjr.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Luke-Jr","fromEmail":"luke@dashjr.org","sentAt":"2009-08-14T20:47:08Z","receivedAt":"2009-08-14T20:47:08Z","isPatch":true,"sender":{"key":"luke@dashjr.org","avatar":null},"body":"Specific use-case of \"git add --ignore-unmatched\":\n\thttp://gitorious.org/gitbackup\n\nWithout this functionality, daily race conditions will break the \nsynchronisation.\n"},{"id":"120665","messageId":"20090815063958.6117@nanako3.lavabit.com","threadId":"20565","inReplyTo":"200908141539.18087.luke@dashjr.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Nanako Shiraishi","fromEmail":"nanako3@lavabit.com","sentAt":"2009-08-14T21:39:58Z","receivedAt":"2009-08-14T21:39:58Z","isPatch":true,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Quoting \"Luke-Jr\" <luke@dashjr.org>\n\n> On Friday 14 August 2009 02:52:33 pm Junio C Hamano wrote:\n>> Thomas Rast <trast@student.ethz.ch> writes:\n>> > Junio C Hamano wrote:\n>> >> Chould you refresh my memory a bit?\n>> >>\n>> >> In what circumstance is \"rm --ignore-unmatch\" useful to begin with?\n>> >\n>> > Not sure about add --ignore-unmatch myself, but there's even an\n>> > example of rm --ignore-unmatch in man git-filter-branch, along the\n>> > lines of\n>> >\n>> >   git filter-branch --index-filter '\n>> >     rm --ignore-unmach some_file_that_shouldnt_be_in_history\n>> >   ' -- --all\n>>\n>> Ah, that makes sense.  I am not sure about \"add --ignore-unmatch\" myself\n>> either, and an example similar to the above filter-branch would not apply\n>> very easily (i.e. \"add a file that should have been in history\" would not\n>> need --ignore-unmatch).\n>\n> The purpose of \"add --ignore-unmatch\" is to ignore race conditions where one \n> of the files to be added has been deleted after git is executed, but before \n> git scans it.\n\nFirst of all, it should have been mentioned as part of your proposed commit log message.\n\nSecond of all, if a race condition makes an \"add\" fail, isn't it a good thing? If your \"add\" ignored such a failure, you'd be recording an inconsistent or incomplete state.\n\nIMHO, fixing your racy script is a much cleaner solution to your problem than forcing \"git add\" to ignore errors.\n\n-- \nNanako Shiraishi\nhttp://ivory.ap.teacup.com/nanako3/\n"},{"id":"120673","messageId":"200908141754.51393.luke@dashjr.org","threadId":"20565","inReplyTo":"20090815063958.6117@nanako3.lavabit.com","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Luke-Jr","fromEmail":"luke@dashjr.org","sentAt":"2009-08-14T22:54:50Z","receivedAt":"2009-08-14T22:54:50Z","isPatch":true,"sender":{"key":"luke@dashjr.org","avatar":null},"body":"On Friday 14 August 2009 04:39:58 pm Nanako Shiraishi wrote:\n> Second of all, if a race condition makes an \"add\" fail, isn't it a good\n> thing? If your \"add\" ignored such a failure, you'd be recording an\n> inconsistent or incomplete state.\n\nIf the file doesn't exist, it is no longer in the current state.\n\n> IMHO, fixing your racy script is a much cleaner solution to your problem\n> than forcing \"git add\" to ignore errors.\n\nIn this situation, the race condition is not a bug, it is normal operation.\n"},{"id":"124578","messageId":"200910101223.36426.luke@dashjr.org","threadId":"20565","inReplyTo":"200908141754.51393.luke@dashjr.org","subject":"Re: [PATCH 1/5] port --ignore-unmatch to \"git add\"","fromName":"Luke-Jr","fromEmail":"luke@dashjr.org","sentAt":"2009-10-10T17:23:32Z","receivedAt":"2009-10-10T17:23:32Z","isPatch":true,"sender":{"key":"luke@dashjr.org","avatar":null},"body":"Just for reference, since these fixes+functions have not yet been merged to \nmainline Git, I have pushed a fork with them rebased on up-to-date tags:\n\thttp://repo.or.cz/w/git/ljr.git\n"}]}