mirror of
https://github.com/git/git.git
synced 2026-01-23 07:17:18 +09:00
Merge branch 'cs/add-skip-submodule-ignore-all' into seen
"git add <submodule>" has been taught to honor submodule.<name>.ignore that is set to "all" (and requires "git add -f" to override it). * cs/add-skip-submodule-ignore-all: Documentation: update add --force option + ignore=all config tests: fix existing tests when add an ignore=all submodule tests: t2206-add-submodule-ignored: ignore=all and add --force tests read-cache: submodule add need --force given ignore=all configuration read-cache: update add_files_to_cache take param ignored_too
This commit is contained in:
commit
c6ca3ad9ee
@ -32,15 +32,16 @@ submodule.<name>.fetchRecurseSubmodules::
|
||||
|
||||
submodule.<name>.ignore::
|
||||
Defines under what circumstances "git status" and the diff family show
|
||||
a submodule as modified. When set to "all", it will never be considered
|
||||
modified (but it will nonetheless show up in the output of status and
|
||||
commit when it has been staged), "dirty" will ignore all changes
|
||||
to the submodule's work tree and
|
||||
a submodule as modified.
|
||||
Set to "all" will never consider the submodule modified. It can
|
||||
nevertheless be staged using the option --force and it will then show up
|
||||
in the output of status.
|
||||
Set to "dirty" will ignore all changes to the submodule's work tree and
|
||||
takes only differences between the HEAD of the submodule and the commit
|
||||
recorded in the superproject into account. "untracked" will additionally
|
||||
let submodules with modified tracked files in their work tree show up.
|
||||
Using "none" (the default when this option is not set) also shows
|
||||
submodules that have untracked files in their work tree as changed.
|
||||
Set to "none"(default) It is also shows submodules that have untracked
|
||||
files in their work tree as changed.
|
||||
This setting overrides any setting made in .gitmodules for this submodule,
|
||||
both settings can be overridden on the command line by using the
|
||||
"--ignore-submodules" option. The 'git submodule' commands are not
|
||||
|
||||
@ -75,7 +75,10 @@ in linkgit:gitglossary[7].
|
||||
|
||||
`-f`::
|
||||
`--force`::
|
||||
Allow adding otherwise ignored files.
|
||||
Allow adding otherwise ignored files. The option is also used when
|
||||
`submodule.<name>.ignore=all` is set, but you want to stage an
|
||||
update of the submodule. The `path` to the submodule must be explicitly
|
||||
specified.
|
||||
|
||||
`--sparse`::
|
||||
Allow updating index entries outside of the sparse-checkout cone.
|
||||
|
||||
@ -70,7 +70,10 @@ submodule.<name>.ignore::
|
||||
--
|
||||
all;; The submodule will never be considered modified (but will
|
||||
nonetheless show up in the output of status and commit when it has
|
||||
been staged).
|
||||
been staged). Add `(new commits)` can be overruled using the
|
||||
`git add --force <submodule.path>`.
|
||||
The setting affects `status`, `update-index`, `diff` and `log`(due
|
||||
to underlaying `diff`).
|
||||
|
||||
dirty;; All changes to the submodule's work tree will be ignored, only
|
||||
committed differences between the `HEAD` of the submodule and its
|
||||
|
||||
@ -584,7 +584,7 @@ int cmd_add(int argc,
|
||||
else
|
||||
exit_status |= add_files_to_cache(repo, prefix,
|
||||
&pathspec, ps_matched,
|
||||
include_sparse, flags);
|
||||
include_sparse, flags, ignored_too);
|
||||
|
||||
if (take_worktree_changes && !add_renormalize && !ignore_add_errors &&
|
||||
report_path_error(ps_matched, &pathspec))
|
||||
|
||||
@ -901,7 +901,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
|
||||
*/
|
||||
|
||||
add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
|
||||
0);
|
||||
0, 0);
|
||||
init_ui_merge_options(&o, the_repository);
|
||||
o.verbosity = 0;
|
||||
work = write_in_core_index_as_tree(the_repository);
|
||||
|
||||
@ -456,7 +456,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
|
||||
repo_hold_locked_index(the_repository, &index_lock,
|
||||
LOCK_DIE_ON_ERROR);
|
||||
add_files_to_cache(the_repository, also ? prefix : NULL,
|
||||
&pathspec, ps_matched, 0, 0);
|
||||
&pathspec, ps_matched, 0, 0, 0 );
|
||||
if (!all && report_path_error(ps_matched, &pathspec))
|
||||
exit(128);
|
||||
|
||||
|
||||
@ -481,7 +481,7 @@ int cmp_cache_name_compare(const void *a_, const void *b_);
|
||||
|
||||
int add_files_to_cache(struct repository *repo, const char *prefix,
|
||||
const struct pathspec *pathspec, char *ps_matched,
|
||||
int include_sparse, int flags);
|
||||
int include_sparse, int flags, int ignored_too );
|
||||
|
||||
void overlay_tree_on_index(struct index_state *istate,
|
||||
const char *tree_name, const char *prefix);
|
||||
|
||||
80
read-cache.c
80
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 */
|
||||
|
||||
@ -3889,9 +3892,12 @@ void overlay_tree_on_index(struct index_state *istate,
|
||||
|
||||
struct update_callback_data {
|
||||
struct index_state *index;
|
||||
struct repository *repo;
|
||||
struct pathspec *pathspec;
|
||||
int include_sparse;
|
||||
int flags;
|
||||
int add_errors;
|
||||
int ignored_too;
|
||||
};
|
||||
|
||||
static int fix_unmerged_status(struct diff_filepair *p,
|
||||
@ -3915,8 +3921,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;
|
||||
@ -3926,7 +3992,7 @@ 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)) {
|
||||
@ -3934,6 +4000,11 @@ static void update_callback(struct diff_queue_struct *q,
|
||||
die(_("unexpected diff status %c"), p->status);
|
||||
case DIFF_STATUS_MODIFIED:
|
||||
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"));
|
||||
@ -3954,7 +4025,7 @@ static void update_callback(struct diff_queue_struct *q,
|
||||
|
||||
int add_files_to_cache(struct repository *repo, const char *prefix,
|
||||
const struct pathspec *pathspec, char *ps_matched,
|
||||
int include_sparse, int flags)
|
||||
int include_sparse, int flags, int ignored_too )
|
||||
{
|
||||
struct odb_transaction *transaction;
|
||||
struct update_callback_data data;
|
||||
@ -3964,6 +4035,9 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
|
||||
data.index = repo->index;
|
||||
data.include_sparse = include_sparse;
|
||||
data.flags = flags;
|
||||
data.repo = repo;
|
||||
data.ignored_too = ignored_too;
|
||||
data.pathspec = (struct pathspec *)pathspec;
|
||||
|
||||
repo_init_revisions(repo, &rev, prefix);
|
||||
setup_revisions(0, NULL, &rev, NULL);
|
||||
|
||||
@ -95,14 +95,14 @@ create_lib_submodule_repo () {
|
||||
git commit -m "modified file2 and added file3" &&
|
||||
git push origin modifications
|
||||
) &&
|
||||
git add sub1 &&
|
||||
git add --force sub1 &&
|
||||
git commit -m "Modify sub1" &&
|
||||
|
||||
git checkout -b add_nested_sub modify_sub1 &&
|
||||
git -C sub1 checkout -b "add_nested_sub" &&
|
||||
git -C sub1 submodule add --branch no_submodule ../submodule_update_sub2 sub2 &&
|
||||
git -C sub1 commit -a -m "add a nested submodule" &&
|
||||
git add sub1 &&
|
||||
git add --force sub1 &&
|
||||
git commit -a -m "update submodule, that updates a nested submodule" &&
|
||||
git checkout -b modify_sub1_recursively &&
|
||||
git -C sub1 checkout -b modify_sub1_recursively &&
|
||||
@ -112,7 +112,7 @@ create_lib_submodule_repo () {
|
||||
git -C sub1/sub2 commit -m "make a change in nested sub" &&
|
||||
git -C sub1 add sub2 &&
|
||||
git -C sub1 commit -m "update nested sub" &&
|
||||
git add sub1 &&
|
||||
git add --force sub1 &&
|
||||
git commit -m "update sub1, that updates nested sub" &&
|
||||
git -C sub1 push origin modify_sub1_recursively &&
|
||||
git -C sub1/sub2 push origin modify_sub1_recursively &&
|
||||
|
||||
@ -294,6 +294,7 @@ integration_tests = [
|
||||
't2203-add-intent.sh',
|
||||
't2204-add-ignored.sh',
|
||||
't2205-add-worktree-config.sh',
|
||||
't2206-add-submodule-ignored.sh',
|
||||
't2300-cd-to-toplevel.sh',
|
||||
't2400-worktree-add.sh',
|
||||
't2401-worktree-prune.sh',
|
||||
|
||||
134
t/t2206-add-submodule-ignored.sh
Executable file
134
t/t2206-add-submodule-ignored.sh
Executable file
@ -0,0 +1,134 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2016
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
test_description='git add respects submodule ignore=all and explicit pathspec'
|
||||
|
||||
# This test covers the behavior of "git add", "git status" and "git log" when
|
||||
# dealing with submodules that have the ignore=all setting in
|
||||
# .gitmodules. It ensures that changes in such submodules are
|
||||
# ignored by default, but can be staged with "git add --force".
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
. ./test-lib.sh
|
||||
|
||||
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
||||
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||
|
||||
base_path=$(pwd -P)
|
||||
|
||||
#1
|
||||
test_expect_success 'setup: create origin repos' '
|
||||
cd "${base_path}" &&
|
||||
git config --global protocol.file.allow always &&
|
||||
git init sub &&
|
||||
pwd &&
|
||||
cd sub &&
|
||||
test_commit sub_file1 &&
|
||||
git tag v1.0 &&
|
||||
test_commit sub_file2 &&
|
||||
git tag v2.0 &&
|
||||
test_commit sub_file3 &&
|
||||
git tag v3.0 &&
|
||||
cd "${base_path}" &&
|
||||
git init main &&
|
||||
cd main &&
|
||||
test_commit first &&
|
||||
cd "${base_path}"
|
||||
'
|
||||
#2
|
||||
# add submodule with default config (ignore=none) and
|
||||
# check log that is contains a path entry for the submodule 'sub'
|
||||
# change the commit in the submodule and check that 'git status' shows it as modified
|
||||
test_expect_success 'main: add submodule with default config' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
git submodule add ../sub &&
|
||||
git commit -m "add submodule" &&
|
||||
git log --oneline --name-only | grep "^sub$" &&
|
||||
git -C sub reset --hard v2.0 &&
|
||||
git status --porcelain | grep "^ M sub$" &&
|
||||
echo
|
||||
'
|
||||
#3
|
||||
# change the submodule config to ignore=all and check that status and log do not show changes
|
||||
test_expect_success 'main: submodule config ignore=all' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
git config -f .gitmodules submodule.sub.ignore all &&
|
||||
GIT_TRACE=1 git add . &&
|
||||
git commit -m "update submodule config sub.ignore all" &&
|
||||
! git status --porcelain | grep "^.*$" &&
|
||||
! git log --oneline --name-only | grep "^sub$" &&
|
||||
echo
|
||||
'
|
||||
#4
|
||||
# change the commit in the submodule and check that 'git status' does not show it as modified
|
||||
# but 'git status --ignore-submodules=none' does show it as modified
|
||||
test_expect_success 'sub: change to different sha1 and check status in main' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
git -C sub reset --hard v1.0 &&
|
||||
! git status --porcelain | grep "^ M sub$" &&
|
||||
git status --ignore-submodules=none --porcelain | grep "^ M sub$" &&
|
||||
echo
|
||||
'
|
||||
|
||||
#5
|
||||
# check that normal 'git add' does not stage the change in the submodule
|
||||
test_expect_success 'main: check normal add and status' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
GIT_TRACE=1 git add . &&
|
||||
! git status --porcelain | grep "^ M sub$" &&
|
||||
echo
|
||||
'
|
||||
|
||||
#6
|
||||
# check that 'git add --force .' does not stage the change in the submodule
|
||||
# and that 'git status' does not show it as modified
|
||||
test_expect_success 'main: check --force add . and status' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
GIT_TRACE=1 git add --force . &&
|
||||
! git status --porcelain | grep "^M sub$" &&
|
||||
echo
|
||||
'
|
||||
|
||||
#7
|
||||
# check that 'git add .' does not stage the change in the submodule
|
||||
# and that 'git status' does not show it as modified
|
||||
test_expect_success 'main: check _add sub_ and status' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
GIT_TRACE=1 git add sub 2>&1 | grep "Skipping submodule due to ignore=all: sub" &&
|
||||
! git status --porcelain | grep "^M sub$" &&
|
||||
echo
|
||||
'
|
||||
|
||||
#8
|
||||
# check that 'git add --force sub' does stage the change in the submodule
|
||||
# check that 'git add --force ./sub/' does stage the change in the submodule
|
||||
# and that 'git status --porcelain' does show it as modified
|
||||
# commit it..
|
||||
# check that 'git log --ignore-submodules=none' shows the submodule change
|
||||
# in the log
|
||||
test_expect_success 'main: check force add sub and ./sub/ and status' '
|
||||
cd "${base_path}" &&
|
||||
cd main &&
|
||||
echo "Adding with --force should work: git add --force sub" &&
|
||||
GIT_TRACE=1 git add --force sub &&
|
||||
git status --porcelain | grep "^M sub$" &&
|
||||
git restore --staged sub &&
|
||||
! git status --porcelain | grep "^M sub$" &&
|
||||
echo "Adding with --force should work: git add --force ./sub/" &&
|
||||
GIT_TRACE=1 git add --force ./sub/ &&
|
||||
git status --porcelain | grep "^M sub$" &&
|
||||
git commit -m "update submodule pointer" &&
|
||||
! git status --porcelain | grep "^ M sub$" &&
|
||||
git log --ignore-submodules=none --name-only --oneline | grep "^sub$" &&
|
||||
echo
|
||||
'
|
||||
|
||||
test_done
|
||||
exit 0
|
||||
@ -1576,7 +1576,7 @@ test_expect_success 'git commit will commit a staged but ignored submodule' '
|
||||
|
||||
test_expect_success 'git commit --dry-run will show a staged but ignored submodule' '
|
||||
git reset HEAD^ &&
|
||||
git add sm &&
|
||||
git add --force sm &&
|
||||
cat >expect << EOF &&
|
||||
On branch main
|
||||
Your branch and '\''upstream'\'' have diverged,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user