From: Junio C Hamano Date: Tue, 31 Jan 2017 21:14:56 +0000 (-0800) Subject: Merge branch 'bw/push-submodule-only' X-Git-Tag: v2.12.0-rc0~42 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/792e22e3fd99f204be11b0ff173f2d991308dca5?hp=-c Merge branch 'bw/push-submodule-only' "git submodule push" learned "--recurse-submodules=only option to push submodules out without pushing the top-level superproject. * bw/push-submodule-only: push: add option to push only submodules submodules: add RECURSE_SUBMODULES_ONLY value transport: reformat flag #defines to be more readable --- 792e22e3fd99f204be11b0ff173f2d991308dca5 diff --combined builtin/push.c index 9307ad56a9,9433797539..5c22e9f2e5 --- a/builtin/push.c +++ b/builtin/push.c @@@ -194,18 -194,15 +194,18 @@@ static void setup_push_upstream(struct die_push_simple(branch, remote); } - strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src); + strbuf_addf(&refspec, "%s:%s", branch->refname, branch->merge[0]->src); add_refspec(refspec.buf); } static void setup_push_current(struct remote *remote, struct branch *branch) { + struct strbuf refspec = STRBUF_INIT; + if (!branch) die(_(message_detached_head_die), remote->name); - add_refspec(branch->name); + strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname); + add_refspec(refspec.buf); } static int is_workflow_triangular(struct remote *remote) @@@ -568,6 -565,8 +568,8 @@@ int cmd_push(int argc, const char **arg flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK; else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND; + else if (recurse_submodules == RECURSE_SUBMODULES_ONLY) + flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY; if (tags) add_refspec("refs/tags/*"); diff --combined submodule-config.c index 4bf50f398a,33eb62d31a..93453909cf --- a/submodule-config.c +++ b/submodule-config.c @@@ -251,6 -251,8 +251,8 @@@ static int parse_push_recurse(const cha return RECURSE_SUBMODULES_ON_DEMAND; else if (!strcmp(arg, "check")) return RECURSE_SUBMODULES_CHECK; + else if (!strcmp(arg, "only")) + return RECURSE_SUBMODULES_ONLY; else if (die_on_error) die("bad %s argument: %s", opt, arg); else @@@ -263,12 -265,12 +265,12 @@@ int parse_push_recurse_submodules_arg(c return parse_push_recurse(opt, arg, 1); } -static void warn_multiple_config(const unsigned char *commit_sha1, +static void warn_multiple_config(const unsigned char *treeish_name, const char *name, const char *option) { const char *commit_string = "WORKTREE"; - if (commit_sha1) - commit_string = sha1_to_hex(commit_sha1); + if (treeish_name) + commit_string = sha1_to_hex(treeish_name); warning("%s:.gitmodules, multiple configurations found for " "'submodule.%s.%s'. Skipping second one!", commit_string, name, option); @@@ -276,7 -278,7 +278,7 @@@ struct parse_config_parameter { struct submodule_cache *cache; - const unsigned char *commit_sha1; + const unsigned char *treeish_name; const unsigned char *gitmodules_sha1; int overwrite; }; @@@ -300,7 -302,7 +302,7 @@@ static int parse_config(const char *var if (!value) ret = config_error_nonbool(var); else if (!me->overwrite && submodule->path) - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "path"); else { if (submodule->path) @@@ -314,7 -316,7 +316,7 @@@ int die_on_error = is_null_sha1(me->gitmodules_sha1); if (!me->overwrite && submodule->fetch_recurse != RECURSE_SUBMODULES_NONE) - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "fetchrecursesubmodules"); else submodule->fetch_recurse = parse_fetch_recurse( @@@ -324,7 -326,7 +326,7 @@@ if (!value) ret = config_error_nonbool(var); else if (!me->overwrite && submodule->ignore) - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "ignore"); else if (strcmp(value, "untracked") && strcmp(value, "dirty") && @@@ -340,7 -342,7 +342,7 @@@ if (!value) { ret = config_error_nonbool(var); } else if (!me->overwrite && submodule->url) { - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "url"); } else { free((void *) submodule->url); @@@ -351,21 -353,21 +353,21 @@@ ret = config_error_nonbool(var); else if (!me->overwrite && submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED) - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "update"); else if (parse_submodule_update_strategy(value, &submodule->update_strategy) < 0) die(_("invalid value for %s"), var); } else if (!strcmp(item.buf, "shallow")) { if (!me->overwrite && submodule->recommend_shallow != -1) - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "shallow"); else submodule->recommend_shallow = git_config_bool(var, value); } else if (!strcmp(item.buf, "branch")) { if (!me->overwrite && submodule->branch) - warn_multiple_config(me->commit_sha1, submodule->name, + warn_multiple_config(me->treeish_name, submodule->name, "branch"); else { free((void *)submodule->branch); @@@ -379,18 -381,18 +381,18 @@@ return ret; } -static int gitmodule_sha1_from_commit(const unsigned char *commit_sha1, +int gitmodule_sha1_from_commit(const unsigned char *treeish_name, unsigned char *gitmodules_sha1, struct strbuf *rev) { int ret = 0; - if (is_null_sha1(commit_sha1)) { + if (is_null_sha1(treeish_name)) { hashclr(gitmodules_sha1); return 1; } - strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(commit_sha1)); + strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name)); if (get_sha1(rev->buf, gitmodules_sha1) >= 0) ret = 1; @@@ -402,7 -404,7 +404,7 @@@ * revisions. */ static const struct submodule *config_from(struct submodule_cache *cache, - const unsigned char *commit_sha1, const char *key, + const unsigned char *treeish_name, const char *key, enum lookup_type lookup_type) { struct strbuf rev = STRBUF_INIT; @@@ -418,7 -420,7 +420,7 @@@ * return the first submodule. Can be used to check whether * there are any submodules parsed. */ - if (!commit_sha1 || !key) { + if (!treeish_name || !key) { struct hashmap_iter iter; struct submodule_entry *entry; @@@ -428,7 -430,7 +430,7 @@@ return entry->config; } - if (!gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) + if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev)) goto out; switch (lookup_type) { @@@ -448,7 -450,7 +450,7 @@@ /* fill the submodule config into the cache */ parameter.cache = cache; - parameter.commit_sha1 = commit_sha1; + parameter.treeish_name = treeish_name; parameter.gitmodules_sha1 = sha1; parameter.overwrite = 0; git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf, @@@ -471,6 -473,18 +473,6 @@@ out return submodule; } -static const struct submodule *config_from_path(struct submodule_cache *cache, - const unsigned char *commit_sha1, const char *path) -{ - return config_from(cache, commit_sha1, path, lookup_path); -} - -static const struct submodule *config_from_name(struct submodule_cache *cache, - const unsigned char *commit_sha1, const char *name) -{ - return config_from(cache, commit_sha1, name, lookup_name); -} - static void ensure_cache_init(void) { if (is_cache_init) @@@ -484,7 -498,7 +486,7 @@@ int parse_submodule_config_option(cons { struct parse_config_parameter parameter; parameter.cache = &the_submodule_cache; - parameter.commit_sha1 = NULL; + parameter.treeish_name = NULL; parameter.gitmodules_sha1 = null_sha1; parameter.overwrite = 1; @@@ -492,18 -506,18 +494,18 @@@ return parse_config(var, value, ¶meter); } -const struct submodule *submodule_from_name(const unsigned char *commit_sha1, +const struct submodule *submodule_from_name(const unsigned char *treeish_name, const char *name) { ensure_cache_init(); - return config_from_name(&the_submodule_cache, commit_sha1, name); + return config_from(&the_submodule_cache, treeish_name, name, lookup_name); } -const struct submodule *submodule_from_path(const unsigned char *commit_sha1, +const struct submodule *submodule_from_path(const unsigned char *treeish_name, const char *path) { ensure_cache_init(); - return config_from_path(&the_submodule_cache, commit_sha1, path); + return config_from(&the_submodule_cache, treeish_name, path, lookup_path); } void submodule_free(void) diff --combined submodule.h index b7fe4d2027,4a83a4c8df..05ab674f06 --- a/submodule.h +++ b/submodule.h @@@ -6,6 -6,7 +6,7 @@@ struct argv_array struct sha1_array; enum { + RECURSE_SUBMODULES_ONLY = -5, RECURSE_SUBMODULES_CHECK = -4, RECURSE_SUBMODULES_ERROR = -3, RECURSE_SUBMODULES_NONE = -2, @@@ -30,66 -31,52 +31,66 @@@ struct submodule_update_strategy }; #define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL} -int is_staging_gitmodules_ok(void); -int update_path_in_gitmodules(const char *oldpath, const char *newpath); -int remove_path_from_gitmodules(const char *path); -void stage_updated_gitmodules(void); -void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, +extern int is_staging_gitmodules_ok(void); +extern int update_path_in_gitmodules(const char *oldpath, const char *newpath); +extern int remove_path_from_gitmodules(const char *path); +extern void stage_updated_gitmodules(void); +extern void set_diffopt_flags_from_submodule_config(struct diff_options *, const char *path); -int submodule_config(const char *var, const char *value, void *cb); -void gitmodules_config(void); -int parse_submodule_update_strategy(const char *value, +extern int submodule_config(const char *var, const char *value, void *cb); +extern void gitmodules_config(void); +extern void gitmodules_config_sha1(const unsigned char *commit_sha1); +extern int is_submodule_initialized(const char *path); +extern int is_submodule_populated(const char *path); +extern int parse_submodule_update_strategy(const char *value, struct submodule_update_strategy *dst); -const char *submodule_strategy_to_string(const struct submodule_update_strategy *s); -void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); -void show_submodule_summary(FILE *f, const char *path, +extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s); +extern void handle_ignore_submodules_arg(struct diff_options *, const char *); +extern void show_submodule_summary(FILE *f, const char *path, const char *line_prefix, struct object_id *one, struct object_id *two, unsigned dirty_submodule, const char *meta, const char *del, const char *add, const char *reset); -void show_submodule_inline_diff(FILE *f, const char *path, +extern void show_submodule_inline_diff(FILE *f, const char *path, const char *line_prefix, struct object_id *one, struct object_id *two, unsigned dirty_submodule, const char *meta, const char *del, const char *add, const char *reset, const struct diff_options *opt); -void set_config_fetch_recurse_submodules(int value); -void check_for_new_submodule_commits(unsigned char new_sha1[20]); -int fetch_populated_submodules(const struct argv_array *options, +extern void set_config_fetch_recurse_submodules(int value); +extern void check_for_new_submodule_commits(unsigned char new_sha1[20]); +extern int fetch_populated_submodules(const struct argv_array *options, const char *prefix, int command_line_option, int quiet, int max_parallel_jobs); -unsigned is_submodule_modified(const char *path, int ignore_untracked); -int submodule_uses_gitfile(const char *path); -int ok_to_remove_submodule(const char *path); -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], int search); -int find_unpushed_submodules(struct sha1_array *commits, const char *remotes_name, - struct string_list *needs_pushing); +extern unsigned is_submodule_modified(const char *path, int ignore_untracked); +extern int submodule_uses_gitfile(const char *path); + +#define SUBMODULE_REMOVAL_DIE_ON_ERROR (1<<0) +#define SUBMODULE_REMOVAL_IGNORE_UNTRACKED (1<<1) +#define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<2) +extern int bad_to_remove_submodule(const char *path, unsigned flags); +extern 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], int search); +extern int find_unpushed_submodules(struct sha1_array *commits, + const char *remotes_name, + struct string_list *needs_pushing); extern int push_unpushed_submodules(struct sha1_array *commits, const char *remotes_name, int dry_run); -void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir); -int parallel_submodules(void); +extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir); +extern int parallel_submodules(void); /* * Prepare the "env_array" parameter of a "struct child_process" for executing * a submodule by clearing any repo-specific envirionment variables, but * retaining any config in the environment. */ -void prepare_submodule_repo_env(struct argv_array *out); +extern void prepare_submodule_repo_env(struct argv_array *out); +#define ABSORB_GITDIR_RECURSE_SUBMODULES (1<<0) +extern void absorb_git_dir_into_superproject(const char *prefix, + const char *path, + unsigned flags); #endif diff --combined transport.c index c86ba2eb89,20ebee84c3..d72e089484 --- a/transport.c +++ b/transport.c @@@ -664,89 -664,21 +664,89 @@@ static const struct string_list *protoc return enabled ? &allowed : NULL; } -int is_transport_allowed(const char *type) +enum protocol_allow_config { + PROTOCOL_ALLOW_NEVER = 0, + PROTOCOL_ALLOW_USER_ONLY, + PROTOCOL_ALLOW_ALWAYS +}; + +static enum protocol_allow_config parse_protocol_config(const char *key, + const char *value) { - const struct string_list *allowed = protocol_whitelist(); - return !allowed || string_list_has_string(allowed, type); + if (!strcasecmp(value, "always")) + return PROTOCOL_ALLOW_ALWAYS; + else if (!strcasecmp(value, "never")) + return PROTOCOL_ALLOW_NEVER; + else if (!strcasecmp(value, "user")) + return PROTOCOL_ALLOW_USER_ONLY; + + die("unknown value for config '%s': %s", key, value); } -void transport_check_allowed(const char *type) +static enum protocol_allow_config get_protocol_config(const char *type) { - if (!is_transport_allowed(type)) - die("transport '%s' not allowed", type); + char *key = xstrfmt("protocol.%s.allow", type); + char *value; + + /* first check the per-protocol config */ + if (!git_config_get_string(key, &value)) { + enum protocol_allow_config ret = + parse_protocol_config(key, value); + free(key); + free(value); + return ret; + } + free(key); + + /* if defined, fallback to user-defined default for unknown protocols */ + if (!git_config_get_string("protocol.allow", &value)) { + enum protocol_allow_config ret = + parse_protocol_config("protocol.allow", value); + free(value); + return ret; + } + + /* fallback to built-in defaults */ + /* known safe */ + if (!strcmp(type, "http") || + !strcmp(type, "https") || + !strcmp(type, "git") || + !strcmp(type, "ssh") || + !strcmp(type, "file")) + return PROTOCOL_ALLOW_ALWAYS; + + /* known scary; err on the side of caution */ + if (!strcmp(type, "ext")) + return PROTOCOL_ALLOW_NEVER; + + /* unknown; by default let them be used only directly by the user */ + return PROTOCOL_ALLOW_USER_ONLY; } -int transport_restrict_protocols(void) +int is_transport_allowed(const char *type, int from_user) { - return !!protocol_whitelist(); + const struct string_list *whitelist = protocol_whitelist(); + if (whitelist) + return string_list_has_string(whitelist, type); + + switch (get_protocol_config(type)) { + case PROTOCOL_ALLOW_ALWAYS: + return 1; + case PROTOCOL_ALLOW_NEVER: + return 0; + case PROTOCOL_ALLOW_USER_ONLY: + if (from_user < 0) + from_user = git_env_bool("GIT_PROTOCOL_FROM_USER", 1); + return from_user; + } + + die("BUG: invalid protocol_allow_config type"); +} + +void transport_check_allowed(const char *type) +{ + if (!is_transport_allowed(type, -1)) + die("transport '%s' not allowed", type); } struct transport *transport_get(struct remote *remote, const char *url) @@@ -1015,7 -947,9 +1015,9 @@@ int transport_push(struct transport *tr if (run_pre_push_hook(transport, remote_refs)) return -1; - if ((flags & TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND) && !is_bare_repository()) { + if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND | + TRANSPORT_RECURSE_SUBMODULES_ONLY)) && + !is_bare_repository()) { struct ref *ref = remote_refs; struct sha1_array commits = SHA1_ARRAY_INIT; @@@ -1033,7 -967,8 +1035,8 @@@ } if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) || - ((flags & TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND) && + ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND | + TRANSPORT_RECURSE_SUBMODULES_ONLY)) && !pretend)) && !is_bare_repository()) { struct ref *ref = remote_refs; struct string_list needs_pushing = STRING_LIST_INIT_DUP; @@@ -1052,7 -987,10 +1055,10 @@@ sha1_array_clear(&commits); } - push_ret = transport->push_refs(transport, remote_refs, flags); + if (!(flags & TRANSPORT_RECURSE_SUBMODULES_ONLY)) + push_ret = transport->push_refs(transport, remote_refs, flags); + else + push_ret = 0; err = push_had_errors(remote_refs); ret = push_ret | err; @@@ -1064,7 -1002,8 +1070,8 @@@ if (flags & TRANSPORT_PUSH_SET_UPSTREAM) set_upstreams(transport, remote_refs, pretend); - if (!(flags & TRANSPORT_PUSH_DRY_RUN)) { + if (!(flags & (TRANSPORT_PUSH_DRY_RUN | + TRANSPORT_RECURSE_SUBMODULES_ONLY))) { struct ref *ref; for (ref = remote_refs; ref; ref = ref->next) transport_update_tracking_ref(transport->remote, ref, verbose); @@@ -1214,7 -1153,7 +1221,7 @@@ static int refs_from_alternate_cb(struc const struct ref *extra; struct alternate_refs_data *cb = data; - other = xstrdup(real_path(e->path)); + other = real_pathdup(e->path); len = strlen(other); while (other[len-1] == '/') diff --combined transport.h index 9820f10b8e,efd5fb668c..e597b31b38 --- a/transport.h +++ b/transport.h @@@ -131,21 -131,22 +131,22 @@@ struct transport enum transport_family family; }; - #define TRANSPORT_PUSH_ALL 1 - #define TRANSPORT_PUSH_FORCE 2 - #define TRANSPORT_PUSH_DRY_RUN 4 - #define TRANSPORT_PUSH_MIRROR 8 - #define TRANSPORT_PUSH_PORCELAIN 16 - #define TRANSPORT_PUSH_SET_UPSTREAM 32 - #define TRANSPORT_RECURSE_SUBMODULES_CHECK 64 - #define TRANSPORT_PUSH_PRUNE 128 - #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256 - #define TRANSPORT_PUSH_NO_HOOK 512 - #define TRANSPORT_PUSH_FOLLOW_TAGS 1024 - #define TRANSPORT_PUSH_CERT_ALWAYS 2048 - #define TRANSPORT_PUSH_CERT_IF_ASKED 4096 - #define TRANSPORT_PUSH_ATOMIC 8192 - #define TRANSPORT_PUSH_OPTIONS 16384 + #define TRANSPORT_PUSH_ALL (1<<0) + #define TRANSPORT_PUSH_FORCE (1<<1) + #define TRANSPORT_PUSH_DRY_RUN (1<<2) + #define TRANSPORT_PUSH_MIRROR (1<<3) + #define TRANSPORT_PUSH_PORCELAIN (1<<4) + #define TRANSPORT_PUSH_SET_UPSTREAM (1<<5) + #define TRANSPORT_RECURSE_SUBMODULES_CHECK (1<<6) + #define TRANSPORT_PUSH_PRUNE (1<<7) + #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND (1<<8) + #define TRANSPORT_PUSH_NO_HOOK (1<<9) + #define TRANSPORT_PUSH_FOLLOW_TAGS (1<<10) + #define TRANSPORT_PUSH_CERT_ALWAYS (1<<11) + #define TRANSPORT_PUSH_CERT_IF_ASKED (1<<12) + #define TRANSPORT_PUSH_ATOMIC (1<<13) + #define TRANSPORT_PUSH_OPTIONS (1<<14) + #define TRANSPORT_RECURSE_SUBMODULES_ONLY (1<<15) extern int transport_summary_width(const struct ref *refs); @@@ -153,17 -154,10 +154,17 @@@ struct transport *transport_get(struct remote *, const char *); /* - * Check whether a transport is allowed by the environment. Type should - * generally be the URL scheme, as described in Documentation/git.txt + * Check whether a transport is allowed by the environment. + * + * Type should generally be the URL scheme, as described in + * Documentation/git.txt + * + * from_user specifies if the transport was given by the user. If unknown pass + * a -1 to read from the environment to determine if the transport was given by + * the user. + * */ -int is_transport_allowed(const char *type); +int is_transport_allowed(const char *type, int from_user); /* * Check whether a transport is allowed by the environment, @@@ -171,6 -165,12 +172,6 @@@ */ void transport_check_allowed(const char *type); -/* - * Returns true if the user has attempted to turn on protocol - * restrictions at all. - */ -int transport_restrict_protocols(void); - /* Transport options which apply to git:// and scp-style URLs */ /* The program to use on the remote side to send a pack */