diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/am.c | 60 | ||||
-rw-r--r-- | builtin/archive.c | 2 | ||||
-rw-r--r-- | builtin/cat-file.c | 16 | ||||
-rw-r--r-- | builtin/config.c | 19 | ||||
-rw-r--r-- | builtin/fetch.c | 146 | ||||
-rw-r--r-- | builtin/grep.c | 17 | ||||
-rw-r--r-- | builtin/ls-remote.c | 13 | ||||
-rw-r--r-- | builtin/pack-objects.c | 1 | ||||
-rw-r--r-- | builtin/prune.c | 3 | ||||
-rw-r--r-- | builtin/pull.c | 2 | ||||
-rw-r--r-- | builtin/repack.c | 13 | ||||
-rw-r--r-- | builtin/reset.c | 15 | ||||
-rw-r--r-- | builtin/rev-list.c | 1 | ||||
-rw-r--r-- | builtin/rev-parse.c | 1 | ||||
-rw-r--r-- | builtin/submodule--helper.c | 91 | ||||
-rw-r--r-- | builtin/upload-archive.c | 2 | ||||
-rw-r--r-- | builtin/worktree.c | 10 |
17 files changed, 267 insertions, 145 deletions
diff --git a/builtin/am.c b/builtin/am.c index 3ee9a9d2a9..dc576a3372 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -261,32 +261,6 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state, } /** - * Take a series of KEY='VALUE' lines where VALUE part is - * sq-quoted, and append <KEY, VALUE> at the end of the string list - */ -static int parse_key_value_squoted(char *buf, struct string_list *list) -{ - while (*buf) { - struct string_list_item *item; - char *np; - char *cp = strchr(buf, '='); - if (!cp) - return -1; - np = strchrnul(cp, '\n'); - *cp++ = '\0'; - item = string_list_append(list, buf); - - buf = np + (*np == '\n'); - *np = '\0'; - cp = sq_dequote(cp); - if (!cp) - return -1; - item->util = xstrdup(cp); - } - return 0; -} - -/** * Reads and parses the state directory's "author-script" file, and sets * state->author_name, state->author_email and state->author_date accordingly. * Returns 0 on success, -1 if the file could not be parsed. @@ -302,42 +276,16 @@ static int parse_key_value_squoted(char *buf, struct string_list *list) * script, and thus if the file differs from what this function expects, it is * better to bail out than to do something that the user does not expect. */ -static int read_author_script(struct am_state *state) +static int read_am_author_script(struct am_state *state) { const char *filename = am_path(state, "author-script"); - struct strbuf buf = STRBUF_INIT; - struct string_list kv = STRING_LIST_INIT_DUP; - int retval = -1; /* assume failure */ - int fd; assert(!state->author_name); assert(!state->author_email); assert(!state->author_date); - fd = open(filename, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) - return 0; - die_errno(_("could not open '%s' for reading"), filename); - } - strbuf_read(&buf, fd, 0); - close(fd); - if (parse_key_value_squoted(buf.buf, &kv)) - goto finish; - - if (kv.nr != 3 || - strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") || - strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") || - strcmp(kv.items[2].string, "GIT_AUTHOR_DATE")) - goto finish; - state->author_name = kv.items[0].util; - state->author_email = kv.items[1].util; - state->author_date = kv.items[2].util; - retval = 0; -finish: - string_list_clear(&kv, !!retval); - strbuf_release(&buf); - return retval; + return read_author_script(filename, &state->author_name, + &state->author_email, &state->author_date, 1); } /** @@ -411,7 +359,7 @@ static void am_load(struct am_state *state) BUG("state file 'last' does not exist"); state->last = strtol(sb.buf, NULL, 10); - if (read_author_script(state) < 0) + if (read_am_author_script(state) < 0) die(_("could not parse author script")); read_commit_msg(state); diff --git a/builtin/archive.c b/builtin/archive.c index e74f675390..d2455237ce 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -97,6 +97,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, local_opts, NULL, PARSE_OPT_KEEP_ALL); + init_archivers(); + if (output) create_output_file(output); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 8d97c84725..0d403eb77d 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -50,6 +50,13 @@ static int filter_object(const char *path, unsigned mode, return 0; } +static int stream_blob(const struct object_id *oid) +{ + if (stream_blob_to_fd(1, oid, NULL, 0)) + die("unable to stream %s to stdout", oid_to_hex(oid)); + return 0; +} + static int cat_one_file(int opt, const char *exp_type, const char *obj_name, int unknown_type) { @@ -132,7 +139,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, } if (type == OBJ_BLOB) - return stream_blob_to_fd(1, &oid, NULL, 0); + return stream_blob(&oid); buf = read_object_file(&oid, &type, &size); if (!buf) die("Cannot read object %s", obj_name); @@ -155,7 +162,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, oidcpy(&blob_oid, &oid); if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) - return stream_blob_to_fd(1, &blob_oid, NULL, 0); + return stream_blob(&blob_oid); /* * we attempted to dereference a tag to a blob * and failed; there may be new dereference @@ -319,8 +326,9 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d BUG("invalid cmdmode: %c", opt->cmdmode); batch_write(opt, contents, size); free(contents); - } else if (stream_blob_to_fd(1, oid, NULL, 0) < 0) - die("unable to stream %s to stdout", oid_to_hex(oid)); + } else { + stream_blob(oid); + } } else { enum object_type type; diff --git a/builtin/config.c b/builtin/config.c index 97b58c4aea..84385ef165 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -5,6 +5,7 @@ #include "parse-options.h" #include "urlmatch.h" #include "quote.h" +#include "worktree.h" static const char *const builtin_config_usage[] = { N_("git config [<options>]"), @@ -24,6 +25,7 @@ static char key_delim = ' '; static char term = '\n'; static int use_global_config, use_system_config, use_local_config; +static int use_worktree_config; static struct git_config_source given_config_source; static int actions, type; static char *default_value; @@ -123,6 +125,7 @@ static struct option builtin_config_options[] = { OPT_BOOL(0, "global", &use_global_config, N_("use global config file")), OPT_BOOL(0, "system", &use_system_config, N_("use system config file")), OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")), + OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")), OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")), OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")), OPT_GROUP(N_("Action")), @@ -602,6 +605,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) PARSE_OPT_STOP_AT_NON_OPTION); if (use_global_config + use_system_config + use_local_config + + use_worktree_config + !!given_config_source.file + !!given_config_source.blob > 1) { error(_("only one config file at a time")); usage_builtin_config(); @@ -645,7 +649,20 @@ int cmd_config(int argc, const char **argv, const char *prefix) given_config_source.file = git_etc_gitconfig(); else if (use_local_config) given_config_source.file = git_pathdup("config"); - else if (given_config_source.file) { + else if (use_worktree_config) { + struct worktree **worktrees = get_worktrees(0); + if (repository_format_worktree_config) + given_config_source.file = git_pathdup("config.worktree"); + else if (worktrees[0] && worktrees[1]) + die(_("--worktree cannot be used with multiple " + "working trees unless the config\n" + "extension worktreeConfig is enabled. " + "Please read \"CONFIGURATION FILE\"\n" + "section in \"git help worktree\" for details")); + else + given_config_source.file = git_pathdup("config"); + free_worktrees(worktrees); + } else if (given_config_source.file) { if (!is_absolute_path(given_config_source.file) && prefix) given_config_source.file = prefix_filename(prefix, given_config_source.file); diff --git a/builtin/fetch.c b/builtin/fetch.c index 8f7249f2b1..6ec7c07d1d 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -223,18 +223,6 @@ static void add_merge_config(struct ref **head, } } -static int add_existing(const char *refname, const struct object_id *oid, - int flag, void *cbdata) -{ - struct string_list *list = (struct string_list *)cbdata; - struct string_list_item *item = string_list_insert(list, refname); - struct object_id *old_oid = xmalloc(sizeof(*old_oid)); - - oidcpy(old_oid, oid); - item->util = old_oid; - return 0; -} - static int will_fetch(struct ref **head, const unsigned char *sha1) { struct ref *rm = *head; @@ -246,16 +234,72 @@ static int will_fetch(struct ref **head, const unsigned char *sha1) return 0; } +struct refname_hash_entry { + struct hashmap_entry ent; /* must be the first member */ + struct object_id oid; + char refname[FLEX_ARRAY]; +}; + +static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data, + const void *e1_, + const void *e2_, + const void *keydata) +{ + const struct refname_hash_entry *e1 = e1_; + const struct refname_hash_entry *e2 = e2_; + + return strcmp(e1->refname, keydata ? keydata : e2->refname); +} + +static struct refname_hash_entry *refname_hash_add(struct hashmap *map, + const char *refname, + const struct object_id *oid) +{ + struct refname_hash_entry *ent; + size_t len = strlen(refname); + + FLEX_ALLOC_MEM(ent, refname, refname, len); + hashmap_entry_init(ent, strhash(refname)); + oidcpy(&ent->oid, oid); + hashmap_add(map, ent); + return ent; +} + +static int add_one_refname(const char *refname, + const struct object_id *oid, + int flag, void *cbdata) +{ + struct hashmap *refname_map = cbdata; + + (void) refname_hash_add(refname_map, refname, oid); + return 0; +} + +static void refname_hash_init(struct hashmap *map) +{ + hashmap_init(map, refname_hash_entry_cmp, NULL, 0); +} + +static int refname_hash_exists(struct hashmap *map, const char *refname) +{ + return !!hashmap_get_from_hash(map, strhash(refname), refname); +} + static void find_non_local_tags(const struct ref *refs, struct ref **head, struct ref ***tail) { - struct string_list existing_refs = STRING_LIST_INIT_DUP; - struct string_list remote_refs = STRING_LIST_INIT_NODUP; + struct hashmap existing_refs; + struct hashmap remote_refs; + struct string_list remote_refs_list = STRING_LIST_INIT_NODUP; + struct string_list_item *remote_ref_item; const struct ref *ref; - struct string_list_item *item = NULL; + struct refname_hash_entry *item = NULL; + + refname_hash_init(&existing_refs); + refname_hash_init(&remote_refs); - for_each_ref(add_existing, &existing_refs); + for_each_ref(add_one_refname, &existing_refs); for (ref = refs; ref; ref = ref->next) { if (!starts_with(ref->name, "refs/tags/")) continue; @@ -271,10 +315,10 @@ static void find_non_local_tags(const struct ref *refs, !has_object_file_with_flags(&ref->old_oid, OBJECT_INFO_QUICK) && !will_fetch(head, ref->old_oid.hash) && - !has_sha1_file_with_flags(item->util, + !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) && - !will_fetch(head, item->util)) - item->util = NULL; + !will_fetch(head, item->oid.hash)) + oidclr(&item->oid); item = NULL; continue; } @@ -286,48 +330,53 @@ static void find_non_local_tags(const struct ref *refs, * fetch. */ if (item && - !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) && - !will_fetch(head, item->util)) - item->util = NULL; + !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) && + !will_fetch(head, item->oid.hash)) + oidclr(&item->oid); item = NULL; /* skip duplicates and refs that we already have */ - if (string_list_has_string(&remote_refs, ref->name) || - string_list_has_string(&existing_refs, ref->name)) + if (refname_hash_exists(&remote_refs, ref->name) || + refname_hash_exists(&existing_refs, ref->name)) continue; - item = string_list_insert(&remote_refs, ref->name); - item->util = (void *)&ref->old_oid; + item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid); + string_list_insert(&remote_refs_list, ref->name); } - string_list_clear(&existing_refs, 1); + hashmap_free(&existing_refs, 1); /* * We may have a final lightweight tag that needs to be * checked to see if it needs fetching. */ if (item && - !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) && - !will_fetch(head, item->util)) - item->util = NULL; + !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) && + !will_fetch(head, item->oid.hash)) + oidclr(&item->oid); /* - * For all the tags in the remote_refs string list, + * For all the tags in the remote_refs_list, * add them to the list of refs to be fetched */ - for_each_string_list_item(item, &remote_refs) { + for_each_string_list_item(remote_ref_item, &remote_refs_list) { + const char *refname = remote_ref_item->string; + + item = hashmap_get_from_hash(&remote_refs, strhash(refname), refname); + if (!item) + BUG("unseen remote ref?"); + /* Unless we have already decided to ignore this item... */ - if (item->util) - { - struct ref *rm = alloc_ref(item->string); - rm->peer_ref = alloc_ref(item->string); - oidcpy(&rm->old_oid, item->util); + if (!is_null_oid(&item->oid)) { + struct ref *rm = alloc_ref(item->refname); + rm->peer_ref = alloc_ref(item->refname); + oidcpy(&rm->old_oid, &item->oid); **tail = rm; *tail = &rm->next; } } - - string_list_clear(&remote_refs, 0); + hashmap_free(&remote_refs, 1); + string_list_clear(&remote_refs_list, 0); } static struct ref *get_ref_map(struct remote *remote, @@ -343,7 +392,7 @@ static struct ref *get_ref_map(struct remote *remote, /* opportunistically-updated references: */ struct ref *orefs = NULL, **oref_tail = &orefs; - struct string_list existing_refs = STRING_LIST_INIT_DUP; + struct hashmap existing_refs; if (rs->nr) { struct refspec *fetch_refspec; @@ -437,19 +486,24 @@ static struct ref *get_ref_map(struct remote *remote, ref_map = ref_remove_duplicates(ref_map); - for_each_ref(add_existing, &existing_refs); + refname_hash_init(&existing_refs); + for_each_ref(add_one_refname, &existing_refs); + for (rm = ref_map; rm; rm = rm->next) { if (rm->peer_ref) { - struct string_list_item *peer_item = - string_list_lookup(&existing_refs, - rm->peer_ref->name); + const char *refname = rm->peer_ref->name; + struct refname_hash_entry *peer_item; + + peer_item = hashmap_get_from_hash(&existing_refs, + strhash(refname), + refname); if (peer_item) { - struct object_id *old_oid = peer_item->util; + struct object_id *old_oid = &peer_item->oid; oidcpy(&rm->peer_ref->old_oid, old_oid); } } } - string_list_clear(&existing_refs, 1); + hashmap_free(&existing_refs, 1); return ref_map; } diff --git a/builtin/grep.c b/builtin/grep.c index d8508ddf79..56e4a11052 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -422,11 +422,23 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject, struct repository submodule; int hit; - if (!is_submodule_active(superproject, path)) + /* + * NEEDSWORK: submodules functions need to be protected because they + * access the object store via config_from_gitmodules(): the latter + * uses get_oid() which, for now, relies on the global the_repository + * object. + */ + grep_read_lock(); + + if (!is_submodule_active(superproject, path)) { + grep_read_unlock(); return 0; + } - if (repo_submodule_init(&submodule, superproject, path)) + if (repo_submodule_init(&submodule, superproject, path)) { + grep_read_unlock(); return 0; + } repo_read_gitmodules(&submodule); @@ -440,7 +452,6 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject, * store is no longer global and instead is a member of the repository * object. */ - grep_read_lock(); add_to_alternates_memory(submodule.objects->objectdir); grep_read_unlock(); diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 6a0cdec30d..1d7f1f5ce2 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -88,18 +88,15 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) int i; pattern = xcalloc(argc, sizeof(const char *)); for (i = 1; i < argc; i++) { - const char *glob; pattern[i - 1] = xstrfmt("*/%s", argv[i]); - - glob = strchr(argv[i], '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - argv[i]), argv[i]); - else - expand_ref_prefix(&ref_prefixes, argv[i]); } } + if (flags & REF_TAGS) + argv_array_push(&ref_prefixes, "refs/tags/"); + if (flags & REF_HEADS) + argv_array_push(&ref_prefixes, "refs/heads/"); + remote = remote_get(dest); if (!remote) { if (dest) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index e50c6cd1ff..c99ee79c31 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -3107,6 +3107,7 @@ static void get_object_list(int ac, const char **av) repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; + revs.allow_exclude_promisor_objects_opt = 1; setup_revisions(ac, av, &revs, NULL); /* make sure shallows are read */ diff --git a/builtin/prune.c b/builtin/prune.c index 41230f8215..e42653b99c 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -120,6 +120,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) save_commit_buffer = 0; read_replace_refs = 0; ref_paranoia = 1; + revs.allow_exclude_promisor_objects_opt = 1; repo_init_revisions(the_repository, &revs, prefix); argc = parse_options(argc, argv, prefix, options, prune_usage, 0); @@ -161,7 +162,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) free(s); if (is_repository_shallow(the_repository)) - prune_shallow(show_only); + prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0); return 0; } diff --git a/builtin/pull.c b/builtin/pull.c index 798ecf7faf..c21aa276f1 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -945,7 +945,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) int ret = 0; if ((recurse_submodules == RECURSE_SUBMODULES_ON || recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) && - submodule_touches_in_range(&the_index, &rebase_fork_point, &curr_head)) + submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head)) die(_("cannot rebase with locally recorded submodule modifications")); if (!autostash) { struct commit_list *list = NULL; diff --git a/builtin/repack.c b/builtin/repack.c index 0223f2880c..45583683ee 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -431,8 +431,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) char *fname, *fname_old; if (!midx_cleared) { - /* if we move a packfile, it will invalidated the midx */ - clear_midx_file(get_object_directory()); + clear_midx_file(the_repository); midx_cleared = 1; } @@ -550,11 +549,21 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (!po_args.quiet && isatty(2)) opts |= PRUNE_PACKED_VERBOSE; prune_packed_objects(opts); + + if (!keep_unreachable && + (!(pack_everything & LOOSEN_UNREACHABLE) || + unpack_unreachable) && + is_repository_shallow(the_repository)) + prune_shallow(PRUNE_QUICK); } if (!no_update_server_info) update_server_info(0); remove_temporary_files(); + + if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) + write_midx_file(get_object_directory()); + string_list_clear(&names, 0); string_list_clear(&rollback, 0); string_list_clear(&existing_packs, 0); diff --git a/builtin/reset.c b/builtin/reset.c index 6d37a35e2e..58166964f8 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -25,6 +25,8 @@ #include "submodule.h" #include "submodule-config.h" +#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000) + static const char * const git_reset_usage[] = { N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"), N_("git reset [-q] [<tree-ish>] [--] <paths>..."), @@ -307,6 +309,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) }; git_config(git_reset_config, NULL); + git_config_get_bool("reset.quiet", &quiet); argc = parse_options(argc, argv, prefix, options, git_reset_usage, PARSE_OPT_KEEP_DASHDASH); @@ -376,9 +379,19 @@ int cmd_reset(int argc, const char **argv, const char *prefix) int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN; if (read_from_tree(&pathspec, &oid, intent_to_add)) return 1; - if (get_git_work_tree()) + if (!quiet && get_git_work_tree()) { + uint64_t t_begin, t_delta_in_ms; + + t_begin = getnanotime(); refresh_index(&the_index, flags, NULL, NULL, _("Unstaged changes after reset:")); + t_delta_in_ms = (getnanotime() - t_begin) / 1000000; + if (advice_reset_quiet_warning && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) { + printf(_("\nIt took %.2f seconds to enumerate unstaged changes after reset. You can\n" + "use '--quiet' to avoid this. Set the config setting reset.quiet to true\n" + "to make this the default.\n"), t_delta_in_ms / 1000.0); + } + } } else { int err = reset_index(&oid, reset_type, quiet); if (reset_type == KEEP && !err) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 5064d08e1b..2880ed37e3 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -374,6 +374,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); repo_init_revisions(the_repository, &revs, prefix); revs.abbrev = DEFAULT_ABBREV; + revs.allow_exclude_promisor_objects_opt = 1; revs.commit_format = CMIT_FMT_UNSPECIFIED; revs.do_not_die_on_missing_tree = 1; diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 455f62246d..10d4dab894 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -765,6 +765,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) } if (!strcmp(arg, "--all")) { for_each_ref(show_reference, NULL); + clear_ref_exclusion(&ref_excludes); continue; } if (skip_prefix(arg, "--disambiguate=", &arg)) { diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 8e1db55e13..d38113a31a 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -584,6 +584,26 @@ static int module_foreach(int argc, const char **argv, const char *prefix) return 0; } +static char *compute_submodule_clone_url(const char *rel_url) +{ + char *remoteurl, *relurl; + char *remote = get_default_remote(); + struct strbuf remotesb = STRBUF_INIT; + + strbuf_addf(&remotesb, "remote.%s.url", remote); + if (git_config_get_string(remotesb.buf, &remoteurl)) { + warning(_("could not look up configuration '%s'. Assuming this repository is its own authoritative upstream."), remotesb.buf); + remoteurl = xgetcwd(); + } + relurl = relative_url(remoteurl, rel_url, NULL); + + free(remote); + free(remoteurl); + strbuf_release(&remotesb); + + return relurl; +} + struct init_cb { const char *prefix; unsigned int flags; @@ -634,21 +654,9 @@ static void init_submodule(const char *path, const char *prefix, /* Possibly a url relative to parent */ if (starts_with_dot_dot_slash(url) || starts_with_dot_slash(url)) { - char *remoteurl, *relurl; - char *remote = get_default_remote(); - struct strbuf remotesb = STRBUF_INIT; - strbuf_addf(&remotesb, "remote.%s.url", remote); - free(remote); - - if (git_config_get_string(remotesb.buf, &remoteurl)) { - warning(_("could not lookup configuration '%s'. Assuming this repository is its own authoritative upstream."), remotesb.buf); - remoteurl = xgetcwd(); - } - relurl = relative_url(remoteurl, url, NULL); - strbuf_release(&remotesb); - free(remoteurl); - free(url); - url = relurl; + char *oldurl = url; + url = compute_submodule_clone_url(oldurl); + free(oldurl); } if (git_config_set_gently(sb.buf, url)) @@ -1582,6 +1590,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, struct strbuf sb = STRBUF_INIT; const char *displaypath = NULL; int needs_cloning = 0; + int need_free_url = 0; if (ce_stage(ce)) { if (suc->recursive_prefix) @@ -1630,8 +1639,14 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, strbuf_reset(&sb); strbuf_addf(&sb, "submodule.%s.url", sub->name); - if (repo_config_get_string_const(the_repository, sb.buf, &url)) - url = sub->url; + if (repo_config_get_string_const(the_repository, sb.buf, &url)) { + if (starts_with_dot_slash(sub->url) || + starts_with_dot_dot_slash(sub->url)) { + url = compute_submodule_clone_url(sub->url); + need_free_url = 1; + } else + url = sub->url; + } strbuf_reset(&sb); strbuf_addf(&sb, "%s/.git", ce->name); @@ -1677,6 +1692,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, cleanup: strbuf_reset(&displaypath_sb); strbuf_reset(&sb); + if (need_free_url) + free((void*)url); return needs_cloning; } @@ -2124,6 +2141,45 @@ static int check_name(int argc, const char **argv, const char *prefix) return 0; } +static int module_config(int argc, const char **argv, const char *prefix) +{ + enum { + CHECK_WRITEABLE = 1 + } command = 0; + + struct option module_config_options[] = { + OPT_CMDMODE(0, "check-writeable", &command, + N_("check if it is safe to write to the .gitmodules file"), + CHECK_WRITEABLE), + OPT_END() + }; + const char *const git_submodule_helper_usage[] = { + N_("git submodule--helper config name [value]"), + N_("git submodule--helper config --check-writeable"), + NULL + }; + + argc = parse_options(argc, argv, prefix, module_config_options, + git_submodule_helper_usage, PARSE_OPT_KEEP_ARGV0); + + if (argc == 1 && command == CHECK_WRITEABLE) + return is_writing_gitmodules_ok() ? 0 : -1; + + /* Equivalent to ACTION_GET in builtin/config.c */ + if (argc == 2) + return print_config_from_gitmodules(the_repository, argv[1]); + + /* Equivalent to ACTION_SET in builtin/config.c */ + if (argc == 3) { + if (!is_writing_gitmodules_ok()) + die(_("please make sure that the .gitmodules file is in the working tree")); + + return config_set_in_gitmodules_file_gently(argv[1], argv[2]); + } + + usage_with_options(git_submodule_helper_usage, module_config_options); +} + #define SUPPORT_SUPER_PREFIX (1<<0) struct cmd_struct { @@ -2153,6 +2209,7 @@ static struct cmd_struct commands[] = { {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX}, {"is-active", is_active, 0}, {"check-name", check_name, 0}, + {"config", module_config, 0}, }; int cmd_submodule__helper(int argc, const char **argv, const char *prefix) diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c index 25d9116356..018879737a 100644 --- a/builtin/upload-archive.c +++ b/builtin/upload-archive.c @@ -28,6 +28,8 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix) if (!enter_repo(argv[1], 0)) die("'%s' does not appear to be a git repository", argv[1]); + init_archivers(); + /* put received options in sent_argv[] */ argv_array_push(&sent_argv, "git-upload-archive"); for (;;) { diff --git a/builtin/worktree.c b/builtin/worktree.c index c4abbde2b8..5e84026177 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -245,7 +245,7 @@ static void validate_worktree_add(const char *path, const struct add_opts *opts) if (!wt) goto done; - locked = !!is_worktree_locked(wt); + locked = !!worktree_lock_reason(wt); if ((!locked && opts->force) || (locked && opts->force > 1)) { if (delete_git_dir(wt->id)) die(_("unable to re-add worktree '%s'"), path); @@ -682,7 +682,7 @@ static int lock_worktree(int ac, const char **av, const char *prefix) if (is_main_worktree(wt)) die(_("The main working tree cannot be locked or unlocked")); - old_reason = is_worktree_locked(wt); + old_reason = worktree_lock_reason(wt); if (old_reason) { if (*old_reason) die(_("'%s' is already locked, reason: %s"), @@ -714,7 +714,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix) die(_("'%s' is not a working tree"), av[0]); if (is_main_worktree(wt)) die(_("The main working tree cannot be locked or unlocked")); - if (!is_worktree_locked(wt)) + if (!worktree_lock_reason(wt)) die(_("'%s' is not locked"), av[0]); ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id)); free_worktrees(worktrees); @@ -787,7 +787,7 @@ static int move_worktree(int ac, const char **av, const char *prefix) validate_no_submodules(wt); if (force < 2) - reason = is_worktree_locked(wt); + reason = worktree_lock_reason(wt); if (reason) { if (*reason) die(_("cannot move a locked working tree, lock reason: %s\nuse 'move -f -f' to override or unlock first"), @@ -900,7 +900,7 @@ static int remove_worktree(int ac, const char **av, const char *prefix) if (is_main_worktree(wt)) die(_("'%s' is a main working tree"), av[0]); if (force < 2) - reason = is_worktree_locked(wt); + reason = worktree_lock_reason(wt); if (reason) { if (*reason) die(_("cannot remove a locked working tree, lock reason: %s\nuse 'remove -f -f' to override or unlock first"), |