summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/diff-config.txt6
-rw-r--r--Documentation/diff-options.txt2
-rw-r--r--Documentation/git-ls-files.txt7
-rw-r--r--Documentation/git-submodule.txt4
-rw-r--r--Documentation/git.txt6
-rw-r--r--Documentation/gitmodules.txt7
-rw-r--r--Documentation/pretty-formats.txt10
-rw-r--r--apply.c70
-rw-r--r--builtin/fetch.c11
-rw-r--r--builtin/ls-files.c181
-rw-r--r--builtin/merge-base.c3
-rw-r--r--builtin/pull.c71
-rw-r--r--builtin/rev-list.c2
-rw-r--r--cache.h3
-rw-r--r--contrib/coccinelle/xstrdup_or_null.cocci7
-rw-r--r--contrib/credential/libsecret/Makefile25
-rw-r--r--contrib/credential/libsecret/git-credential-libsecret.c370
-rw-r--r--convert.c12
-rw-r--r--credential-cache--daemon.c6
-rw-r--r--diff.c126
-rw-r--r--dir.c46
-rw-r--r--dir.h4
-rw-r--r--environment.c13
-rw-r--r--git-compat-util.h17
-rw-r--r--git.c30
-rwxr-xr-xgitweb/gitweb.perl20
-rw-r--r--gpg-interface.c13
-rw-r--r--imap-send.c6
-rw-r--r--mailmap.c6
-rw-r--r--pretty.c4
-rw-r--r--refs.c3
-rw-r--r--send-pack.c3
-rw-r--r--sha1_file.c5
-rwxr-xr-xt/perf/p5550-fetch-tags.sh99
-rwxr-xr-xt/t0020-crlf.sh6
-rwxr-xr-xt/t0040-parse-options.sh183
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh2
-rwxr-xr-xt/t2025-worktree-add.sh8
-rwxr-xr-xt/t3007-ls-files-recurse-submodules.sh210
-rwxr-xr-xt/t3700-add.sh1
-rwxr-xr-xt/t4015-diff-whitespace.sh74
-rwxr-xr-xt/t4254-am-corrupt.sh2
-rwxr-xr-xt/t6000-rev-list-misc.sh14
-rwxr-xr-xt/t6010-merge-base.sh6
-rwxr-xr-xt/t7510-signed-commit.sh13
-rw-r--r--trailer.c9
-rw-r--r--upload-pack.c13
-rw-r--r--worktree.c2
-rw-r--r--wt-status.c78
-rw-r--r--wt-status.h6
50 files changed, 1385 insertions, 440 deletions
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
index b27a38f896..58f4bd6afa 100644
--- a/Documentation/diff-config.txt
+++ b/Documentation/diff-config.txt
@@ -193,3 +193,9 @@ diff.algorithm::
low-occurrence common elements".
--
+
+
+diff.wsErrorHighlight::
+ A comma separated list of `old`, `new`, `context`, that
+ specifies how whitespace errors on lines are highlighted
+ with `color.diff.whitespace`. Can be overridden by the
+ command line option `--ws-error-highlight=<kind>`
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 2d77a19626..29630c2389 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -308,6 +308,8 @@ ifndef::git-format-patch[]
lines are highlighted. E.g. `--ws-error-highlight=new,old`
highlights whitespace errors on both deleted and added lines.
`all` can be used as a short-hand for `old,new,context`.
+ The `diff.wsErrorHighlight` configuration variable can be
+ used to specify the default behaviour.
endif::git-format-patch[]
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 0d933ac355..446209e206 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -18,7 +18,8 @@ SYNOPSIS
[--exclude-per-directory=<file>]
[--exclude-standard]
[--error-unmatch] [--with-tree=<tree-ish>]
- [--full-name] [--abbrev] [--] [<file>...]
+ [--full-name] [--recurse-submodules]
+ [--abbrev] [--] [<file>...]
DESCRIPTION
-----------
@@ -137,6 +138,10 @@ a space) at the start of each line:
option forces paths to be output relative to the project
top directory.
+--recurse-submodules::
+ Recursively calls ls-files on each submodule in the repository.
+ Currently there is only support for the --cached mode.
+
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
lines, show only a partial prefix.
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index bf3bb372ee..d841573475 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -259,7 +259,9 @@ OPTIONS
--branch::
Branch of repository to add as submodule.
The name of the branch is recorded as `submodule.<name>.branch` in
- `.gitmodules` for `update --remote`.
+ `.gitmodules` for `update --remote`. A special value of `.` is used to
+ indicate that the name of the branch in the submodule should be the
+ same name as the current branch in the current repository.
-f::
--force::
diff --git a/Documentation/git.txt b/Documentation/git.txt
index b8bec711f4..2cf7e225f5 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,6 +13,7 @@ SYNOPSIS
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
+ [--super-prefix=<path>]
<command> [<args>]
DESCRIPTION
@@ -602,6 +603,11 @@ foo.bar= ...`) sets `foo.bar` to the empty string.
details. Equivalent to setting the `GIT_NAMESPACE` environment
variable.
+--super-prefix=<path>::
+ Currently for internal use only. Set a prefix which gives a path from
+ above a repository down to its root. One use is to give submodules
+ context about the superproject that invoked it.
+
--bare::
Treat the repository as a bare repository. If GIT_DIR
environment is not set, it is set to the current working
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 10dcc08ff9..8f7c50f330 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -50,8 +50,11 @@ submodule.<name>.update::
submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
- If the option is not specified, it defaults to 'master'. See the
- `--remote` documentation in linkgit:git-submodule[1] for details.
+ If the option is not specified, it defaults to 'master'. A special
+ value of `.` is used to indicate that the name of the branch in the
+ submodule should be the same name as the current branch in the
+ current repository. See the `--remote` documentation in
+ linkgit:git-submodule[1] for details.
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 69c289dd0c..3bcee2ddb1 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -143,8 +143,14 @@ ifndef::git-rev-list[]
- '%N': commit notes
endif::git-rev-list[]
- '%GG': raw verification message from GPG for a signed commit
-- '%G?': show "G" for a good (valid) signature, "B" for a bad signature,
- "U" for a good signature with unknown validity and "N" for no signature
+- '%G?': show "G" for a good (valid) signature,
+ "B" for a bad signature,
+ "U" for a good signature with unknown validity,
+ "X" for a good signature that has expired,
+ "Y" for a good signature made by an expired key,
+ "R" for a good signature made by a revoked key,
+ "E" if the signature cannot be checked (e.g. missing key)
+ and "N" for no signature
- '%GS': show the name of the signer for a signed commit
- '%GK': show the key used to sign a signed commit
- '%gD': reflog selector, e.g., `refs/stash@{1}` or
diff --git a/apply.c b/apply.c
index b03d274b52..705cf562f0 100644
--- a/apply.c
+++ b/apply.c
@@ -122,9 +122,9 @@ int check_apply_state(struct apply_state *state, int force_apply)
int is_not_gitdir = !startup_info->have_repository;
if (state->apply_with_reject && state->threeway)
- return error("--reject and --3way cannot be used together.");
+ return error(_("--reject and --3way cannot be used together."));
if (state->cached && state->threeway)
- return error("--cached and --3way cannot be used together.");
+ return error(_("--cached and --3way cannot be used together."));
if (state->threeway) {
if (is_not_gitdir)
return error(_("--3way outside a repository"));
@@ -1586,8 +1586,8 @@ static int find_header(struct apply_state *state,
patch->new_name = xstrdup(patch->def_name);
}
if (!patch->is_delete && !patch->new_name) {
- error("git diff header lacks filename information "
- "(line %d)", state->linenr);
+ error(_("git diff header lacks filename information "
+ "(line %d)"), state->linenr);
return -128;
}
patch->is_toplevel_relative = 1;
@@ -3095,8 +3095,8 @@ static int apply_binary_fragment(struct apply_state *state,
/* Binary patch is irreversible without the optional second hunk */
if (state->apply_in_reverse) {
if (!fragment->next)
- return error("cannot reverse-apply a binary patch "
- "without the reverse hunk to '%s'",
+ return error(_("cannot reverse-apply a binary patch "
+ "without the reverse hunk to '%s'"),
patch->new_name
? patch->new_name : patch->old_name);
fragment = fragment->next;
@@ -3141,8 +3141,8 @@ static int apply_binary(struct apply_state *state,
strlen(patch->new_sha1_prefix) != 40 ||
get_oid_hex(patch->old_sha1_prefix, &oid) ||
get_oid_hex(patch->new_sha1_prefix, &oid))
- return error("cannot apply binary patch to '%s' "
- "without full index line", name);
+ return error(_("cannot apply binary patch to '%s' "
+ "without full index line"), name);
if (patch->old_name) {
/*
@@ -3151,16 +3151,16 @@ static int apply_binary(struct apply_state *state,
*/
hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
- return error("the patch applies to '%s' (%s), "
- "which does not match the "
- "current contents.",
+ return error(_("the patch applies to '%s' (%s), "
+ "which does not match the "
+ "current contents."),
name, oid_to_hex(&oid));
}
else {
/* Otherwise, the old one must be empty. */
if (img->len)
- return error("the patch applies to an empty "
- "'%s' but it is not empty", name);
+ return error(_("the patch applies to an empty "
+ "'%s' but it is not empty"), name);
}
get_oid_hex(patch->new_sha1_prefix, &oid);
@@ -3177,8 +3177,8 @@ static int apply_binary(struct apply_state *state,
result = read_sha1_file(oid.hash, &type, &size);
if (!result)
- return error("the necessary postimage %s for "
- "'%s' cannot be read",
+ return error(_("the necessary postimage %s for "
+ "'%s' cannot be read"),
patch->new_sha1_prefix, name);
clear_image(img);
img->buf = result;
@@ -3551,10 +3551,10 @@ static int try_threeway(struct apply_state *state,
write_sha1_file("", 0, blob_type, pre_oid.hash);
else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) ||
read_blob_object(&buf, &pre_oid, patch->old_mode))
- return error("repository lacks the necessary blob to fall back on 3-way merge.");
+ return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
if (state->apply_verbosity > verbosity_silent)
- fprintf(stderr, "Falling back to three-way merge...\n");
+ fprintf(stderr, _("Falling back to three-way merge...\n"));
img = strbuf_detach(&buf, &len);
prepare_image(&tmp_image, img, len, 1);
@@ -3570,11 +3570,11 @@ static int try_threeway(struct apply_state *state,
/* our_oid is ours */
if (patch->is_new) {
if (load_current(state, &tmp_image, patch))
- return error("cannot read the current contents of '%s'",
+ return error(_("cannot read the current contents of '%s'"),
patch->new_name);
} else {
if (load_preimage(state, &tmp_image, patch, st, ce))
- return error("cannot read the current contents of '%s'",
+ return error(_("cannot read the current contents of '%s'"),
patch->old_name);
}
write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
@@ -3586,7 +3586,7 @@ static int try_threeway(struct apply_state *state,
if (status < 0) {
if (state->apply_verbosity > verbosity_silent)
fprintf(stderr,
- "Failed to fall back on three-way merge...\n");
+ _("Failed to fall back on three-way merge...\n"));
return status;
}
@@ -3600,12 +3600,12 @@ static int try_threeway(struct apply_state *state,
oidcpy(&patch->threeway_stage[2], &post_oid);
if (state->apply_verbosity > verbosity_silent)
fprintf(stderr,
- "Applied patch to '%s' with conflicts.\n",
+ _("Applied patch to '%s' with conflicts.\n"),
patch->new_name);
} else {
if (state->apply_verbosity > verbosity_silent)
fprintf(stderr,
- "Applied patch to '%s' cleanly.\n",
+ _("Applied patch to '%s' cleanly.\n"),
patch->new_name);
}
return 0;
@@ -4072,18 +4072,18 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
if (!preimage_oid_in_gitlink_patch(patch, &oid))
; /* ok, the textual part looks sane */
else
- return error("sha1 information is lacking or "
- "useless for submodule %s", name);
+ return error(_("sha1 information is lacking or "
+ "useless for submodule %s"), name);
} else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) {
; /* ok */
} else if (!patch->lines_added && !patch->lines_deleted) {
/* mode-only change: update the current */
if (get_current_oid(state, patch->old_name, &oid))
- return error("mode change for %s, which is not "
- "in current HEAD", name);
+ return error(_("mode change for %s, which is not "
+ "in current HEAD"), name);
} else
- return error("sha1 information is lacking or useless "
- "(%s).", name);
+ return error(_("sha1 information is lacking or useless "
+ "(%s)."), name);
ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);
if (!ce)
@@ -4091,7 +4091,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
name);
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
free(ce);
- return error("Could not add %s to temporary index",
+ return error(_("could not add %s to temporary index"),
name);
}
}
@@ -4101,7 +4101,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
discard_index(&result);
if (res)
- return error("Could not write temporary index to %s",
+ return error(_("could not write temporary index to %s"),
state->fake_ancestor);
return 0;
@@ -4869,10 +4869,12 @@ int apply_all_patches(struct apply_state *state,
goto end;
}
if (state->applied_after_fixing_ws && state->apply)
- warning("%d line%s applied after"
- " fixing whitespace errors.",
- state->applied_after_fixing_ws,
- state->applied_after_fixing_ws == 1 ? "" : "s");
+ warning(Q_("%d line applied after"
+ " fixing whitespace errors.",
+ "%d lines applied after"
+ " fixing whitespace errors.",
+ state->applied_after_fixing_ws),
+ state->applied_after_fixing_ws);
else if (state->whitespace_error)
warning(Q_("%d line adds whitespace errors.",
"%d lines add whitespace errors.",
diff --git a/builtin/fetch.c b/builtin/fetch.c
index d5329f915e..74c0546362 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -241,9 +241,10 @@ static void find_non_local_tags(struct transport *transport,
* as one to ignore by setting util to NULL.
*/
if (ends_with(ref->name, "^{}")) {
- if (item && !has_object_file(&ref->old_oid) &&
+ if (item &&
+ !has_object_file_with_flags(&ref->old_oid, HAS_SHA1_QUICK) &&
!will_fetch(head, ref->old_oid.hash) &&
- !has_sha1_file(item->util) &&
+ !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
!will_fetch(head, item->util))
item->util = NULL;
item = NULL;
@@ -256,7 +257,8 @@ static void find_non_local_tags(struct transport *transport,
* to check if it is a lightweight tag that we want to
* fetch.
*/
- if (item && !has_sha1_file(item->util) &&
+ if (item &&
+ !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
!will_fetch(head, item->util))
item->util = NULL;
@@ -276,7 +278,8 @@ static void find_non_local_tags(struct transport *transport,
* We may have a final lightweight tag that needs to be
* checked to see if it needs fetching.
*/
- if (item && !has_sha1_file(item->util) &&
+ if (item &&
+ !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
!will_fetch(head, item->util))
item->util = NULL;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 197f153f50..1592290815 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -14,6 +14,7 @@
#include "resolve-undo.h"
#include "string-list.h"
#include "pathspec.h"
+#include "run-command.h"
static int abbrev;
static int show_deleted;
@@ -28,8 +29,11 @@ static int show_valid_bit;
static int line_terminator = '\n';
static int debug_mode;
static int show_eol;
+static int recurse_submodules;
+static struct argv_array submodules_options = ARGV_ARRAY_INIT;
static const char *prefix;
+static const char *super_prefix;
static int max_prefix_len;
static int prefix_len;
static struct pathspec pathspec;
@@ -68,11 +72,24 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)
static void write_name(const char *name)
{
/*
+ * Prepend the super_prefix to name to construct the full_name to be
+ * written.
+ */
+ struct strbuf full_name = STRBUF_INIT;
+ if (super_prefix) {
+ strbuf_addstr(&full_name, super_prefix);
+ strbuf_addstr(&full_name, name);
+ name = full_name.buf;
+ }
+
+ /*
* With "--full-name", prefix_len=0; this caller needs to pass
* an empty string in that case (a NULL is good for "").
*/
write_name_quoted_relative(name, prefix_len ? prefix : NULL,
stdout, line_terminator);
+
+ strbuf_release(&full_name);
}
static void show_dir_entry(const char *tag, struct dir_entry *ent)
@@ -152,55 +169,117 @@ static void show_killed_files(struct dir_struct *dir)
}
}
+/*
+ * Compile an argv_array with all of the options supported by --recurse_submodules
+ */
+static void compile_submodule_options(const struct dir_struct *dir, int show_tag)
+{
+ if (line_terminator == '\0')
+ argv_array_push(&submodules_options, "-z");
+ if (show_tag)
+ argv_array_push(&submodules_options, "-t");
+ if (show_valid_bit)
+ argv_array_push(&submodules_options, "-v");
+ if (show_cached)
+ argv_array_push(&submodules_options, "--cached");
+ if (show_eol)
+ argv_array_push(&submodules_options, "--eol");
+ if (debug_mode)
+ argv_array_push(&submodules_options, "--debug");
+}
+
+/**
+ * Recursively call ls-files on a submodule
+ */
+static void show_gitlink(const struct cache_entry *ce)
+{
+ struct child_process cp = CHILD_PROCESS_INIT;
+ int status;
+ int i;
+
+ argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
+ super_prefix ? super_prefix : "",
+ ce->name);
+ argv_array_push(&cp.args, "ls-files");
+ argv_array_push(&cp.args, "--recurse-submodules");
+
+ /* add supported options */
+ argv_array_pushv(&cp.args, submodules_options.argv);
+
+ /*
+ * Pass in the original pathspec args. The submodule will be
+ * responsible for prepending the 'submodule_prefix' prior to comparing
+ * against the pathspec for matches.
+ */
+ argv_array_push(&cp.args, "--");
+ for (i = 0; i < pathspec.nr; i++)
+ argv_array_push(&cp.args, pathspec.items[i].original);
+
+ cp.git_cmd = 1;
+ cp.dir = ce->name;
+ status = run_command(&cp);
+ if (status)
+ exit(status);
+}
+
static void show_ce_entry(const char *tag, const struct cache_entry *ce)
{
+ struct strbuf name = STRBUF_INIT;
int len = max_prefix_len;
+ if (super_prefix)
+ strbuf_addstr(&name, super_prefix);
+ strbuf_addstr(&name, ce->name);
if (len >= ce_namelen(ce))
die("git ls-files: internal error - cache entry not superset of prefix");
- if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
- len, ps_matched,
- S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
- return;
+ if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
+ submodule_path_match(&pathspec, name.buf, ps_matched)) {
+ show_gitlink(ce);
+ } else if (match_pathspec(&pathspec, name.buf, name.len,
+ len, ps_matched,
+ S_ISDIR(ce->ce_mode) ||
+ S_ISGITLINK(ce->ce_mode))) {
+ if (tag && *tag && show_valid_bit &&
+ (ce->ce_flags & CE_VALID)) {
+ static char alttag[4];
+ memcpy(alttag, tag, 3);
+ if (isalpha(tag[0]))
+ alttag[0] = tolower(tag[0]);
+ else if (tag[0] == '?')
+ alttag[0] = '!';
+ else {
+ alttag[0] = 'v';
+ alttag[1] = tag[0];
+ alttag[2] = ' ';
+ alttag[3] = 0;
+ }
+ tag = alttag;
+ }
- if (tag && *tag && show_valid_bit &&
- (ce->ce_flags & CE_VALID)) {
- static char alttag[4];
- memcpy(alttag, tag, 3);
- if (isalpha(tag[0]))
- alttag[0] = tolower(tag[0]);
- else if (tag[0] == '?')
- alttag[0] = '!';
- else {
- alttag[0] = 'v';
- alttag[1] = tag[0];
- alttag[2] = ' ';
- alttag[3] = 0;
+ if (!show_stage) {
+ fputs(tag, stdout);
+ } else {
+ printf("%s%06o %s %d\t",
+ tag,
+ ce->ce_mode,
+ find_unique_abbrev(ce->oid.hash, abbrev),
+ ce_stage(ce));
+ }
+ write_eolinfo(ce, ce->name);
+ write_name(ce->name);
+ if (debug_mode) {
+ const struct stat_data *sd = &ce->ce_stat_data;
+
+ printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
+ printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
+ printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino);
+ printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid);
+ printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags);
}
- tag = alttag;
}
- if (!show_stage) {
- fputs(tag, stdout);
- } else {
- printf("%s%06o %s %d\t",
- tag,
- ce->ce_mode,
- find_unique_abbrev(ce->oid.hash,abbrev),
- ce_stage(ce));
- }
- write_eolinfo(ce, ce->name);
- write_name(ce->name);
- if (debug_mode) {
- const struct stat_data *sd = &ce->ce_stat_data;
-
- printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
- printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
- printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino);
- printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid);
- printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags);
- }
+ strbuf_release(&name);
}
static void show_ru_info(void)
@@ -468,6 +547,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{ OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
N_("make the output relative to the project top directory"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
+ OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
+ N_("recurse through submodules")),
OPT_BOOL(0, "error-unmatch", &error_unmatch,
N_("if any <file> is not in the index, treat this as an error")),
OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
@@ -484,6 +565,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
prefix = cmd_prefix;
if (prefix)
prefix_len = strlen(prefix);
+ super_prefix = get_super_prefix();
git_config(git_default_config, NULL);
if (read_cache() < 0)
@@ -519,13 +601,32 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
+ if (recurse_submodules)
+ compile_submodule_options(&dir, show_tag);
+
+ if (recurse_submodules &&
+ (show_stage || show_deleted || show_others || show_unmerged ||
+ show_killed || show_modified || show_resolve_undo || with_tree))
+ die("ls-files --recurse-submodules unsupported mode");
+
+ if (recurse_submodules && error_unmatch)
+ die("ls-files --recurse-submodules does not support "
+ "--error-unmatch");
+
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD |
PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
prefix, argv);
- /* Find common prefix for all pathspec's */