From: Junio C Hamano Date: Thu, 20 Apr 2017 04:37:13 +0000 (-0700) Subject: Merge branch 'bc/object-id' X-Git-Tag: v2.13.0-rc0~16 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/b1081e4004091947b6c6a806625addd1cbba61b7?ds=inline;hp=-c Merge branch 'bc/object-id' Conversion from unsigned char [40] to struct object_id continues. * bc/object-id: Documentation: update and rename api-sha1-array.txt Rename sha1_array to oid_array Convert sha1_array_for_each_unique and for_each_abbrev to object_id Convert sha1_array_lookup to take struct object_id Convert remaining callers of sha1_array_lookup to object_id Make sha1_array_append take a struct object_id * sha1-array: convert internal storage for struct sha1_array to object_id builtin/pull: convert to struct object_id submodule: convert check_for_new_submodule_commits to object_id sha1_name: convert disambiguate_hint_fn to take object_id sha1_name: convert struct disambiguate_state to object_id test-sha1-array: convert most code to struct object_id parse-options-cb: convert sha1_array_append caller to struct object_id fsck: convert init_skiplist to struct object_id builtin/receive-pack: convert portions to struct object_id builtin/pull: convert portions to struct object_id builtin/diff: convert to struct object_id Convert GIT_SHA1_RAWSZ used for allocation to GIT_MAX_RAWSZ Convert GIT_SHA1_HEXSZ used for allocation to GIT_MAX_HEXSZ Define new hash-size constants for allocating memory --- b1081e4004091947b6c6a806625addd1cbba61b7 diff --combined bisect.c index d12583eaac,54d69e77b9..03af06c66c --- a/bisect.c +++ b/bisect.c @@@ -12,8 -12,8 +12,8 @@@ #include "sha1-array.h" #include "argv-array.h" - static struct sha1_array good_revs; - static struct sha1_array skipped_revs; + static struct oid_array good_revs; + static struct oid_array skipped_revs; static struct object_id *current_bad_oid; @@@ -200,7 -200,6 +200,7 @@@ static struct commit_list *best_bisecti { struct commit_list *p; struct commit_dist *array = xcalloc(nr, sizeof(*array)); + struct strbuf buf = STRBUF_INIT; int cnt, i; for (p = list, cnt = 0; p; p = p->next) { @@@ -218,18 -217,17 +218,18 @@@ } QSORT(array, cnt, compare_commit_dist); for (p = list, i = 0; i < cnt; i++) { - char buf[100]; /* enough for dist=%d */ struct object *obj = &(array[i].commit->object); - snprintf(buf, sizeof(buf), "dist=%d", array[i].distance); - add_name_decoration(DECORATION_NONE, buf, obj); + strbuf_reset(&buf); + strbuf_addf(&buf, "dist=%d", array[i].distance); + add_name_decoration(DECORATION_NONE, buf.buf, obj); p->item = array[i].commit; p = p->next; } if (p) p->next = NULL; + strbuf_release(&buf); free(array); return list; } @@@ -415,9 -413,9 +415,9 @@@ static int register_ref(const char *ref current_bad_oid = xmalloc(sizeof(*current_bad_oid)); oidcpy(current_bad_oid, oid); } else if (starts_with(refname, good_prefix.buf)) { - sha1_array_append(&good_revs, oid->hash); + oid_array_append(&good_revs, oid); } else if (starts_with(refname, "skip-")) { - sha1_array_append(&skipped_revs, oid->hash); + oid_array_append(&skipped_revs, oid); } strbuf_release(&good_prefix); @@@ -453,13 -451,13 +453,13 @@@ static void read_bisect_paths(struct ar fclose(fp); } - static char *join_sha1_array_hex(struct sha1_array *array, char delim) + static char *join_sha1_array_hex(struct oid_array *array, char delim) { struct strbuf joined_hexs = STRBUF_INIT; int i; for (i = 0; i < array->nr; i++) { - strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i])); + strbuf_addstr(&joined_hexs, oid_to_hex(array->oid + i)); if (i + 1 < array->nr) strbuf_addch(&joined_hexs, delim); } @@@ -501,8 -499,7 +501,7 @@@ struct commit_list *filter_skipped(stru while (list) { struct commit_list *next = list->next; list->next = NULL; - if (0 <= sha1_array_lookup(&skipped_revs, - list->item->object.oid.hash)) { + if (0 <= oid_array_lookup(&skipped_revs, &list->item->object.oid)) { if (skipped_first && !*skipped_first) *skipped_first = 1; /* Move current to tried list */ @@@ -623,7 -620,7 +622,7 @@@ static void bisect_rev_setup(struct rev argv_array_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid)); for (i = 0; i < good_revs.nr; i++) argv_array_pushf(&rev_argv, good_format, - sha1_to_hex(good_revs.sha1[i])); + oid_to_hex(good_revs.oid + i)); argv_array_push(&rev_argv, "--"); if (read_paths) read_bisect_paths(&rev_argv); @@@ -684,7 -681,7 +683,7 @@@ static int is_expected_rev(const struc static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout) { - char bisect_rev_hex[GIT_SHA1_HEXSZ + 1]; + char bisect_rev_hex[GIT_MAX_HEXSZ + 1]; memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1); update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR); @@@ -703,11 -700,11 +702,11 @@@ return run_command_v_opt(argv_show_branch, RUN_GIT_CMD); } - static struct commit *get_commit_reference(const unsigned char *sha1) + static struct commit *get_commit_reference(const struct object_id *oid) { - struct commit *r = lookup_commit_reference(sha1); + struct commit *r = lookup_commit_reference(oid->hash); if (!r) - die(_("Not a valid commit name %s"), sha1_to_hex(sha1)); + die(_("Not a valid commit name %s"), oid_to_hex(oid)); return r; } @@@ -717,9 -714,9 +716,9 @@@ static struct commit **get_bad_and_good int i, n = 0; ALLOC_ARRAY(rev, 1 + good_revs.nr); - rev[n++] = get_commit_reference(current_bad_oid->hash); + rev[n++] = get_commit_reference(current_bad_oid); for (i = 0; i < good_revs.nr; i++) - rev[n++] = get_commit_reference(good_revs.sha1[i]); + rev[n++] = get_commit_reference(good_revs.oid + i); *rev_nr = n; return rev; @@@ -756,9 -753,9 +755,9 @@@ static void handle_bad_merge_base(void exit(1); } - static void handle_skipped_merge_base(const unsigned char *mb) + static void handle_skipped_merge_base(const struct object_id *mb) { - char *mb_hex = sha1_to_hex(mb); + char *mb_hex = oid_to_hex(mb); char *bad_hex = oid_to_hex(current_bad_oid); char *good_hex = join_sha1_array_hex(&good_revs, ' '); @@@ -789,16 -786,16 +788,16 @@@ static void check_merge_bases(int no_ch result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1); for (; result; result = result->next) { - const unsigned char *mb = result->item->object.oid.hash; - if (!hashcmp(mb, current_bad_oid->hash)) { + const struct object_id *mb = &result->item->object.oid; + if (!oidcmp(mb, current_bad_oid)) { handle_bad_merge_base(); - } else if (0 <= sha1_array_lookup(&good_revs, mb)) { + } else if (0 <= oid_array_lookup(&good_revs, mb)) { continue; - } else if (0 <= sha1_array_lookup(&skipped_revs, mb)) { + } else if (0 <= oid_array_lookup(&skipped_revs, mb)) { handle_skipped_merge_base(mb); } else { printf(_("Bisecting: a merge base must be tested\n")); - exit(bisect_checkout(mb, no_checkout)); + exit(bisect_checkout(mb->hash, no_checkout)); } } diff --combined builtin/fetch.c index 4ef7a08afc,a41b892dcc..5f2c2ab23e --- a/builtin/fetch.c +++ b/builtin/fetch.c @@@ -421,7 -421,7 +421,7 @@@ static int s_update_ref(const char *act struct ref *ref, int check_old) { - char msg[1024]; + char *msg; char *rla = getenv("GIT_REFLOG_ACTION"); struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; @@@ -431,7 -431,7 +431,7 @@@ return 0; if (!rla) rla = default_rla.buf; - snprintf(msg, sizeof(msg), "%s: %s", rla, action); + msg = xstrfmt("%s: %s", rla, action); transaction = ref_transaction_begin(&err); if (!transaction || @@@ -449,13 -449,11 +449,13 @@@ ref_transaction_free(transaction); strbuf_release(&err); + free(msg); return 0; fail: ref_transaction_free(transaction); error("%s", err.buf); strbuf_release(&err); + free(msg); return df_conflict ? STORE_REF_ERROR_DF_CONFLICT : STORE_REF_ERROR_OTHER; } @@@ -661,7 -659,7 +661,7 @@@ static int update_local_ref(struct ref if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_oid.hash); + check_for_new_submodule_commits(&ref->new_oid); r = s_update_ref(msg, ref, 0); format_display(display, r ? '!' : '*', what, r ? _("unable to update local ref") : NULL, @@@ -677,7 -675,7 +677,7 @@@ strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV); if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_oid.hash); + check_for_new_submodule_commits(&ref->new_oid); r = s_update_ref("fast-forward", ref, 1); format_display(display, r ? '!' : ' ', quickref.buf, r ? _("unable to update local ref") : NULL, @@@ -692,7 -690,7 +692,7 @@@ strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV); if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_oid.hash); + check_for_new_submodule_commits(&ref->new_oid); r = s_update_ref("forced-update", ref, 1); format_display(display, r ? '!' : '+', quickref.buf, r ? _("unable to update local ref") : _("forced update"), diff --combined builtin/merge.c index 95572b1810,a2cceea3fb..703827f006 --- a/builtin/merge.c +++ b/builtin/merge.c @@@ -44,6 -44,7 +44,6 @@@ struct strategy static const char * const builtin_merge_usage[] = { N_("git merge [] [...]"), - N_("git merge [] HEAD "), N_("git merge --abort"), N_("git merge --continue"), NULL @@@ -633,10 -634,9 +633,10 @@@ static void write_tree_trivial(struct o static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *remoteheads, - struct commit *head, const char *head_arg) + struct commit *head) { static struct lock_file lock; + const char *head_arg = "HEAD"; hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); @@@ -853,6 -853,24 +853,6 @@@ static int suggest_conflicts(void return 1; } -static struct commit *is_old_style_invocation(int argc, const char **argv, - const struct object_id *head) -{ - struct commit *second_token = NULL; - if (argc > 2) { - struct object_id second_oid; - - if (get_oid(argv[1], &second_oid)) - return NULL; - second_token = lookup_commit_reference_gently(second_oid.hash, 0); - if (!second_token) - die(_("'%s' is not a commit"), argv[1]); - if (oidcmp(&second_token->object.oid, head)) - return NULL; - } - return second_token; -} - static int evaluate_result(void) { int cnt = 0; @@@ -1102,6 -1120,7 +1102,6 @@@ int cmd_merge(int argc, const char **ar struct object_id result_tree, stash, head_oid; struct commit *head_commit; struct strbuf buf = STRBUF_INIT; - const char *head_arg; int i, ret = 0, head_subsumed; int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0; struct commit_list *common = NULL; @@@ -1241,12 -1260,34 +1241,12 @@@ } /* - * This could be traditional "merge HEAD ..." and - * the way we can tell it is to see if the second token is HEAD, - * but some people might have misused the interface and used a - * commit-ish that is the same as HEAD there instead. - * Traditional format never would have "-m" so it is an - * additional safety measure to check for it. + * All the rest are the commits being merged; prepare + * the standard merge summary message to be appended + * to the given message. */ - if (!have_message && - is_old_style_invocation(argc, argv, &head_commit->object.oid)) { - warning("old-style 'git merge HEAD ' is deprecated."); - strbuf_addstr(&merge_msg, argv[0]); - head_arg = argv[1]; - argv += 2; - argc -= 2; - remoteheads = collect_parents(head_commit, &head_subsumed, - argc, argv, NULL); - } else { - /* We are invoked directly as the first-class UI. */ - head_arg = "HEAD"; - - /* - * All the rest are the commits being merged; prepare - * the standard merge summary message to be appended - * to the given message. - */ - remoteheads = collect_parents(head_commit, &head_subsumed, - argc, argv, &merge_msg); - } + remoteheads = collect_parents(head_commit, &head_subsumed, + argc, argv, &merge_msg); if (!head_commit || !argc) usage_with_options(builtin_merge_usage, @@@ -1255,7 -1296,7 +1255,7 @@@ if (verify_signatures) { for (p = remoteheads; p; p = p->next) { struct commit *commit = p->item; - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; struct signature_check signature_check; memset(&signature_check, 0, sizeof(signature_check)); @@@ -1472,7 -1513,7 +1472,7 @@@ ret = try_merge_strategy(use_strategies[i]->name, common, remoteheads, - head_commit, head_arg); + head_commit); if (!option_commit && !ret) { merge_was_ok = 1; /* @@@ -1542,7 -1583,7 +1542,7 @@@ printf(_("Using the %s to prepare resolving by hand.\n"), best_strategy); try_merge_strategy(best_strategy, common, remoteheads, - head_commit, head_arg); + head_commit); } if (squash) diff --combined builtin/pack-objects.c index 84af7c2324,4fc032e3ec..0fe35d1b5a --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@ -239,8 -239,7 +239,8 @@@ static unsigned long write_no_reuse_obj unsigned long limit, int usable_delta) { unsigned long size, datalen; - unsigned char header[10], dheader[10]; + unsigned char header[MAX_PACK_OBJECT_HEADER], + dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; enum object_type type; void *buf; @@@ -287,8 -286,7 +287,8 @@@ * The object header is a byte of 'type' followed by zero or * more bytes of length. */ - hdrlen = encode_in_pack_object_header(type, size, header); + hdrlen = encode_in_pack_object_header(header, sizeof(header), + type, size); if (type == OBJ_OFS_DELTA) { /* @@@ -354,15 -352,13 +354,15 @@@ static off_t write_reuse_object(struct off_t offset; enum object_type type = entry->type; off_t datalen; - unsigned char header[10], dheader[10]; + unsigned char header[MAX_PACK_OBJECT_HEADER], + dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; if (entry->delta) type = (allow_ofs_delta && entry->delta->idx.offset) ? OBJ_OFS_DELTA : OBJ_REF_DELTA; - hdrlen = encode_in_pack_object_header(type, entry->size, header); + hdrlen = encode_in_pack_object_header(header, sizeof(header), + type, entry->size); offset = entry->in_pack_offset; revidx = find_pack_revindex(p, offset); @@@ -2672,16 -2668,16 +2672,16 @@@ static int has_sha1_pack_kept_or_nonloc * * This is filled by get_object_list. */ - static struct sha1_array recent_objects; + static struct oid_array recent_objects; - static int loosened_object_can_be_discarded(const unsigned char *sha1, + static int loosened_object_can_be_discarded(const struct object_id *oid, unsigned long mtime) { if (!unpack_unreachable_expiration) return 0; if (mtime > unpack_unreachable_expiration) return 0; - if (sha1_array_lookup(&recent_objects, sha1) >= 0) + if (oid_array_lookup(&recent_objects, oid) >= 0) return 0; return 1; } @@@ -2690,7 -2686,7 +2690,7 @@@ static void loosen_unused_packed_object { struct packed_git *p; uint32_t i; - const unsigned char *sha1; + struct object_id oid; for (p = packed_git; p; p = p->next) { if (!p->pack_local || p->pack_keep) @@@ -2700,11 -2696,11 +2700,11 @@@ die("cannot open pack index"); for (i = 0; i < p->num_objects; i++) { - sha1 = nth_packed_object_sha1(p, i); - if (!packlist_find(&to_pack, sha1, NULL) && - !has_sha1_pack_kept_or_nonlocal(sha1) && - !loosened_object_can_be_discarded(sha1, p->mtime)) - if (force_object_loose(sha1, p->mtime)) + nth_packed_object_oid(&oid, p, i); + if (!packlist_find(&to_pack, oid.hash, NULL) && + !has_sha1_pack_kept_or_nonlocal(oid.hash) && + !loosened_object_can_be_discarded(&oid, p->mtime)) + if (force_object_loose(oid.hash, p->mtime)) die("unable to force loose object"); } } @@@ -2743,12 -2739,12 +2743,12 @@@ static void record_recent_object(struc const char *name, void *data) { - sha1_array_append(&recent_objects, obj->oid.hash); + oid_array_append(&recent_objects, &obj->oid); } static void record_recent_commit(struct commit *commit, void *data) { - sha1_array_append(&recent_objects, commit->object.oid.hash); + oid_array_append(&recent_objects, &commit->object.oid); } static void get_object_list(int ac, const char **av) @@@ -2816,7 -2812,7 +2816,7 @@@ if (unpack_unreachable) loosen_unused_packed_objects(&revs); - sha1_array_clear(&recent_objects); + oid_array_clear(&recent_objects); } static int option_parse_index_version(const struct option *opt, diff --combined builtin/receive-pack.c index 7020278081,bec46a5a92..3cba3fd278 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@@ -225,10 -225,10 +225,10 @@@ static int receive_pack_config(const ch return git_default_config(var, value, cb); } - static void show_ref(const char *path, const unsigned char *sha1) + static void show_ref(const char *path, const struct object_id *oid) { if (sent_capabilities) { - packet_write_fmt(1, "%s %s\n", sha1_to_hex(sha1), path); + packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), path); } else { struct strbuf cap = STRBUF_INIT; @@@ -244,7 -244,7 +244,7 @@@ strbuf_addstr(&cap, " push-options"); strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized()); packet_write_fmt(1, "%s %s%c%s\n", - sha1_to_hex(sha1), path, 0, cap.buf); + oid_to_hex(oid), path, 0, cap.buf); strbuf_release(&cap); sent_capabilities = 1; } @@@ -271,7 -271,7 +271,7 @@@ static int show_ref_cb(const char *path } else { oidset_insert(seen, oid); } - show_ref(path, oid->hash); + show_ref(path, oid); return 0; } @@@ -284,7 -284,7 +284,7 @@@ static void show_one_alternate_ref(cons if (oidset_insert(seen, oid)) return; - show_ref(".have", oid->hash); + show_ref(".have", oid); } static void write_head_info(void) @@@ -295,7 -295,7 +295,7 @@@ for_each_alternate_ref(show_one_alternate_ref, &seen); oidset_clear(&seen); if (!sent_capabilities) - show_ref("capabilities^{}", null_sha1); + show_ref("capabilities^{}", &null_oid); advertise_shallow_grafts(1); @@@ -309,8 -309,8 +309,8 @@@ struct command unsigned int skip_update:1, did_not_exist:1; int index; - unsigned char old_sha1[20]; - unsigned char new_sha1[20]; + struct object_id old_oid; + struct object_id new_oid; char ref_name[FLEX_ARRAY]; /* more */ }; @@@ -723,7 -723,7 +723,7 @@@ static int feed_receive_hook(void *stat return -1; /* EOF */ strbuf_reset(&state->buf); strbuf_addf(&state->buf, "%s %s %s\n", - sha1_to_hex(cmd->old_sha1), sha1_to_hex(cmd->new_sha1), + oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid), cmd->ref_name); state->cmd = cmd->next; if (bufp) { @@@ -764,8 -764,8 +764,8 @@@ static int run_update_hook(struct comma return 0; argv[1] = cmd->ref_name; - argv[2] = sha1_to_hex(cmd->old_sha1); - argv[3] = sha1_to_hex(cmd->new_sha1); + argv[2] = oid_to_hex(&cmd->old_oid); + argv[3] = oid_to_hex(&cmd->new_oid); argv[4] = NULL; proc.no_stdin = 1; @@@ -831,7 -831,7 +831,7 @@@ static int command_singleton_iterator(v static int update_shallow_ref(struct command *cmd, struct shallow_info *si) { static struct lock_file shallow_lock; - struct sha1_array extra = SHA1_ARRAY_INIT; + struct oid_array extra = OID_ARRAY_INIT; struct check_connected_options opt = CHECK_CONNECTED_INIT; uint32_t mask = 1 << (cmd->index % 32); int i; @@@ -842,13 -842,13 +842,13 @@@ if (si->used_shallow[i] && (si->used_shallow[i][cmd->index / 32] & mask) && !delayed_reachability_test(si, i)) - sha1_array_append(&extra, si->shallow->sha1[i]); + oid_array_append(&extra, &si->shallow->oid[i]); opt.env = tmp_objdir_env(tmp_objdir); setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra); if (check_connected(command_singleton_iterator, cmd, &opt)) { rollback_lock_file(&shallow_lock); - sha1_array_clear(&extra); + oid_array_clear(&extra); return -1; } @@@ -859,10 -859,10 +859,10 @@@ * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) - register_shallow(extra.sha1[i]); + register_shallow(extra.oid[i].hash); si->shallow_ref[cmd->index] = 0; - sha1_array_clear(&extra); + oid_array_clear(&extra); return 0; } @@@ -988,8 -988,8 +988,8 @@@ static const char *update(struct comman const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; const char *namespaced_name, *ret; - unsigned char *old_sha1 = cmd->old_sha1; - unsigned char *new_sha1 = cmd->new_sha1; + struct object_id *old_oid = &cmd->old_oid; + struct object_id *new_oid = &cmd->new_oid; /* only refs/... are allowed */ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) { @@@ -1014,20 -1014,20 +1014,20 @@@ refuse_unconfigured_deny(); return "branch is currently checked out"; case DENY_UPDATE_INSTEAD: - ret = update_worktree(new_sha1); + ret = update_worktree(new_oid->hash); if (ret) return ret; break; } } - if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { + if (!is_null_oid(new_oid) && !has_object_file(new_oid)) { error("unpack should have generated %s, " - "but I can't find it!", sha1_to_hex(new_sha1)); + "but I can't find it!", oid_to_hex(new_oid)); return "bad pack"; } - if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) { + if (!is_null_oid(old_oid) && is_null_oid(new_oid)) { if (deny_deletes && starts_with(name, "refs/heads/")) { rp_error("denying ref deletion for %s", name); return "deletion prohibited"; @@@ -1053,14 -1053,14 +1053,14 @@@ } } - if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && - !is_null_sha1(old_sha1) && + if (deny_non_fast_forwards && !is_null_oid(new_oid) && + !is_null_oid(old_oid) && starts_with(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - old_object = parse_object(old_sha1); - new_object = parse_object(new_sha1); + old_object = parse_object(old_oid->hash); + new_object = parse_object(new_oid->hash); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || @@@ -1081,10 -1081,10 +1081,10 @@@ return "hook declined"; } - if (is_null_sha1(new_sha1)) { + if (is_null_oid(new_oid)) { struct strbuf err = STRBUF_INIT; - if (!parse_object(old_sha1)) { - old_sha1 = NULL; + if (!parse_object(old_oid->hash)) { + old_oid = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); } else { @@@ -1094,7 -1094,7 +1094,7 @@@ } if (ref_transaction_delete(transaction, namespaced_name, - old_sha1, + old_oid->hash, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); @@@ -1111,7 -1111,7 +1111,7 @@@ if (ref_transaction_update(transaction, namespaced_name, - new_sha1, old_sha1, + new_oid->hash, old_oid->hash, 0, "push", &err)) { rp_error("%s", err.buf); @@@ -1162,7 -1162,7 +1162,7 @@@ static void check_aliased_update(struc const char *dst_name; struct string_list_item *item; struct command *dst_cmd; - unsigned char sha1[GIT_SHA1_RAWSZ]; + unsigned char sha1[GIT_MAX_RAWSZ]; int flag; strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); @@@ -1187,8 -1187,8 +1187,8 @@@ dst_cmd = (struct command *) item->util; - if (!hashcmp(cmd->old_sha1, dst_cmd->old_sha1) && - !hashcmp(cmd->new_sha1, dst_cmd->new_sha1)) + if (!oidcmp(&cmd->old_oid, &dst_cmd->old_oid) && + !oidcmp(&cmd->new_oid, &dst_cmd->new_oid)) return; dst_cmd->skip_update = 1; @@@ -1196,11 -1196,11 +1196,11 @@@ rp_error("refusing inconsistent update between symref '%s' (%s..%s) and" " its target '%s' (%s..%s)", cmd->ref_name, - find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV), - find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV), + find_unique_abbrev(cmd->old_oid.hash, DEFAULT_ABBREV), + find_unique_abbrev(cmd->new_oid.hash, DEFAULT_ABBREV), dst_cmd->ref_name, - find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV), - find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV)); + find_unique_abbrev(dst_cmd->old_oid.hash, DEFAULT_ABBREV), + find_unique_abbrev(dst_cmd->new_oid.hash, DEFAULT_ABBREV)); cmd->error_string = dst_cmd->error_string = "inconsistent aliased update"; @@@ -1231,10 -1231,10 +1231,10 @@@ static int command_singleton_iterator(v struct command **cmd_list = cb_data; struct command *cmd = *cmd_list; - if (!cmd || is_null_sha1(cmd->new_sha1)) + if (!cmd || is_null_oid(&cmd->new_oid)) return -1; /* end of list */ *cmd_list = NULL; /* this returns only one */ - hashcpy(sha1, cmd->new_sha1); + hashcpy(sha1, cmd->new_oid.hash); return 0; } @@@ -1275,8 -1275,8 +1275,8 @@@ static int iterate_receive_command_list if (shallow_update && data->si->shallow_ref[cmd->index]) /* to be checked in update_shallow_ref() */ continue; - if (!is_null_sha1(cmd->new_sha1) && !cmd->skip_update) { - hashcpy(sha1, cmd->new_sha1); + if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) { + hashcpy(sha1, cmd->new_oid.hash); *cmd_list = cmd->next; return 0; } @@@ -1303,7 -1303,7 +1303,7 @@@ static void reject_updates_to_hidden(st if (!ref_is_hidden(cmd->ref_name, refname_full.buf)) continue; - if (is_null_sha1(cmd->new_sha1)) + if (is_null_oid(&cmd->new_oid)) cmd->error_string = "deny deleting a hidden ref"; else cmd->error_string = "deny updating a hidden ref"; @@@ -1486,23 -1486,23 +1486,23 @@@ static struct command **queue_command(s const char *line, int linelen) { - unsigned char old_sha1[20], new_sha1[20]; + struct object_id old_oid, new_oid; struct command *cmd; const char *refname; int reflen; + const char *p; - if (linelen < 83 || - line[40] != ' ' || - line[81] != ' ' || - get_sha1_hex(line, old_sha1) || - get_sha1_hex(line + 41, new_sha1)) + if (parse_oid_hex(line, &old_oid, &p) || + *p++ != ' ' || + parse_oid_hex(p, &new_oid, &p) || + *p++ != ' ') die("protocol error: expected old/new/ref, got '%s'", line); - refname = line + 82; - reflen = linelen - 82; + refname = p; + reflen = linelen - (p - line); FLEX_ALLOC_MEM(cmd, ref_name, refname, reflen); - hashcpy(cmd->old_sha1, old_sha1); - hashcpy(cmd->new_sha1, new_sha1); + oidcpy(&cmd->old_oid, &old_oid); + oidcpy(&cmd->new_oid, &new_oid); *tail = cmd; return &cmd->next; } @@@ -1524,12 -1524,12 +1524,12 @@@ static void queue_commands_from_cert(st while (boc < eoc) { const char *eol = memchr(boc, '\n', eoc - boc); - tail = queue_command(tail, boc, eol ? eol - boc : eoc - eol); + tail = queue_command(tail, boc, eol ? eol - boc : eoc - boc); boc = eol ? eol + 1 : eoc; } } - static struct command *read_head_info(struct sha1_array *shallow) + static struct command *read_head_info(struct oid_array *shallow) { struct command *commands = NULL; struct command **p = &commands; @@@ -1541,12 -1541,12 +1541,12 @@@ if (!line) break; - if (len == 48 && starts_with(line, "shallow ")) { - unsigned char sha1[20]; - if (get_sha1_hex(line + 8, sha1)) + if (len > 8 && starts_with(line, "shallow ")) { + struct object_id oid; + if (get_oid_hex(line + 8, &oid)) die("protocol error: expected shallow sha, got '%s'", line + 8); - sha1_array_append(shallow, sha1); + oid_array_append(shallow, &oid); continue; } @@@ -1634,17 -1634,12 +1634,17 @@@ static const char *parse_pack_header(st static const char *pack_lockfile; +static void push_header_arg(struct argv_array *args, struct pack_header *hdr) +{ + argv_array_pushf(args, "--pack_header=%"PRIu32",%"PRIu32, + ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries)); +} + static const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; const char *hdr_err; int status; - char hdr_arg[38]; struct child_process child = CHILD_PROCESS_INIT; int fsck_objects = (receive_fsck_objects >= 0 ? receive_fsck_objects @@@ -1658,6 -1653,9 +1658,6 @@@ close(err_fd); return hdr_err; } - snprintf(hdr_arg, sizeof(hdr_arg), - "--pack_header=%"PRIu32",%"PRIu32, - ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); @@@ -1681,8 -1679,7 +1681,8 @@@ tmp_objdir_add_as_alternate(tmp_objdir); if (ntohl(hdr.hdr_entries) < unpack_limit) { - argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL); + argv_array_push(&child.args, "unpack-objects"); + push_header_arg(&child.args, &hdr); if (quiet) argv_array_push(&child.args, "-q"); if (fsck_objects) @@@ -1700,8 -1697,8 +1700,8 @@@ } else { char hostname[256]; - argv_array_pushl(&child.args, "index-pack", - "--stdin", hdr_arg, NULL); + argv_array_pushl(&child.args, "index-pack", "--stdin", NULL); + push_header_arg(&child.args, &hdr); if (gethostname(hostname, sizeof(hostname))) xsnprintf(hostname, sizeof(hostname), "localhost"); @@@ -1807,7 -1804,7 +1807,7 @@@ static void prepare_shallow_update(stru static void update_shallow_info(struct command *commands, struct shallow_info *si, - struct sha1_array *ref) + struct oid_array *ref) { struct command *cmd; int *ref_status; @@@ -1818,9 -1815,9 +1818,9 @@@ } for (cmd = commands; cmd; cmd = cmd->next) { - if (is_null_sha1(cmd->new_sha1)) + if (is_null_oid(&cmd->new_oid)) continue; - sha1_array_append(ref, cmd->new_sha1); + oid_array_append(ref, &cmd->new_oid); cmd->index = ref->nr - 1; } si->ref = ref; @@@ -1833,7 -1830,7 +1833,7 @@@ ALLOC_ARRAY(ref_status, ref->nr); assign_shallow_commits_to_refs(si, NULL, ref_status); for (cmd = commands; cmd; cmd = cmd->next) { - if (is_null_sha1(cmd->new_sha1)) + if (is_null_oid(&cmd->new_oid)) continue; if (ref_status[cmd->index]) { cmd->error_string = "shallow update not allowed"; @@@ -1871,7 -1868,7 +1871,7 @@@ static int delete_only(struct command * { struct command *cmd; for (cmd = commands; cmd; cmd = cmd->next) { - if (!is_null_sha1(cmd->new_sha1)) + if (!is_null_oid(&cmd->new_oid)) return 0; } return 1; @@@ -1881,8 -1878,8 +1881,8 @@@ int cmd_receive_pack(int argc, const ch { int advertise_refs = 0; struct command *commands; - struct sha1_array shallow = SHA1_ARRAY_INIT; - struct sha1_array ref = SHA1_ARRAY_INIT; + struct oid_array shallow = OID_ARRAY_INIT; + struct oid_array ref = OID_ARRAY_INIT; struct shallow_info si; struct option options[] = { @@@ -1974,8 -1971,8 +1974,8 @@@ } if (use_sideband) packet_flush(1); - sha1_array_clear(&shallow); - sha1_array_clear(&ref); + oid_array_clear(&shallow); + oid_array_clear(&ref); free((void *)push_cert_nonce); return 0; } diff --combined builtin/rev-parse.c index f54d7b5028,8d635add8f..0513330910 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@@ -205,22 -205,21 +205,22 @@@ static int anti_reference(const char *r return 0; } - static int show_abbrev(const unsigned char *sha1, void *cb_data) + static int show_abbrev(const struct object_id *oid, void *cb_data) { - show_rev(NORMAL, sha1, NULL); + show_rev(NORMAL, oid->hash, NULL); return 0; } static void show_datestring(const char *flag, const char *datestr) { - static char buffer[100]; + char *buffer; /* date handling requires both flags and revs */ if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS)) return; - snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr)); + buffer = xstrfmt("%s%lu", flag, approxidate(datestr)); show(buffer); + free(buffer); } static int show_file(const char *arg, int output_prefix) @@@ -229,9 -228,9 +229,9 @@@ if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) { if (output_prefix) { const char *prefix = startup_info->prefix; - show(prefix_filename(prefix, - prefix ? strlen(prefix) : 0, - arg)); + char *fname = prefix_filename(prefix, arg); + show(fname); + free(fname); } else show(arg); return 1; diff --combined builtin/send-pack.c index 832fd7ed0a,b646194429..b8e2e74fe0 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@@ -131,8 -131,8 +131,8 @@@ int cmd_send_pack(int argc, const char const char *dest = NULL; int fd[2]; struct child_process *conn; - struct sha1_array extra_have = SHA1_ARRAY_INIT; - struct sha1_array shallow = SHA1_ARRAY_INIT; + struct oid_array extra_have = OID_ARRAY_INIT; + struct oid_array shallow = OID_ARRAY_INIT; struct ref *remote_refs, *local_refs; int ret; int helper_status = 0; @@@ -144,7 -144,6 +144,7 @@@ unsigned force_update = 0; unsigned quiet = 0; int push_cert = 0; + struct string_list push_options = STRING_LIST_INIT_NODUP; unsigned use_thin_pack = 0; unsigned atomic = 0; unsigned stateless_rpc = 0; @@@ -166,9 -165,6 +166,9 @@@ { OPTION_CALLBACK, 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, + OPT_STRING_LIST(0, "push-option", &push_options, + N_("server-specific"), + N_("option to transmit")), OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")), OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")), @@@ -203,7 -199,6 +203,7 @@@ args.use_thin_pack = use_thin_pack; args.atomic = atomic; args.stateless_rpc = stateless_rpc; + args.push_options = push_options.nr ? &push_options : NULL; if (from_stdin) { struct argv_array all_refspecs = ARGV_ARRAY_INIT; diff --combined cache.h index 556468c25b,93e7f0d000..ba27595d54 --- a/cache.h +++ b/cache.h @@@ -66,8 -66,12 +66,12 @@@ unsigned long git_deflate_bound(git_zst #define GIT_SHA1_RAWSZ 20 #define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) + /* The length in byte and in hex digits of the largest possible hash value. */ + #define GIT_MAX_RAWSZ GIT_SHA1_RAWSZ + #define GIT_MAX_HEXSZ GIT_SHA1_HEXSZ + struct object_id { - unsigned char hash[GIT_SHA1_RAWSZ]; + unsigned char hash[GIT_MAX_RAWSZ]; }; #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) @@@ -343,7 -347,6 +347,7 @@@ struct index_state extern struct index_state the_index; /* Name hashing */ +extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded); extern void add_name_hash(struct index_state *istate, struct cache_entry *ce); extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce); extern void free_name_hash(struct index_state *istate); @@@ -411,7 -414,6 +415,7 @@@ static inline enum object_type object_t #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE" #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX" #define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX" +#define GIT_TOPLEVEL_PREFIX_ENVIRONMENT "GIT_INTERNAL_TOPLEVEL_PREFIX" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY" #define INDEX_ENVIRONMENT "GIT_INDEX_FILE" @@@ -531,19 -533,7 +535,19 @@@ extern const char *setup_git_directory_ extern const char *setup_git_directory(void); extern char *prefix_path(const char *prefix, int len, const char *path); extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path); -extern const char *prefix_filename(const char *prefix, int len, const char *path); + +/* + * Concatenate "prefix" (if len is non-zero) and "path", with no + * connecting characters (so "prefix" should end with a "/"). + * Unlike prefix_path, this should be used if the named file does + * not have to interact with index entry; i.e. name of a random file + * on the filesystem. + * + * The return value is always a newly allocated string (even if the + * prefix was empty). + */ +extern char *prefix_filename(const char *prefix, const char *path); + extern int check_filename(const char *prefix, const char *name); extern void verify_filename(const char *prefix, const char *name, @@@ -978,7 -968,7 +982,7 @@@ extern char *sha1_pack_index_name(cons extern const char *find_unique_abbrev(const unsigned char *sha1, int len); extern int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len); - extern const unsigned char null_sha1[GIT_SHA1_RAWSZ]; + extern const unsigned char null_sha1[GIT_MAX_RAWSZ]; extern const struct object_id null_oid; static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) @@@ -1360,7 -1350,7 +1364,7 @@@ extern int get_sha1_with_context(const extern int get_oid(const char *str, struct object_id *oid); - typedef int each_abbrev_fn(const unsigned char *sha1, void *); + typedef int each_abbrev_fn(const struct object_id *oid, void *); extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *); extern int set_disambiguate_hint_config(const char *var, const char *value); @@@ -1675,12 -1665,9 +1679,12 @@@ extern struct packed_git *find_sha1_pac extern void pack_report(void); /* - * Create a temporary file rooted in the object database directory. + * Create a temporary file rooted in the object database directory, or + * die on failure. The filename is taken from "pattern", which should have the + * usual "XXXXXX" trailer, and the resulting filename is written into the + * "template" buffer. Returns the open descriptor. */ -extern int odb_mkstemp(char *template, size_t limit, const char *pattern); +extern int odb_mkstemp(struct strbuf *template, const char *pattern); /* * Generate the filename to be used for a pack file with checksum "sha1" and diff --combined combine-diff.c index d3560573ac,c5586c972d..2848034fe9 --- a/combine-diff.c +++ b/combine-diff.c @@@ -292,10 -292,9 +292,10 @@@ static char *grab_blob(const struct obj enum object_type type; if (S_ISGITLINK(mode)) { - blob = xmalloc(100); - *size = snprintf(blob, 100, - "Subproject commit %s\n", oid_to_hex(oid)); + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "Subproject commit %s\n", oid_to_hex(oid)); + *size = buf.len; + blob = strbuf_detach(&buf, NULL); } else if (is_null_oid(oid)) { /* deleted blob */ *size = 0; @@@ -1312,7 -1311,7 +1312,7 @@@ static const char *path_path(void *obj /* find set of paths that every parent touches */ static struct combine_diff_path *find_paths_generic(const unsigned char *sha1, - const struct sha1_array *parents, struct diff_options *opt) + const struct oid_array *parents, struct diff_options *opt) { struct combine_diff_path *paths = NULL; int i, num_parent = parents->nr; @@@ -1336,7 -1335,7 +1336,7 @@@ opt->output_format = stat_opt; else opt->output_format = DIFF_FORMAT_NO_OUTPUT; - diff_tree_sha1(parents->sha1[i], sha1, "", opt); + diff_tree_sha1(parents->oid[i].hash, sha1, "", opt); diffcore_std(opt); paths = intersect_paths(paths, i, num_parent); @@@ -1360,7 -1359,7 +1360,7 @@@ * rename/copy detection, etc, comparing all trees simultaneously (= faster). */ static struct combine_diff_path *find_paths_multitree( - const unsigned char *sha1, const struct sha1_array *parents, + const unsigned char *sha1, const struct oid_array *parents, struct diff_options *opt) { int i, nparent = parents->nr; @@@ -1370,7 -1369,7 +1370,7 @@@ ALLOC_ARRAY(parents_sha1, nparent); for (i = 0; i < nparent; i++) - parents_sha1[i] = parents->sha1[i]; + parents_sha1[i] = parents->oid[i].hash; /* fake list head, so worker can assume it is non-NULL */ paths_head.next = NULL; @@@ -1385,7 -1384,7 +1385,7 @@@ void diff_tree_combined(const unsigned char *sha1, - const struct sha1_array *parents, + const struct oid_array *parents, int dense, struct rev_info *rev) { @@@ -1463,7 -1462,7 +1463,7 @@@ if (stat_opt) { diffopts.output_format = stat_opt; - diff_tree_sha1(parents->sha1[0], sha1, "", &diffopts); + diff_tree_sha1(parents->oid[0].hash, sha1, "", &diffopts); diffcore_std(&diffopts); if (opt->orderfile) diffcore_order(opt->orderfile); @@@ -1533,12 -1532,12 +1533,12 @@@ void diff_tree_combined_merge(const str struct rev_info *rev) { struct commit_list *parent = get_saved_parents(rev, commit); - struct sha1_array parents = SHA1_ARRAY_INIT; + struct oid_array parents = OID_ARRAY_INIT; while (parent) { - sha1_array_append(&parents, parent->item->object.oid.hash); + oid_array_append(&parents, &parent->item->object.oid); parent = parent->next; } diff_tree_combined(commit->object.oid.hash, &parents, dense, rev); - sha1_array_clear(&parents); + oid_array_clear(&parents); } diff --combined diff.c index 92d78e4596,330b640c68..11eef1c85d --- a/diff.c +++ b/diff.c @@@ -398,7 -398,7 +398,7 @@@ static struct diff_tempfile */ const char *name; - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; char mode[10]; /* @@@ -4023,7 -4023,8 +4023,7 @@@ int diff_opt_parse(struct diff_options else if (!strcmp(arg, "--pickaxe-regex")) options->pickaxe_opts |= DIFF_PICKAXE_REGEX; else if ((argcount = short_opt('O', av, &optarg))) { - const char *path = prefix_filename(prefix, strlen(prefix), optarg); - options->orderfile = xstrdup(path); + options->orderfile = prefix_filename(prefix, optarg); return argcount; } else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { @@@ -4070,14 -4071,13 +4070,14 @@@ else if (!strcmp(arg, "--no-function-context")) DIFF_OPT_CLR(options, FUNCCONTEXT); else if ((argcount = parse_long_opt("output", av, &optarg))) { - const char *path = prefix_filename(prefix, strlen(prefix), optarg); + char *path = prefix_filename(prefix, optarg); options->file = fopen(path, "w"); if (!options->file) die_errno("Could not open '%s'", path); options->close_file = 1; if (options->use_color != GIT_COLOR_ALWAYS) options->use_color = GIT_COLOR_NEVER; + free(path); return argcount; } else return 0; @@@ -4219,7 -4219,7 +4219,7 @@@ const char *diff_aligned_abbrev(const s * uniqueness across all objects (statistically speaking). */ if (abblen < GIT_SHA1_HEXSZ - 3) { - static char hex[GIT_SHA1_HEXSZ + 1]; + static char hex[GIT_MAX_HEXSZ + 1]; if (len < abblen && abblen <= len + 2) xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, ".."); else @@@ -4570,19 -4570,6 +4570,19 @@@ static void patch_id_consume(void *priv data->patchlen += new_len; } +static void patch_id_add_string(git_SHA_CTX *ctx, const char *str) +{ + git_SHA1_Update(ctx, str, strlen(str)); +} + +static void patch_id_add_mode(git_SHA_CTX *ctx, unsigned mode) +{ + /* large enough for 2^32 in octal */ + char buf[12]; + int len = xsnprintf(buf, sizeof(buf), "%06o", mode); + git_SHA1_Update(ctx, buf, len); +} + /* returns 0 upon success, and writes result into sha1 */ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only) { @@@ -4590,6 -4577,7 +4590,6 @@@ int i; git_SHA_CTX ctx; struct patch_id_t data; - char buffer[PATH_MAX * 4 + 20]; git_SHA1_Init(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); @@@ -4621,30 -4609,36 +4621,30 @@@ len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); - if (p->one->mode == 0) - len1 = snprintf(buffer, sizeof(buffer), - "diff--gita/%.*sb/%.*s" - "newfilemode%06o" - "---/dev/null" - "+++b/%.*s", - len1, p->one->path, - len2, p->two->path, - p->two->mode, - len2, p->two->path); - else if (p->two->mode == 0) - len1 = snprintf(buffer, sizeof(buffer), - "diff--gita/%.*sb/%.*s" - "deletedfilemode%06o" - "---a/%.*s" - "+++/dev/null", - len1, p->one->path, - len2, p->two->path, - p->one->mode, - len1, p->one->path); - else - len1 = snprintf(buffer, sizeof(buffer), - "diff--gita/%.*sb/%.*s" - "---a/%.*s" - "+++b/%.*s", - len1, p->one->path, - len2, p->two->path, - len1, p->one->path, - len2, p->two->path); - git_SHA1_Update(&ctx, buffer, len1); + patch_id_add_string(&ctx, "diff--git"); + patch_id_add_string(&ctx, "a/"); + git_SHA1_Update(&ctx, p->one->path, len1); + patch_id_add_string(&ctx, "b/"); + git_SHA1_Update(&ctx, p->two->path, len2); + + if (p->one->mode == 0) { + patch_id_add_string(&ctx, "newfilemode"); + patch_id_add_mode(&ctx, p->two->mode); + patch_id_add_string(&ctx, "---/dev/null"); + patch_id_add_string(&ctx, "+++b/"); + git_SHA1_Update(&ctx, p->two->path, len2); + } else if (p->two->mode == 0) { + patch_id_add_string(&ctx, "deletedfilemode"); + patch_id_add_mode(&ctx, p->one->mode); + patch_id_add_string(&ctx, "---a/"); + git_SHA1_Update(&ctx, p->one->path, len1); + patch_id_add_string(&ctx, "+++/dev/null"); + } else { + patch_id_add_string(&ctx, "---a/"); + git_SHA1_Update(&ctx, p->one->path, len1); + patch_id_add_string(&ctx, "+++b/"); + git_SHA1_Update(&ctx, p->two->path, len2); + } if (diff_header_only) continue; diff --combined ref-filter.c index 1e39273005,fe1abf65ff..3a640448fd --- a/ref-filter.c +++ b/ref-filter.c @@@ -1487,7 -1487,6 +1487,7 @@@ struct ref_filter_cbdata struct ref_array *array; struct ref_filter *filter; struct contains_cache contains_cache; + struct contains_cache no_contains_cache; }; /* @@@ -1587,11 -1586,11 +1587,11 @@@ static enum contains_result contains_ta } static int commit_contains(struct ref_filter *filter, struct commit *commit, - struct contains_cache *cache) + struct commit_list *list, struct contains_cache *cache) { if (filter->with_commit_tag_algo) - return contains_tag_algo(commit, filter->with_commit, cache) == CONTAINS_YES; - return is_descendant_of(commit, filter->with_commit); + return contains_tag_algo(commit, list, cache) == CONTAINS_YES; + return is_descendant_of(commit, list); } /* @@@ -1678,22 -1677,22 +1678,22 @@@ static int filter_pattern_match(struct * the need to parse the object via parse_object(). peel_ref() might be a * more efficient alternative to obtain the pointee. */ - static const unsigned char *match_points_at(struct sha1_array *points_at, - const unsigned char *sha1, - const char *refname) + static const struct object_id *match_points_at(struct oid_array *points_at, + const struct object_id *oid, + const char *refname) { - const unsigned char *tagged_sha1 = NULL; + const struct object_id *tagged_oid = NULL; struct object *obj; - if (sha1_array_lookup(points_at, sha1) >= 0) - return sha1; - obj = parse_object(sha1); + if (oid_array_lookup(points_at, oid) >= 0) + return oid; + obj = parse_object(oid->hash); if (!obj) die(_("malformed object at '%s'"), refname); if (obj->type == OBJ_TAG) - tagged_sha1 = ((struct tag *)obj)->tagged->oid.hash; - if (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0) - return tagged_sha1; + tagged_oid = &((struct tag *)obj)->tagged->oid; + if (tagged_oid && oid_array_lookup(points_at, tagged_oid) >= 0) + return tagged_oid; return NULL; } @@@ -1773,7 -1772,7 +1773,7 @@@ static int ref_filter_handler(const cha if (!filter_pattern_match(filter, refname)) return 0; - if (filter->points_at.nr && !match_points_at(&filter->points_at, oid->hash, refname)) + if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname)) return 0; /* @@@ -1781,17 -1780,13 +1781,17 @@@ * obtain the commit using the 'oid' available and discard all * non-commits early. The actual filtering is done later. */ - if (filter->merge_commit || filter->with_commit || filter->verbose) { + if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { commit = lookup_commit_reference_gently(oid->hash, 1); if (!commit) return 0; - /* We perform the filtering for the '--contains' option */ + /* We perform the filtering for the '--contains' option... */ if (filter->with_commit && - !commit_contains(filter, commit, &ref_cbdata->contains_cache)) + !commit_contains(filter, commit, filter->with_commit, &ref_cbdata->contains_cache)) + return 0; + /* ...or for the `--no-contains' option */ + if (filter->no_commit && + commit_contains(filter, commit, filter->no_commit, &ref_cbdata->no_contains_cache)) return 0; } @@@ -1892,7 -1887,6 +1892,7 @@@ int filter_refs(struct ref_array *array filter->kind = type & FILTER_REFS_KIND_MASK; init_contains_cache(&ref_cbdata.contains_cache); + init_contains_cache(&ref_cbdata.no_contains_cache); /* Simple per-ref filtering */ if (!filter->kind) @@@ -1917,7 -1911,6 +1917,7 @@@ } clear_contains_cache(&ref_cbdata.contains_cache); + clear_contains_cache(&ref_cbdata.no_contains_cache); /* Filters that need revision walking */ if (filter->merge_commit) @@@ -2091,17 -2084,8 +2091,17 @@@ int parse_opt_merge_filter(const struc { struct ref_filter *rf = opt->value; unsigned char sha1[20]; + int no_merged = starts_with(opt->long_name, "no"); + + if (rf->merge) { + if (no_merged) { + return opterror(opt, "is incompatible with --merged", 0); + } else { + return opterror(opt, "is incompatible with --no-merged", 0); + } + } - rf->merge = starts_with(opt->long_name, "no") + rf->merge = no_merged ? REF_FILTER_MERGED_OMIT : REF_FILTER_MERGED_INCLUDE; diff --combined ref-filter.h index dde40f6849,e5e177d5f1..c20167aa3c --- a/ref-filter.h +++ b/ref-filter.h @@@ -51,9 -51,8 +51,9 @@@ struct ref_array struct ref_filter { const char **name_patterns; - struct sha1_array points_at; + struct oid_array points_at; struct commit_list *with_commit; + struct commit_list *no_commit; enum { REF_FILTER_MERGED_NONE = 0, diff --combined remote-curl.c index e953d06f66,82a019d7db..d41fe16ff3 --- a/remote-curl.c +++ b/remote-curl.c @@@ -22,7 -22,6 +22,7 @@@ struct options unsigned long depth; char *deepen_since; struct string_list deepen_not; + struct string_list push_options; unsigned progress : 1, check_self_contained_and_connected : 1, cloning : 1, @@@ -140,9 -139,6 +140,9 @@@ static int set_option(const char *name else return -1; return 0; + } else if (!strcmp(name, "push-option")) { + string_list_append(&options.push_options, value); + return 0; #if LIBCURL_VERSION_NUM >= 0x070a08 } else if (!strcmp(name, "family")) { @@@ -167,7 -163,7 +167,7 @@@ struct discovery char *buf; size_t len; struct ref *refs; - struct sha1_array shallow; + struct oid_array shallow; unsigned proto_git : 1; }; static struct discovery *last_discovery; @@@ -234,7 -230,7 +234,7 @@@ static void free_discovery(struct disco if (d) { if (d == last_discovery) last_discovery = NULL; - free(d->shallow.sha1); + free(d->shallow.oid); free(d->buf_alloc); free_refs(d->refs); free(d); @@@ -947,9 -943,6 +947,9 @@@ static int push_git(struct discovery *h argv_array_push(&args, "--quiet"); else if (options.verbosity > 1) argv_array_push(&args, "--verbose"); + for (i = 0; i < options.push_options.nr; i++) + argv_array_pushf(&args, "--push-option=%s", + options.push_options.items[i].string); argv_array_push(&args, options.progress ? "--progress" : "--no-progress"); for_each_string_list_item(cas_option, &cas_options) argv_array_push(&args, cas_option->string); @@@ -1035,7 -1028,6 +1035,7 @@@ int cmd_main(int argc, const char **arg options.progress = !!isatty(2); options.thin = 1; string_list_init(&options.deepen_not, 1); + string_list_init(&options.push_options, 1); remote = remote_get(argv[1]); diff --combined remote.h index d7992c4ef1,eb61cc884d..949badc4ee --- a/remote.h +++ b/remote.h @@@ -149,11 -149,11 +149,11 @@@ int check_ref_type(const struct ref *re */ void free_refs(struct ref *ref); - struct sha1_array; + struct oid_array; extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, struct ref **list, unsigned int flags, - struct sha1_array *extra_have, - struct sha1_array *shallow); + struct oid_array *extra_have, + struct oid_array *shallow); int resolve_remote_symref(struct ref *ref, struct ref *list); int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); @@@ -290,6 -290,7 +290,6 @@@ struct push_cas_option }; extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset); -extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset); extern int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); diff --combined send-pack.c index 66e652f7ef,312cd2c282..78bb34ebec --- a/send-pack.c +++ b/send-pack.c @@@ -50,7 -50,7 +50,7 @@@ static void feed_object(const unsigned /* * Make a pack stream and spit it out into file descriptor fd */ - static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, struct send_pack_args *args) + static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struct send_pack_args *args) { /* * The child becomes pack-objects --revs; we feed @@@ -98,7 -98,7 +98,7 @@@ */ po_in = xfdopen(po.in, "w"); for (i = 0; i < extra->nr; i++) - feed_object(extra->sha1[i], po_in, 1); + feed_object(extra->oid[i].hash, po_in, 1); while (refs) { if (!is_null_oid(&refs->old_oid)) @@@ -376,7 -376,7 +376,7 @@@ static void reject_invalid_nonce(const int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, - struct sha1_array *extra_have) + struct oid_array *extra_have) { int in = fd[0]; int out = fd[1]; @@@ -532,14 -532,6 +532,14 @@@ } } + if (use_push_options) { + struct string_list_item *item; + + packet_buf_flush(&req_buf); + for_each_string_list_item(item, args->push_options) + packet_buf_write(&req_buf, "%s", item->string); + } + if (args->stateless_rpc) { if (!args->dry_run && (cmds_sent || is_repository_shallow())) { packet_buf_flush(&req_buf); @@@ -552,6 -544,18 +552,6 @@@ strbuf_release(&req_buf); strbuf_release(&cap_buf); - if (use_push_options) { - struct string_list_item *item; - struct strbuf sb = STRBUF_INIT; - - for_each_string_list_item(item, args->push_options) - packet_buf_write(&sb, "%s", item->string); - - write_or_die(out, sb.buf, sb.len); - packet_flush(out); - strbuf_release(&sb); - } - if (use_sideband && cmds_sent) { memset(&demux, 0, sizeof(demux)); demux.proc = sideband_demux; diff --combined sha1_file.c index 7369f7495a,b4666ee5c2..2270f36a2b --- a/sha1_file.c +++ b/sha1_file.c @@@ -1606,7 -1606,7 +1606,7 @@@ static void mark_bad_packed_object(stru if (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i)) return; p->bad_object_sha1 = xrealloc(p->bad_object_sha1, - st_mult(GIT_SHA1_RAWSZ, + st_mult(GIT_MAX_RAWSZ, st_add(p->num_bad_objects, 1))); hashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1); p->num_bad_objects++; @@@ -2952,7 -2952,7 +2952,7 @@@ static int sha1_loose_object_info(cons if (status && oi->typep) *oi->typep = status; strbuf_release(&hdrbuf); - return 0; + return (status < 0) ? status : 0; } int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags) @@@ -3759,11 -3759,11 +3759,11 @@@ static int for_each_file_in_obj_subdir( strbuf_addf(path, "/%s", de->d_name); if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2) { - char hex[GIT_SHA1_HEXSZ+1]; + char hex[GIT_MAX_HEXSZ+1]; struct object_id oid; - snprintf(hex, sizeof(hex), "%02x%s", - subdir_nr, de->d_name); + xsnprintf(hex, sizeof(hex), "%02x%s", + subdir_nr, de->d_name); if (!get_oid_hex(hex, &oid)) { if (obj_cb) { r = obj_cb(&oid, path->buf, data); @@@ -3913,7 -3913,7 +3913,7 @@@ static int check_stream_sha1(git_zstrea const unsigned char *expected_sha1) { git_SHA_CTX c; - unsigned char real_sha1[GIT_SHA1_RAWSZ]; + unsigned char real_sha1[GIT_MAX_RAWSZ]; unsigned char buf[4096]; unsigned long total_read; int status = Z_OK; diff --combined sha1_name.c index d9d1b2fce8,323dd34c63..8eec9f7c1b --- a/sha1_name.c +++ b/sha1_name.c @@@ -11,16 -11,16 +11,16 @@@ static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *); - typedef int (*disambiguate_hint_fn)(const unsigned char *, void *); + typedef int (*disambiguate_hint_fn)(const struct object_id *, void *); struct disambiguate_state { int len; /* length of prefix in hex chars */ - char hex_pfx[GIT_SHA1_HEXSZ + 1]; - unsigned char bin_pfx[GIT_SHA1_RAWSZ]; + char hex_pfx[GIT_MAX_HEXSZ + 1]; + struct object_id bin_pfx; disambiguate_hint_fn fn; void *cb_data; - unsigned char candidate[GIT_SHA1_RAWSZ]; + struct object_id candidate; unsigned candidate_exists:1; unsigned candidate_checked:1; unsigned candidate_ok:1; @@@ -29,7 -29,7 +29,7 @@@ unsigned always_call_fn:1; }; - static void update_candidates(struct disambiguate_state *ds, const unsigned char *current) + static void update_candidates(struct disambiguate_state *ds, const struct object_id *current) { if (ds->always_call_fn) { ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0; @@@ -37,10 -37,10 +37,10 @@@ } if (!ds->candidate_exists) { /* this is the first candidate */ - hashcpy(ds->candidate, current); + oidcpy(&ds->candidate, current); ds->candidate_exists = 1; return; - } else if (!hashcmp(ds->candidate, current)) { + } else if (!oidcmp(&ds->candidate, current)) { /* the same as what we already have seen */ return; } @@@ -52,14 -52,14 +52,14 @@@ } if (!ds->candidate_checked) { - ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data); + ds->candidate_ok = ds->fn(&ds->candidate, ds->cb_data); ds->disambiguate_fn_used = 1; ds->candidate_checked = 1; } if (!ds->candidate_ok) { /* discard the candidate; we know it does not satisfy fn */ - hashcpy(ds->candidate, current); + oidcpy(&ds->candidate, current); ds->candidate_checked = 0; return; } @@@ -80,7 -80,7 +80,7 @@@ static void find_short_object_filename(struct disambiguate_state *ds) { struct alternate_object_database *alt; - char hex[GIT_SHA1_HEXSZ]; + char hex[GIT_MAX_HEXSZ]; static struct alternate_object_database *fakeent; if (!fakeent) { @@@ -107,15 -107,15 +107,15 @@@ continue; while (!ds->ambiguous && (de = readdir(dir)) != NULL) { - unsigned char sha1[20]; + struct object_id oid; - if (strlen(de->d_name) != 38) + if (strlen(de->d_name) != GIT_SHA1_HEXSZ - 2) continue; if (memcmp(de->d_name, ds->hex_pfx + 2, ds->len - 2)) continue; - memcpy(hex + 2, de->d_name, 38); - if (!get_sha1_hex(hex, sha1)) - update_candidates(ds, sha1); + memcpy(hex + 2, de->d_name, GIT_SHA1_HEXSZ - 2); + if (!get_oid_hex(hex, &oid)) + update_candidates(ds, &oid); } closedir(dir); } @@@ -140,7 -140,7 +140,7 @@@ static void unique_in_pack(struct packe struct disambiguate_state *ds) { uint32_t num, last, i, first = 0; - const unsigned char *current = NULL; + const struct object_id *current = NULL; open_pack_index(p); num = p->num_objects; @@@ -151,7 -151,7 +151,7 @@@ int cmp; current = nth_packed_object_sha1(p, mid); - cmp = hashcmp(ds->bin_pfx, current); + cmp = hashcmp(ds->bin_pfx.hash, current); if (!cmp) { first = mid; break; @@@ -169,8 -169,9 +169,9 @@@ * 0, 1 or more objects that actually match(es). */ for (i = first; i < num && !ds->ambiguous; i++) { - current = nth_packed_object_sha1(p, i); - if (!match_sha(ds->len, ds->bin_pfx, current)) + struct object_id oid; + current = nth_packed_object_oid(&oid, p, i); + if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash)) break; update_candidates(ds, current); } @@@ -213,66 -214,66 +214,66 @@@ static int finish_object_disambiguation * same repository! */ ds->candidate_ok = (!ds->disambiguate_fn_used || - ds->fn(ds->candidate, ds->cb_data)); + ds->fn(&ds->candidate, ds->cb_data)); if (!ds->candidate_ok) return SHORT_NAME_AMBIGUOUS; - hashcpy(sha1, ds->candidate); + hashcpy(sha1, ds->candidate.hash); return 0; } - static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused) + static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused) { - int kind = sha1_object_info(sha1, NULL); + int kind = sha1_object_info(oid->hash, NULL); return kind == OBJ_COMMIT; } - static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused) + static int disambiguate_committish_only(const struct object_id *oid, void *cb_data_unused) { struct object *obj; int kind; - kind = sha1_object_info(sha1, NULL); + kind = sha1_object_info(oid->hash, NULL); if (kind == OBJ_COMMIT) return 1; if (kind != OBJ_TAG) return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(sha1), NULL, 0); + obj = deref_tag(parse_object(oid->hash), NULL, 0); if (obj && obj->type == OBJ_COMMIT) return 1; return 0; } - static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused) + static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused) { - int kind = sha1_object_info(sha1, NULL); + int kind = sha1_object_info(oid->hash, NULL); return kind == OBJ_TREE; } - static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused) + static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_unused) { struct object *obj; int kind; - kind = sha1_object_info(sha1, NULL); + kind = sha1_object_info(oid->hash, NULL); if (kind == OBJ_TREE || kind == OBJ_COMMIT) return 1; if (kind != OBJ_TAG) return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(sha1), NULL, 0); + obj = deref_tag(parse_object(oid->hash), NULL, 0); if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT)) return 1; return 0; } - static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused) + static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused) { - int kind = sha1_object_info(sha1, NULL); + int kind = sha1_object_info(oid->hash, NULL); return kind == OBJ_BLOB; } @@@ -332,7 -333,7 +333,7 @@@ static int init_object_disambiguation(c ds->hex_pfx[i] = c; if (!(i & 1)) val <<= 4; - ds->bin_pfx[i >> 1] |= val; + ds->bin_pfx.hash[i >> 1] |= val; } ds->len = len; @@@ -341,31 -342,32 +342,32 @@@ return 0; } - static int show_ambiguous_object(const unsigned char *sha1, void *data) + static int show_ambiguous_object(const struct object_id *oid, void *data) { const struct disambiguate_state *ds = data; struct strbuf desc = STRBUF_INIT; int type; - if (ds->fn && !ds->fn(sha1, ds->cb_data)) + + if (ds->fn && !ds->fn(oid, ds->cb_data)) return 0; - type = sha1_object_info(sha1, NULL); + type = sha1_object_info(oid->hash, NULL); if (type == OBJ_COMMIT) { - struct commit *commit = lookup_commit(sha1); + struct commit *commit = lookup_commit(oid->hash); if (commit) { struct pretty_print_context pp = {0}; pp.date_mode.type = DATE_SHORT; format_commit_message(commit, " %ad - %s", &desc, &pp); } } else if (type == OBJ_TAG) { - struct tag *tag = lookup_tag(sha1); + struct tag *tag = lookup_tag(oid->hash); if (!parse_tag(tag) && tag->tag) strbuf_addf(&desc, " %s", tag->tag); } advise(" %s %s%s", - find_unique_abbrev(sha1, DEFAULT_ABBREV), + find_unique_abbrev(oid->hash, DEFAULT_ABBREV), typename(type) ? typename(type) : "unknown type", desc.buf); @@@ -422,15 -424,15 +424,15 @@@ static int get_short_sha1(const char *n return status; } - static int collect_ambiguous(const unsigned char *sha1, void *data) + static int collect_ambiguous(const struct object_id *oid, void *data) { - sha1_array_append(data, sha1); + oid_array_append(data, oid); return 0; } int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data) { - struct sha1_array collect = SHA1_ARRAY_INIT; + struct oid_array collect = OID_ARRAY_INIT; struct disambiguate_state ds; int ret; @@@ -443,8 -445,8 +445,8 @@@ find_short_object_filename(&ds); find_short_packed_object(&ds); - ret = sha1_array_for_each_unique(&collect, fn, cb_data); - sha1_array_clear(&collect); + ret = oid_array_for_each_unique(&collect, fn, cb_data); + oid_array_clear(&collect); return ret; } @@@ -509,7 -511,7 +511,7 @@@ int find_unique_abbrev_r(char *hex, con const char *find_unique_abbrev(const unsigned char *sha1, int len) { static int bufno; - static char hexbuffer[4][GIT_SHA1_HEXSZ + 1]; + static char hexbuffer[4][GIT_MAX_HEXSZ + 1]; char *hex = hexbuffer[bufno]; bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer); find_unique_abbrev_r(hex, sha1, len); @@@ -549,7 -551,7 +551,7 @@@ static inline int at_mark(const char *s for (i = 0; i < nr; i++) { int suffix_len = strlen(suffix[i]); if (suffix_len <= len - && !memcmp(string, suffix[i], suffix_len)) + && !strncasecmp(string, suffix[i], suffix_len)) return suffix_len; } return 0; diff --combined submodule.c index 2ee9705729,b6bfb0cad9..6368d5fa6a --- a/submodule.c +++ b/submodule.c @@@ -17,12 -17,11 +17,12 @@@ #include "worktree.h" static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND; +static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int parallel_jobs = 1; static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP; static int initialized_fetch_ref_tips; - static struct sha1_array ref_tips_before_fetch; - static struct sha1_array ref_tips_after_fetch; + static struct oid_array ref_tips_before_fetch; + static struct oid_array ref_tips_after_fetch; /* * The following flag is set if the .gitmodules file is unmerged. We then @@@ -213,68 -212,37 +213,68 @@@ void gitmodules_config_sha1(const unsig } /* + * NEEDSWORK: With the addition of different configuration options to determine + * if a submodule is of interests, the validity of this function's name comes + * into question. Once the dust has settled and more concrete terminology is + * decided upon, come up with a more proper name for this function. One + * potential candidate could be 'is_submodule_active()'. + * * Determine if a submodule has been initialized at a given 'path' */ int is_submodule_initialized(const char *path) { int ret = 0; - const struct submodule *module = NULL; + char *key = NULL; + char *value = NULL; + const struct string_list *sl; + const struct submodule *module = submodule_from_path(null_sha1, path); - module = submodule_from_path(null_sha1, path); + /* early return if there isn't a path->module mapping */ + if (!module) + return 0; - if (module) { - char *key = xstrfmt("submodule.%s.url", module->name); - char *value = NULL; + /* submodule..active is set */ + key = xstrfmt("submodule.%s.active", module->name); + if (!git_config_get_bool(key, &ret)) { + free(key); + return ret; + } + free(key); - ret = !git_config_get_string(key, &value); + /* submodule.active is set */ + sl = git_config_get_value_multi("submodule.active"); + if (sl) { + struct pathspec ps; + struct argv_array args = ARGV_ARRAY_INIT; + const struct string_list_item *item; - free(value); - free(key); + for_each_string_list_item(item, sl) { + argv_array_push(&args, item->string); + } + + parse_pathspec(&ps, 0, 0, NULL, args.argv); + ret = match_pathspec(&ps, path, strlen(path), 0, NULL, 1); + + argv_array_clear(&args); + clear_pathspec(&ps); + return ret; } + /* fallback to checking if the URL is set */ + key = xstrfmt("submodule.%s.url", module->name); + ret = !git_config_get_string(key, &value); + + free(value); + free(key); return ret; } -/* - * Determine if a submodule has been populated at a given 'path' - */ -int is_submodule_populated(const char *path) +int is_submodule_populated_gently(const char *path, int *return_error_code) { int ret = 0; char *gitdir = xstrfmt("%s/.git", path); - if (resolve_gitdir(gitdir)) + if (resolve_gitdir_gently(gitdir, return_error_code)) ret = 1; free(gitdir); @@@ -390,23 -358,6 +390,23 @@@ static void print_submodule_summary(str strbuf_release(&sb); } +static void prepare_submodule_repo_env_no_git_dir(struct argv_array *out) +{ + const char * const *var; + + for (var = local_repo_env; *var; var++) { + if (strcmp(*var, CONFIG_DATA_ENVIRONMENT)) + argv_array_push(out, *var); + } +} + +void prepare_submodule_repo_env(struct argv_array *out) +{ + prepare_submodule_repo_env_no_git_dir(out); + argv_array_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT, + DEFAULT_GIT_DIR_ENVIRONMENT); +} + /* Helper function to display the submodule header line prior to the full * summary output. If it can locate the submodule objects directory it will * attempt to lookup both the left and right commits and put them into the @@@ -576,7 -527,6 +576,7 @@@ void show_submodule_inline_diff(FILE *f if (!(dirty_submodule & DIRTY_SUBMODULE_MODIFIED)) argv_array_push(&cp.args, oid_to_hex(new)); + prepare_submodule_repo_env(&cp.env_array); if (run_command(&cp)) fprintf(f, "(diff failed)\n"); @@@ -595,62 -545,41 +595,62 @@@ void set_config_fetch_recurse_submodule config_fetch_recurse_submodules = value; } +void set_config_update_recurse_submodules(int value) +{ + config_update_recurse_submodules = value; +} + +int should_update_submodules(void) +{ + return config_update_recurse_submodules == RECURSE_SUBMODULES_ON; +} + +const struct submodule *submodule_from_ce(const struct cache_entry *ce) +{ + if (!S_ISGITLINK(ce->ce_mode)) + return NULL; + + if (!should_update_submodules()) + return NULL; + + return submodule_from_path(null_sha1, ce->name); +} + static int has_remote(const char *refname, const struct object_id *oid, int flags, void *cb_data) { return 1; } - static int append_sha1_to_argv(const unsigned char sha1[20], void *data) + static int append_oid_to_argv(const struct object_id *oid, void *data) { struct argv_array *argv = data; - argv_array_push(argv, sha1_to_hex(sha1)); + argv_array_push(argv, oid_to_hex(oid)); return 0; } - static int check_has_commit(const unsigned char sha1[20], void *data) + static int check_has_commit(const struct object_id *oid, void *data) { int *has_commit = data; - if (!lookup_commit_reference(sha1)) + if (!lookup_commit_reference(oid->hash)) *has_commit = 0; return 0; } - static int submodule_has_commits(const char *path, struct sha1_array *commits) + static int submodule_has_commits(const char *path, struct oid_array *commits) { int has_commit = 1; if (add_submodule_odb(path)) return 0; - sha1_array_for_each_unique(commits, check_has_commit, &has_commit); + oid_array_for_each_unique(commits, check_has_commit, &has_commit); return has_commit; } - static int submodule_needs_pushing(const char *path, struct sha1_array *commits) + static int submodule_needs_pushing(const char *path, struct oid_array *commits) { if (!submodule_has_commits(path, commits)) /* @@@ -672,7 -601,7 +672,7 @@@ int needs_pushing = 0; argv_array_push(&cp.args, "rev-list"); - sha1_array_for_each_unique(commits, append_sha1_to_argv, &cp.args); + oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args); argv_array_pushl(&cp.args, "--not", "--remotes", "-n", "1" , NULL); prepare_submodule_repo_env(&cp.env_array); @@@ -694,18 -623,18 +694,18 @@@ return 0; } - static struct sha1_array *submodule_commits(struct string_list *submodules, + static struct oid_array *submodule_commits(struct string_list *submodules, const char *path) { struct string_list_item *item; item = string_list_insert(submodules, path); if (item->util) - return (struct sha1_array *) item->util; + return (struct oid_array *) item->util; - /* NEEDSWORK: should we have sha1_array_init()? */ - item->util = xcalloc(1, sizeof(struct sha1_array)); - return (struct sha1_array *) item->util; + /* NEEDSWORK: should we have oid_array_init()? */ + item->util = xcalloc(1, sizeof(struct oid_array)); + return (struct oid_array *) item->util; } static void collect_submodules_from_diff(struct diff_queue_struct *q, @@@ -717,11 -646,11 +717,11 @@@ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - struct sha1_array *commits; + struct oid_array *commits; if (!S_ISGITLINK(p->two->mode)) continue; commits = submodule_commits(submodules, p->two->path); - sha1_array_append(commits, p->two->oid.hash); + oid_array_append(commits, &p->two->oid); } } @@@ -741,11 -670,11 +741,11 @@@ static void free_submodules_sha1s(struc { struct string_list_item *item; for_each_string_list_item(item, submodules) - sha1_array_clear((struct sha1_array *) item->util); + oid_array_clear((struct oid_array *) item->util); string_list_clear(submodules, 1); } - int find_unpushed_submodules(struct sha1_array *commits, + int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing) { struct rev_info rev; @@@ -758,7 -687,7 +758,7 @@@ /* argv.argv[0] will be ignored by setup_revisions */ argv_array_push(&argv, "find_unpushed_submodules"); - sha1_array_for_each_unique(commits, append_sha1_to_argv, &argv); + oid_array_for_each_unique(commits, append_oid_to_argv, &argv); argv_array_push(&argv, "--not"); argv_array_pushf(&argv, "--remotes=%s", remotes_name); @@@ -773,7 -702,7 +773,7 @@@ argv_array_clear(&argv); for_each_string_list_item(submodule, &submodules) { - struct sha1_array *commits = (struct sha1_array *) submodule->util; + struct oid_array *commits = (struct oid_array *) submodule->util; if (submodule_needs_pushing(submodule->string, commits)) string_list_insert(needs_pushing, submodule->string); @@@ -806,7 -735,7 +806,7 @@@ static int push_submodule(const char *p return 1; } - int push_unpushed_submodules(struct sha1_array *commits, + int push_unpushed_submodules(struct oid_array *commits, const char *remotes_name, int dry_run) { @@@ -888,23 -817,23 +888,23 @@@ static void submodule_collect_changed_c static int add_sha1_to_array(const char *ref, const struct object_id *oid, int flags, void *data) { - sha1_array_append(data, oid->hash); + oid_array_append(data, oid); return 0; } - void check_for_new_submodule_commits(unsigned char new_sha1[20]) + void check_for_new_submodule_commits(struct object_id *oid) { if (!initialized_fetch_ref_tips) { for_each_ref(add_sha1_to_array, &ref_tips_before_fetch); initialized_fetch_ref_tips = 1; } - sha1_array_append(&ref_tips_after_fetch, new_sha1); + oid_array_append(&ref_tips_after_fetch, oid); } - static int add_sha1_to_argv(const unsigned char sha1[20], void *data) + static int add_oid_to_argv(const struct object_id *oid, void *data) { - argv_array_push(data, sha1_to_hex(sha1)); + argv_array_push(data, oid_to_hex(oid)); return 0; } @@@ -920,11 -849,11 +920,11 @@@ static void calculate_changed_submodule init_revisions(&rev, NULL); argv_array_push(&argv, "--"); /* argv[0] program name */ - sha1_array_for_each_unique(&ref_tips_after_fetch, - add_sha1_to_argv, &argv); + oid_array_for_each_unique(&ref_tips_after_fetch, + add_oid_to_argv, &argv); argv_array_push(&argv, "--not"); - sha1_array_for_each_unique(&ref_tips_before_fetch, - add_sha1_to_argv, &argv); + oid_array_for_each_unique(&ref_tips_before_fetch, + add_oid_to_argv, &argv); setup_revisions(argv.argc, argv.argv, &rev, NULL); if (prepare_revision_walk(&rev)) die("revision walk setup failed"); @@@ -950,8 -879,8 +950,8 @@@ } argv_array_clear(&argv); - sha1_array_clear(&ref_tips_before_fetch); - sha1_array_clear(&ref_tips_after_fetch); + oid_array_clear(&ref_tips_before_fetch); + oid_array_clear(&ref_tips_after_fetch); initialized_fetch_ref_tips = 0; } @@@ -1112,78 -1041,67 +1112,78 @@@ out unsigned is_submodule_modified(const char *path, int ignore_untracked) { - ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; - const char *argv[] = { - "status", - "--porcelain", - NULL, - NULL, - }; struct strbuf buf = STRBUF_INIT; + FILE *fp; unsigned dirty_submodule = 0; - const char *line, *next_line; const char *git_dir; + int ignore_cp_exit_code = 0; strbuf_addf(&buf, "%s/.git", path); git_dir = read_gitfile(buf.buf); if (!git_dir) git_dir = buf.buf; - if (!is_directory(git_dir)) { + if (!is_git_directory(git_dir)) { + if (is_directory(git_dir)) + die(_("'%s' not recognized as a git repository"), git_dir); strbuf_release(&buf); /* The submodule is not checked out, so it is not modified */ return 0; - } strbuf_reset(&buf); + argv_array_pushl(&cp.args, "status", "--porcelain=2", NULL); if (ignore_untracked) - argv[2] = "-uno"; + argv_array_push(&cp.args, "-uno"); - cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; cp.out = -1; cp.dir = path; if (start_command(&cp)) - die("Could not run 'git status --porcelain' in submodule %s", path); + die("Could not run 'git status --porcelain=2' in submodule %s", path); - len = strbuf_read(&buf, cp.out, 1024); - line = buf.buf; - while (len > 2) { - if ((line[0] == '?') && (line[1] == '?')) { + fp = xfdopen(cp.out, "r"); + while (strbuf_getwholeline(&buf, fp, '\n') != EOF) { + /* regular untracked files */ + if (buf.buf[0] == '?') dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - break; - } else { - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; - if (ignore_untracked || - (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)) - break; + + if (buf.buf[0] == 'u' || + buf.buf[0] == '1' || + buf.buf[0] == '2') { + /* T = line type, XY = status, SSSS = submodule state */ + if (buf.len < strlen("T XY SSSS")) + die("BUG: invalid status --porcelain=2 line %s", + buf.buf); + + if (buf.buf[5] == 'S' && buf.buf[8] == 'U') + /* nested untracked file */ + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; + + if (buf.buf[0] == 'u' || + buf.buf[0] == '2' || + memcmp(buf.buf + 5, "S..U", 4)) + /* other change */ + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; } - next_line = strchr(line, '\n'); - if (!next_line) + + if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && + ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || + ignore_untracked)) { + /* + * We're not interested in any further information from + * the child any more, neither output nor its exit code. + */ + ignore_cp_exit_code = 1; break; - next_line++; - len -= (next_line - line); - line = next_line; + } } - close(cp.out); + fclose(fp); - if (finish_command(&cp)) - die("'git status --porcelain' failed in submodule %s", path); + if (finish_command(&cp) && !ignore_cp_exit_code) + die("'git status --porcelain=2' failed in submodule %s", path); strbuf_release(&buf); return dirty_submodule; @@@ -1285,151 -1203,6 +1285,151 @@@ out return ret; } +static const char *get_super_prefix_or_empty(void) +{ + const char *s = get_super_prefix(); + if (!s) + s = ""; + return s; +} + +static int submodule_has_dirty_index(const struct submodule *sub) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + prepare_submodule_repo_env_no_git_dir(&cp.env_array); + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "diff-index", "--quiet", + "--cached", "HEAD", NULL); + cp.no_stdin = 1; + cp.no_stdout = 1; + cp.dir = sub->path; + if (start_command(&cp)) + die("could not recurse into submodule '%s'", sub->path); + + return finish_command(&cp); +} + +static void submodule_reset_index(const char *path) +{ + struct child_process cp = CHILD_PROCESS_INIT; + prepare_submodule_repo_env_no_git_dir(&cp.env_array); + + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; + + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + get_super_prefix_or_empty(), path); + argv_array_pushl(&cp.args, "read-tree", "-u", "--reset", NULL); + + argv_array_push(&cp.args, EMPTY_TREE_SHA1_HEX); + + if (run_command(&cp)) + die("could not reset submodule index"); +} + +/** + * Moves a submodule at a given path from a given head to another new head. + * For edge cases (a submodule coming into existence or removing a submodule) + * pass NULL for old or new respectively. + */ +int submodule_move_head(const char *path, + const char *old, + const char *new, + unsigned flags) +{ + int ret = 0; + struct child_process cp = CHILD_PROCESS_INIT; + const struct submodule *sub; + + sub = submodule_from_path(null_sha1, path); + + if (!sub) + die("BUG: could not get submodule information for '%s'", path); + + if (old && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) { + /* Check if the submodule has a dirty index. */ + if (submodule_has_dirty_index(sub)) + return error(_("submodule '%s' has dirty index"), path); + } + + if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) { + if (old) { + if (!submodule_uses_gitfile(path)) + absorb_git_dir_into_superproject("", path, + ABSORB_GITDIR_RECURSE_SUBMODULES); + } else { + struct strbuf sb = STRBUF_INIT; + strbuf_addf(&sb, "%s/modules/%s", + get_git_common_dir(), sub->name); + connect_work_tree_and_git_dir(path, sb.buf); + strbuf_release(&sb); + + /* make sure the index is clean as well */ + submodule_reset_index(path); + } + } + + prepare_submodule_repo_env_no_git_dir(&cp.env_array); + + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; + + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + get_super_prefix_or_empty(), path); + argv_array_pushl(&cp.args, "read-tree", NULL); + + if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN) + argv_array_push(&cp.args, "-n"); + else + argv_array_push(&cp.args, "-u"); + + if (flags & SUBMODULE_MOVE_HEAD_FORCE) + argv_array_push(&cp.args, "--reset"); + else + argv_array_push(&cp.args, "-m"); + + argv_array_push(&cp.args, old ? old : EMPTY_TREE_SHA1_HEX); + argv_array_push(&cp.args, new ? new : EMPTY_TREE_SHA1_HEX); + + if (run_command(&cp)) { + ret = -1; + goto out; + } + + if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) { + if (new) { + struct child_process cp1 = CHILD_PROCESS_INIT; + /* also set the HEAD accordingly */ + cp1.git_cmd = 1; + cp1.no_stdin = 1; + cp1.dir = path; + + argv_array_pushl(&cp1.args, "update-ref", "HEAD", + new ? new : EMPTY_TREE_SHA1_HEX, NULL); + + if (run_command(&cp1)) { + ret = -1; + goto out; + } + } else { + struct strbuf sb = STRBUF_INIT; + + strbuf_addf(&sb, "%s/.git", path); + unlink_or_warn(sb.buf); + strbuf_release(&sb); + + if (is_empty_dir(path)) + rmdir_or_warn(path); + } + } +out: + return ret; +} + static int find_first_merges(struct object_array *result, const char *path, struct commit *a, struct commit *b) { @@@ -1448,7 -1221,7 +1448,7 @@@ memset(&rev_opts, 0, sizeof(rev_opts)); /* get all revisions that merge commit a */ - snprintf(merged_revision, sizeof(merged_revision), "^%s", + xsnprintf(merged_revision, sizeof(merged_revision), "^%s", oid_to_hex(&a->object.oid)); init_revisions(&revs, NULL); rev_opts.submodule = path; @@@ -1598,6 -1371,18 +1598,6 @@@ int parallel_submodules(void return parallel_jobs; } -void prepare_submodule_repo_env(struct argv_array *out) -{ - const char * const *var; - - for (var = local_repo_env; *var; var++) { - if (strcmp(*var, CONFIG_DATA_ENVIRONMENT)) - argv_array_push(out, *var); - } - argv_array_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT, - DEFAULT_GIT_DIR_ENVIRONMENT); -} - /* * Embeds a single submodules git directory into the superprojects git dir, * non recursively. @@@ -1629,8 -1414,11 +1629,8 @@@ static void relocate_single_git_dir_int die(_("could not create directory '%s'"), new_git_dir); real_new_git_dir = real_pathdup(new_git_dir, 1); - if (!prefix) - prefix = get_super_prefix(); - fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"), - prefix ? prefix : "", path, + get_super_prefix_or_empty(), path, real_old_git_dir, real_new_git_dir); relocate_gitdir(path, real_old_git_dir, real_new_git_dir); @@@ -1657,6 -1445,8 +1657,6 @@@ void absorb_git_dir_into_superproject(c /* Not populated? */ if (!sub_git_dir) { - char *real_new_git_dir; - const char *new_git_dir; const struct submodule *sub; if (err_code == READ_GITFILE_ERR_STAT_FAILED) { @@@ -1679,8 -1469,13 +1679,8 @@@ sub = submodule_from_path(null_sha1, path); if (!sub) die(_("could not lookup name for submodule '%s'"), path); - new_git_dir = git_path("modules/%s", sub->name); - if (safe_create_leading_directories_const(new_git_dir) < 0) - die(_("could not create directory '%s'"), new_git_dir); - real_new_git_dir = real_pathdup(new_git_dir, 1); - connect_work_tree_and_git_dir(path, real_new_git_dir); - - free(real_new_git_dir); + connect_work_tree_and_git_dir(path, + git_path("modules/%s", sub->name)); } else { /* Is it already absorbed into the superprojects git dir? */ char *real_sub_git_dir = real_pathdup(sub_git_dir, 1); @@@ -1701,7 -1496,8 +1701,7 @@@ if (flags & ~ABSORB_GITDIR_RECURSE_SUBMODULES) die("BUG: we don't know how to pass the flags down?"); - if (get_super_prefix()) - strbuf_addstr(&sb, get_super_prefix()); + strbuf_addstr(&sb, get_super_prefix_or_empty()); strbuf_addstr(&sb, path); strbuf_addch(&sb, '/'); diff --combined submodule.h index 8a8bc49dc9,decca25e37..a86f757a06 --- a/submodule.h +++ b/submodule.h @@@ -3,7 -3,7 +3,7 @@@ struct diff_options; struct argv_array; - struct sha1_array; + struct oid_array; enum { RECURSE_SUBMODULES_ONLY = -5, @@@ -41,13 -41,7 +41,13 @@@ extern int submodule_config(const char 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); +/* + * Determine if a submodule has been populated at a given 'path' by checking if + * the /.git resolves to a valid git repository. + * If return_error_code is NULL, die on error. + * Otherwise the return error code is the same as of resolve_gitdir_gently. + */ +extern int is_submodule_populated_gently(const char *path, int *return_error_code); extern int parse_submodule_update_strategy(const char *value, struct submodule_update_strategy *dst); extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s); @@@ -64,15 -58,7 +64,15 @@@ extern void show_submodule_inline_diff( const char *del, const char *add, const char *reset, const struct diff_options *opt); extern void set_config_fetch_recurse_submodules(int value); +extern void set_config_update_recurse_submodules(int value); +/* Check if we want to update any submodule.*/ +extern int should_update_submodules(void); +/* + * Returns the submodule struct if the given ce entry is a submodule + * and it should be updated. Returns NULL otherwise. + */ +extern const struct submodule *submodule_from_ce(const struct cache_entry *ce); - extern void check_for_new_submodule_commits(unsigned char new_sha1[20]); + extern void check_for_new_submodule_commits(struct object_id *oid); extern int fetch_populated_submodules(const struct argv_array *options, const char *prefix, int command_line_option, int quiet, int max_parallel_jobs); @@@ -87,22 -73,15 +87,22 @@@ extern int merge_submodule(unsigned cha 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, + extern int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing); - extern int push_unpushed_submodules(struct sha1_array *commits, + extern int push_unpushed_submodules(struct oid_array *commits, const char *remotes_name, int dry_run); extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir); extern int parallel_submodules(void); +#define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0) +#define SUBMODULE_MOVE_HEAD_FORCE (1<<1) +extern int submodule_move_head(const char *path, + const char *old, + const char *new, + unsigned flags); + /* * Prepare the "env_array" parameter of a "struct child_process" for executing * a submodule by clearing any repo-specific envirionment variables, but