diff options
| author | Claus Schneider(Eficode) <claus.schneider@eficode.com> | 2026-02-06 13:22:57 +0000 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-02-06 09:43:26 -0800 |
| commit | a16c4a245acb2420bafcbd572ba9fb94b1ba5146 (patch) | |
| tree | dcd0b573b4e458a3388b97647ba3ad50652c4821 /read-cache.c | |
| parent | 37196d8995ee60e08230c5d05dfd26204d604580 (diff) | |
| download | git-a16c4a245acb2420bafcbd572ba9fb94b1ba5146.tar.xz | |
read-cache: submodule add need --force given ignore=all configuration
Submodules configured with ignore=all are now skipped during add operations
unless overridden by --force and the submodule path is explicitly specified.
A message is printed (like ignored files) guiding the user to use the
--force flag if the user explicitly wants to update the submodule reference.
The reason for the change is to support branch tracking in submodules
with configuration `submdule.<name>.branch` or similar workflows where the
user is not interested in tracking each update of the sha1 in the submdule.
You can additionally set `submodule.<name>.ignore=all` and the `git status`
will state nothing and, with this patch, the `git add` does not either - as
the default behaviour. This patch changes the workflow to a more logical
behaviour and similar to workflow for ignored files.
The patch gives more scenarios for submodules to be used effectively with
less friction similar to the "repo" tool. A submodule can be added for many
different reasons than a hard dependency. It can be added as loosely
coupled dependencies whereas the user wants the latest based on the
configuration `submoule.<name>.branch`, but are not interested to track
each commit in the `super-repo`. Currently it gives friction of handling
conflicts between branches even the sha1's are fast-forward and the user
just wants the latest in any way. The user can still add a sha1 explicitly
to track updates.
Signed-off-by: Claus Schneider(Eficode) <claus.schneider@eficode.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'read-cache.c')
| -rw-r--r-- | read-cache.c | 74 |
1 files changed, 71 insertions, 3 deletions
diff --git a/read-cache.c b/read-cache.c index 5349b94e59..b5ed66f6b7 100644 --- a/read-cache.c +++ b/read-cache.c @@ -47,6 +47,9 @@ #include "csum-file.h" #include "promisor-remote.h" #include "hook.h" +#include "submodule.h" +#include "submodule-config.h" +#include "advice.h" /* Mask for the name length in ce_flags in the on-disk index */ @@ -3907,8 +3910,68 @@ static int fix_unmerged_status(struct diff_filepair *p, return DIFF_STATUS_MODIFIED; } +static int skip_submodule(const char *path, + struct repository *repo, + struct pathspec *pathspec, + int ignored_too) +{ + struct stat st; + const struct submodule *sub; + int pathspec_matches = 0; + int ps_i; + char *norm_pathspec = NULL; + + /* Only consider if path is a directory */ + if (lstat(path, &st) || !S_ISDIR(st.st_mode)) + return 0; + + /* Check if it's a submodule with ignore=all */ + sub = submodule_from_path(repo, null_oid(the_hash_algo), path); + if (!sub || !sub->name || !sub->ignore || strcmp(sub->ignore, "all")) + return 0; + + trace_printf("ignore=all: %s\n", path); + trace_printf("pathspec %s\n", (pathspec && pathspec->nr) + ? "has pathspec" + : "no pathspec"); + + /* Check if submodule path is explicitly mentioned in pathspec */ + if (pathspec) { + for (ps_i = 0; ps_i < pathspec->nr; ps_i++) { + const char *m = pathspec->items[ps_i].match; + if (!m) + continue; + norm_pathspec = xstrdup(m); + strip_dir_trailing_slashes(norm_pathspec); + if (!strcmp(path, norm_pathspec)) { + pathspec_matches = 1; + FREE_AND_NULL(norm_pathspec); + break; + } + FREE_AND_NULL(norm_pathspec); + } + } + + /* If explicitly matched and forced, allow adding */ + if (pathspec_matches) { + if (ignored_too && ignored_too > 0) { + trace_printf("Add submodule due to --force: %s\n", path); + return 0; + } else { + advise_if_enabled(ADVICE_ADD_IGNORED_FILE, + _("Skipping submodule due to ignore=all: %s\n" + "Use --force if you really want to add the submodule."), path); + return 1; + } + } + + /* No explicit pathspec match -> skip silently */ + trace_printf("Pathspec to submodule does not match explicitly: %s\n", path); + return 1; +} + static void update_callback(struct diff_queue_struct *q, - struct diff_options *opt UNUSED, void *cbdata) + struct diff_options *opt UNUSED, void *cbdata) { int i; struct update_callback_data *data = cbdata; @@ -3918,14 +3981,19 @@ static void update_callback(struct diff_queue_struct *q, const char *path = p->one->path; if (!data->include_sparse && - !path_in_sparse_checkout(path, data->index)) + !path_in_sparse_checkout(path, data->index)) continue; switch (fix_unmerged_status(p, data)) { default: die(_("unexpected diff status %c"), p->status); case DIFF_STATUS_MODIFIED: - case DIFF_STATUS_TYPE_CHANGED: { + case DIFF_STATUS_TYPE_CHANGED: + if (skip_submodule(path, data->repo, + data->pathspec, + data->ignored_too)) + continue; + if (add_file_to_index(data->index, path, data->flags)) { if (!(data->flags & ADD_CACHE_IGNORE_ERRORS)) die(_("updating files failed")); |
