mirror of
https://github.com/git/git.git
synced 2026-03-19 05:00:08 +01:00
Merge branch 'jl/fetch-submodule-recursive' into next
* jl/fetch-submodule-recursive: Submodules: Add the new "fetch" config option for fetch and pull fetch/pull: Recursively fetch populated submodules
This commit is contained in:
@@ -1787,6 +1787,12 @@ submodule.<name>.update::
|
||||
URL and other values found in the `.gitmodules` file. See
|
||||
linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
|
||||
|
||||
submodule.<name>.fetch::
|
||||
A boolean to enable/disable recursive fetching of this submodule. It can
|
||||
be overriden by using the --[no-]recursive command line option to "git
|
||||
fetch" and "git pull". This setting overrides any setting made in
|
||||
.gitmodules for this submodule.
|
||||
|
||||
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
|
||||
|
||||
@@ -64,6 +64,12 @@ endif::git-pull[]
|
||||
specified with the remote.<name>.tagopt setting. See
|
||||
linkgit:git-config[1].
|
||||
|
||||
--[no-]recursive::
|
||||
By default new commits of all populated submodules will be fetched
|
||||
too. This option can be used to disable/enable recursive fetching of
|
||||
submodules regardless of the 'fetch' configuration setting (see
|
||||
linkgit:git-config[1] or linkgit:gitmodules[5]).
|
||||
|
||||
-u::
|
||||
--update-head-ok::
|
||||
By default 'git fetch' refuses to update the head which
|
||||
|
||||
@@ -44,6 +44,14 @@ submodule.<name>.update::
|
||||
This config option is overridden if 'git submodule update' is given
|
||||
the '--merge' or '--rebase' options.
|
||||
|
||||
submodule.<name>.fetch::
|
||||
A boolean to enable/disable recursive fetching of this submodule.
|
||||
If this option is also present in the submodules entry in .git/config of
|
||||
the superproject, the setting there will override the one found in
|
||||
.gitmodules.
|
||||
Both settings can be overriden on the command line by using the
|
||||
"--[no-]recursive" option to "git fetch" and "git pull"..
|
||||
|
||||
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
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "parse-options.h"
|
||||
#include "sigchain.h"
|
||||
#include "transport.h"
|
||||
#include "submodule.h"
|
||||
|
||||
static const char * const builtin_fetch_usage[] = {
|
||||
"git fetch [<options>] [<repository> [<refspec>...]]",
|
||||
@@ -27,7 +28,13 @@ enum {
|
||||
TAGS_SET = 2
|
||||
};
|
||||
|
||||
static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
|
||||
enum {
|
||||
RECURSIVE_UNSET = 0,
|
||||
RECURSIVE_DEFAULT = 1,
|
||||
RECURSIVE_SET = 2
|
||||
};
|
||||
|
||||
static int all, append, dry_run, force, keep, multiple, prune, recursive = RECURSIVE_DEFAULT, update_head_ok, verbosity;
|
||||
static int progress;
|
||||
static int tags = TAGS_DEFAULT;
|
||||
static const char *depth;
|
||||
@@ -53,6 +60,8 @@ static struct option builtin_fetch_options[] = {
|
||||
"do not fetch all tags (--no-tags)", TAGS_UNSET),
|
||||
OPT_BOOLEAN('p', "prune", &prune,
|
||||
"prune tracking branches no longer on remote"),
|
||||
OPT_SET_INT(0, "recursive", &recursive,
|
||||
"control recursive fetching of submodules", RECURSIVE_SET),
|
||||
OPT_BOOLEAN(0, "dry-run", &dry_run,
|
||||
"dry run"),
|
||||
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
|
||||
@@ -926,6 +935,12 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (!result && recursive) {
|
||||
gitmodules_config();
|
||||
git_config(submodule_config, NULL);
|
||||
result = fetch_populated_submodules(recursive == RECURSIVE_SET);
|
||||
}
|
||||
|
||||
/* All names were strdup()ed or strndup()ed */
|
||||
list.strdup_strings = 1;
|
||||
string_list_clear(&list, 0);
|
||||
|
||||
10
git-pull.sh
10
git-pull.sh
@@ -38,7 +38,7 @@ test -z "$(git ls-files -u)" || die_conflict
|
||||
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
|
||||
|
||||
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
|
||||
log_arg= verbosity= progress=
|
||||
log_arg= verbosity= progress= recursive=
|
||||
merge_args=
|
||||
curr_branch=$(git symbolic-ref -q HEAD)
|
||||
curr_branch_short="${curr_branch#refs/heads/}"
|
||||
@@ -105,6 +105,12 @@ do
|
||||
--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
|
||||
rebase=false
|
||||
;;
|
||||
--recursive)
|
||||
recursive=--recursive
|
||||
;;
|
||||
--no-recursive)
|
||||
recursive=--no-recursive
|
||||
;;
|
||||
--d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
|
||||
dry_run=--dry-run
|
||||
;;
|
||||
@@ -220,7 +226,7 @@ test true = "$rebase" && {
|
||||
done
|
||||
}
|
||||
orig_head=$(git rev-parse -q --verify HEAD)
|
||||
git fetch $verbosity $progress $dry_run --update-head-ok "$@" || exit 1
|
||||
git fetch $verbosity $progress $dry_run $recursive --update-head-ok "$@" || exit 1
|
||||
test -z "$dry_run" || exit 0
|
||||
|
||||
curr_head=$(git rev-parse -q --verify HEAD)
|
||||
|
||||
60
submodule.c
60
submodule.c
@@ -10,6 +10,7 @@
|
||||
#include "string-list.h"
|
||||
|
||||
struct string_list config_name_for_path;
|
||||
struct string_list config_fetch_for_name;
|
||||
struct string_list config_ignore_for_name;
|
||||
|
||||
static int add_submodule_odb(const char *path)
|
||||
@@ -63,7 +64,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
|
||||
}
|
||||
}
|
||||
|
||||
static int submodule_config(const char *var, const char *value, void *cb)
|
||||
int submodule_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!prefixcmp(var, "submodule."))
|
||||
return parse_submodule_config_option(var, value);
|
||||
@@ -100,6 +101,14 @@ int parse_submodule_config_option(const char *var, const char *value)
|
||||
config = string_list_append(&config_name_for_path, xstrdup(value));
|
||||
config->util = strbuf_detach(&submodname, NULL);
|
||||
strbuf_release(&submodname);
|
||||
} else if ((len > 5) && !strcmp(var + len - 6, ".fetch")) {
|
||||
strbuf_add(&submodname, var, len - 6);
|
||||
config = unsorted_string_list_lookup(&config_fetch_for_name, submodname.buf);
|
||||
if (!config)
|
||||
config = string_list_append(&config_fetch_for_name,
|
||||
strbuf_detach(&submodname, NULL));
|
||||
config->util = git_config_bool(var, value) ? (void *)1 : NULL;
|
||||
strbuf_release(&submodname);
|
||||
} else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) {
|
||||
if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
|
||||
strcmp(value, "all") && strcmp(value, "none")) {
|
||||
@@ -229,6 +238,55 @@ void show_submodule_summary(FILE *f, const char *path,
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
int fetch_populated_submodules(int forced)
|
||||
{
|
||||
int result = 0;
|
||||
struct child_process cp;
|
||||
const char *argv[] = {
|
||||
"fetch",
|
||||
NULL,
|
||||
};
|
||||
struct string_list_item *name_for_path;
|
||||
const char *work_tree = get_git_work_tree();
|
||||
if (!work_tree)
|
||||
return 0;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.argv = argv;
|
||||
cp.env = local_repo_env;
|
||||
cp.git_cmd = 1;
|
||||
cp.no_stdin = 1;
|
||||
cp.out = -1;
|
||||
|
||||
for_each_string_list_item(name_for_path, &config_name_for_path) {
|
||||
struct strbuf submodule_path = STRBUF_INIT;
|
||||
struct strbuf submodule_git_dir = STRBUF_INIT;
|
||||
const char *git_dir;
|
||||
|
||||
if (!forced) {
|
||||
struct string_list_item *fetch_option;
|
||||
fetch_option = unsorted_string_list_lookup(&config_fetch_for_name, name_for_path->util);
|
||||
if (fetch_option && !fetch_option->util)
|
||||
continue;
|
||||
}
|
||||
|
||||
strbuf_addf(&submodule_path, "%s/%s", work_tree, name_for_path->string);
|
||||
strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf);
|
||||
git_dir = read_gitfile_gently(submodule_git_dir.buf);
|
||||
if (!git_dir)
|
||||
git_dir = submodule_git_dir.buf;
|
||||
if (is_directory(git_dir)) {
|
||||
printf("Fetching submodule %s\n", name_for_path->string);
|
||||
cp.dir = submodule_path.buf;
|
||||
if (run_command(&cp))
|
||||
result = 1;
|
||||
}
|
||||
strbuf_release(&submodule_path);
|
||||
strbuf_release(&submodule_git_dir);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned is_submodule_modified(const char *path, int ignore_untracked)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
@@ -5,6 +5,7 @@ struct diff_options;
|
||||
|
||||
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
|
||||
const char *path);
|
||||
int submodule_config(const char *var, const char *value, void *cb);
|
||||
void gitmodules_config();
|
||||
int parse_submodule_config_option(const char *var, const char *value);
|
||||
void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
|
||||
@@ -12,6 +13,7 @@ void show_submodule_summary(FILE *f, const char *path,
|
||||
unsigned char one[20], unsigned char two[20],
|
||||
unsigned dirty_submodule,
|
||||
const char *del, const char *add, const char *reset);
|
||||
int fetch_populated_submodules(int forced);
|
||||
unsigned is_submodule_modified(const char *path, int ignore_untracked);
|
||||
int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],
|
||||
const unsigned char a[20], const unsigned char b[20]);
|
||||
|
||||
104
t/t5526-fetch-submodules.sh
Executable file
104
t/t5526-fetch-submodules.sh
Executable file
@@ -0,0 +1,104 @@
|
||||
#!/bin/sh
|
||||
# Copyright (c) 2010, Jens Lehmann
|
||||
|
||||
test_description='Recursive "git fetch" for submodules'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
pwd=$(pwd)
|
||||
|
||||
add_upstream_commit() {
|
||||
(
|
||||
cd submodule &&
|
||||
head1=$(git rev-parse --short HEAD) &&
|
||||
echo new >> subfile &&
|
||||
test_tick &&
|
||||
git add subfile &&
|
||||
git commit -m new subfile &&
|
||||
head2=$(git rev-parse --short HEAD) &&
|
||||
echo "From $pwd/submodule" > ../expect.err
|
||||
echo " $head1..$head2 master -> origin/master" >> ../expect.err
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
mkdir submodule &&
|
||||
(
|
||||
cd submodule &&
|
||||
git init &&
|
||||
echo subcontent > subfile &&
|
||||
git add subfile &&
|
||||
git commit -m new subfile
|
||||
) &&
|
||||
git submodule add "$pwd/submodule" submodule &&
|
||||
git commit -am initial &&
|
||||
git clone . downstream &&
|
||||
(
|
||||
cd downstream &&
|
||||
git submodule init &&
|
||||
git submodule update
|
||||
) &&
|
||||
echo "Fetching submodule submodule" > expect.out
|
||||
'
|
||||
|
||||
test_expect_success "fetch recurses into submodules" '
|
||||
add_upstream_commit &&
|
||||
(
|
||||
cd downstream &&
|
||||
git fetch >../actual.out 2>../actual.err
|
||||
) &&
|
||||
test_cmp expect.out actual.out &&
|
||||
test_cmp expect.err actual.err
|
||||
'
|
||||
|
||||
test_expect_success "fetch --no-recursive only fetches superproject" '
|
||||
(
|
||||
cd downstream &&
|
||||
git fetch --no-recursive >../actual.out 2>../actual.err
|
||||
) &&
|
||||
! test -s actual.out &&
|
||||
! test -s actual.err
|
||||
'
|
||||
|
||||
test_expect_success "using fetch=false in .gitmodules only fetches superproject" '
|
||||
(
|
||||
cd downstream &&
|
||||
git config -f .gitmodules submodule.submodule.fetch false &&
|
||||
git fetch >../actual.out 2>../actual.err
|
||||
) &&
|
||||
! test -s actual.out &&
|
||||
! test -s actual.err
|
||||
'
|
||||
|
||||
test_expect_success "--recursive overrides .gitmodules config" '
|
||||
add_upstream_commit &&
|
||||
(
|
||||
cd downstream &&
|
||||
git fetch --recursive >../actual.out 2>../actual.err
|
||||
) &&
|
||||
test_cmp expect.out actual.out &&
|
||||
test_cmp expect.err actual.err
|
||||
'
|
||||
|
||||
test_expect_success "using fetch=true in .git/config overrides setting in .gitmodules" '
|
||||
add_upstream_commit &&
|
||||
(
|
||||
cd downstream &&
|
||||
git config submodule.submodule.fetch true &&
|
||||
git fetch >../actual.out 2>../actual.err
|
||||
) &&
|
||||
test_cmp expect.out actual.out &&
|
||||
test_cmp expect.err actual.err
|
||||
'
|
||||
|
||||
test_expect_success "--no-recursive overrides fetch setting from .git/config" '
|
||||
add_upstream_commit &&
|
||||
(
|
||||
cd downstream &&
|
||||
git fetch --no-recursive >../actual.out 2>../actual.err
|
||||
) &&
|
||||
! test -s actual.out &&
|
||||
! test -s actual.err
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -50,7 +50,7 @@ test_expect_success 'change submodule url' '
|
||||
|
||||
test_expect_success '"git submodule sync" should update submodule URLs' '
|
||||
(cd super-clone &&
|
||||
git pull &&
|
||||
git pull --no-recursive &&
|
||||
git submodule sync
|
||||
) &&
|
||||
test -d "$(git config -f super-clone/submodule/.git/config \
|
||||
|
||||
Reference in New Issue
Block a user