From: Junio C Hamano Date: Fri, 28 Dec 2018 18:40:58 +0000 (-0800) Subject: Merge branch 'sb/more-repo-in-api' into md/list-objects-filter-by-depth X-Git-Tag: v2.21.0-rc0~55^2~4 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/b9fbc04e26fcc2c7ba6dda32512b3726d31e4beb?ds=inline;hp=-c Merge branch 'sb/more-repo-in-api' into md/list-objects-filter-by-depth --- b9fbc04e26fcc2c7ba6dda32512b3726d31e4beb diff --combined builtin/fsck.c index 3c3e0f06e7,c476ac6983..967341e1d3 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@@ -19,7 -19,6 +19,7 @@@ #include "packfile.h" #include "object-store.h" #include "run-command.h" +#include "worktree.h" #define REACHABLE 0x0001 #define SEEN 0x0002 @@@ -37,6 -36,8 +37,6 @@@ static int check_strict static int keep_cache_objects; static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT; static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT; -static struct object_id head_oid; -static const char *head_points_at; static int errors_found; static int write_lost_and_found; static int verbose; @@@ -381,7 -382,8 +381,8 @@@ out if (obj->type == OBJ_TREE) free_tree_buffer((struct tree *)obj); if (obj->type == OBJ_COMMIT) - free_commit_buffer((struct commit *)obj); + free_commit_buffer(the_repository->parsed_objects, + (struct commit *)obj); return err; } @@@ -445,11 -447,7 +446,11 @@@ static int fsck_handle_reflog_ent(struc static int fsck_handle_reflog(const char *logname, const struct object_id *oid, int flag, void *cb_data) { - for_each_reflog_ent(logname, fsck_handle_reflog_ent, (void *)logname); + struct strbuf refname = STRBUF_INIT; + + strbuf_worktree_ref(cb_data, &refname, logname); + for_each_reflog_ent(refname.buf, fsck_handle_reflog_ent, refname.buf); + strbuf_release(&refname); return 0; } @@@ -487,34 -485,13 +488,34 @@@ static int fsck_handle_ref(const char * return 0; } +static int fsck_head_link(const char *head_ref_name, + const char **head_points_at, + struct object_id *head_oid); + static void get_default_heads(void) { - if (head_points_at && !is_null_oid(&head_oid)) - fsck_handle_ref("HEAD", &head_oid, 0, NULL); + struct worktree **worktrees, **p; + const char *head_points_at; + struct object_id head_oid; + for_each_rawref(fsck_handle_ref, NULL); - if (include_reflogs) - for_each_reflog(fsck_handle_reflog, NULL); + + worktrees = get_worktrees(0); + for (p = worktrees; *p; p++) { + struct worktree *wt = *p; + struct strbuf ref = STRBUF_INIT; + + strbuf_worktree_ref(wt, &ref, "HEAD"); + fsck_head_link(ref.buf, &head_points_at, &head_oid); + if (head_points_at && !is_null_oid(&head_oid)) + fsck_handle_ref(ref.buf, &head_oid, 0, NULL); + strbuf_release(&ref); + + if (include_reflogs) + refs_for_each_reflog(get_worktree_ref_store(wt), + fsck_handle_reflog, wt); + } + free_worktrees(worktrees); /* * Not having any default heads isn't really fatal, but @@@ -603,36 -580,33 +604,36 @@@ static void fsck_object_dir(const char stop_progress(&progress); } -static int fsck_head_link(void) +static int fsck_head_link(const char *head_ref_name, + const char **head_points_at, + struct object_id *head_oid) { int null_is_error = 0; if (verbose) - fprintf(stderr, "Checking HEAD link\n"); + fprintf(stderr, "Checking %s link\n", head_ref_name); - head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL); - if (!head_points_at) { + *head_points_at = resolve_ref_unsafe(head_ref_name, 0, head_oid, NULL); + if (!*head_points_at) { errors_found |= ERROR_REFS; - return error("Invalid HEAD"); + return error("Invalid %s", head_ref_name); } - if (!strcmp(head_points_at, "HEAD")) + if (!strcmp(*head_points_at, head_ref_name)) /* detached HEAD */ null_is_error = 1; - else if (!starts_with(head_points_at, "refs/heads/")) { + else if (!starts_with(*head_points_at, "refs/heads/")) { errors_found |= ERROR_REFS; - return error("HEAD points to something strange (%s)", - head_points_at); + return error("%s points to something strange (%s)", + head_ref_name, *head_points_at); } - if (is_null_oid(&head_oid)) { + if (is_null_oid(head_oid)) { if (null_is_error) { errors_found |= ERROR_REFS; - return error("HEAD: detached HEAD points at nothing"); + return error("%s: detached HEAD points at nothing", + head_ref_name); } - fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n", - head_points_at + 11); + fprintf(stderr, "notice: %s points to an unborn branch (%s)\n", + head_ref_name, *head_points_at + 11); } return 0; } @@@ -747,6 -721,7 +748,6 @@@ int cmd_fsck(int argc, const char **arg git_config(fsck_config, NULL); - fsck_head_link(); if (connectivity_only) { for_each_loose_object(mark_loose_for_connectivity, NULL, 0); for_each_packed_object(mark_packed_for_connectivity, NULL, 0); diff --combined builtin/log.c index e8e51068bd,64c2649c7c..45aa376a59 --- a/builtin/log.c +++ b/builtin/log.c @@@ -107,8 -107,6 +107,8 @@@ static int log_line_range_callback(cons { struct line_opt_callback_data *data = option->value; + BUG_ON_OPT_NEG(unset); + if (!arg) return -1; @@@ -397,7 -395,8 +397,8 @@@ static int cmd_log_walk(struct rev_inf * We may show a given commit multiple times when * walking the reflogs. */ - free_commit_buffer(commit); + free_commit_buffer(the_repository->parsed_objects, + commit); free_commit_list(commit->parents); commit->parents = NULL; } @@@ -1011,6 -1010,8 +1012,6 @@@ static void show_diffstat(struct rev_in memcpy(&opts, &rev->diffopt, sizeof(opts)); opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; - opts.stat_width = MAIL_DEFAULT_WRAP; - diff_setup_done(&opts); diff_tree_oid(get_commit_tree_oid(origin), @@@ -1094,18 -1095,9 +1095,18 @@@ static void make_cover_letter(struct re } if (rev->rdiff1) { + /* + * Pass minimum required diff-options to range-diff; others + * can be added later if deemed desirable. + */ + struct diff_options opts; + diff_setup(&opts); + opts.file = rev->diffopt.file; + opts.use_color = rev->diffopt.use_color; + diff_setup_done(&opts); fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title); show_range_diff(rev->rdiff1, rev->rdiff2, - rev->creation_factor, 1, &rev->diffopt); + rev->creation_factor, 1, &opts); } } @@@ -1160,8 -1152,6 +1161,8 @@@ static int keep_subject = 0 static int keep_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); ((struct rev_info *)opt->value)->total = -1; keep_subject = 1; return 0; @@@ -1172,7 -1162,6 +1173,7 @@@ static int subject_prefix = 0 static int subject_prefix_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); subject_prefix = 1; ((struct rev_info *)opt->value)->subject_prefix = arg; return 0; @@@ -1180,8 -1169,6 +1181,8 @@@ static int rfc_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); return subject_prefix_callback(opt, "RFC PATCH", unset); } @@@ -1190,7 -1177,6 +1191,7 @@@ static int numbered_cmdline_opt = 0 static int numbered_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_ARG(arg); *(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1; if (unset) auto_number = 0; @@@ -1200,7 -1186,6 +1201,7 @@@ static int no_numbered_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); return numbered_callback(opt, arg, 1); } @@@ -1208,7 -1193,6 +1209,7 @@@ static int output_directory_callback(co int unset) { const char **dir = (const char **)opt->value; + BUG_ON_OPT_NEG(unset); if (*dir) die(_("Two output directories?")); *dir = arg; @@@ -1525,7 -1509,7 +1526,7 @@@ int cmd_format_patch(int argc, const ch PARSE_OPT_NOARG, numbered_callback }, { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL, N_("use [PATCH] even with multiple patches"), - PARSE_OPT_NOARG, no_numbered_callback }, + PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback }, OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")), OPT_BOOL(0, "stdout", &use_stdout, N_("print patches to standard out")), @@@ -1939,7 -1923,8 +1940,8 @@@ open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); - free_commit_buffer(commit); + free_commit_buffer(the_repository->parsed_objects, + commit); /* We put one extra blank line between formatted * patches and this flag is used by log-tree code diff --combined builtin/rev-list.c index 2880ed37e3,2b301fa315..3a2c0c23b6 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@@ -6,7 -6,6 +6,7 @@@ #include "list-objects.h" #include "list-objects-filter.h" #include "list-objects-filter-options.h" +#include "object.h" #include "object-store.h" #include "pack.h" #include "pack-bitmap.h" @@@ -197,7 -196,8 +197,8 @@@ static void finish_commit(struct commi free_commit_list(commit->parents); commit->parents = NULL; } - free_commit_buffer(commit); + free_commit_buffer(the_repository->parsed_objects, + commit); } static inline void finish_object__ma(struct object *obj) @@@ -210,8 -210,7 +211,8 @@@ */ switch (arg_missing_action) { case MA_ERROR: - die("missing blob object '%s'", oid_to_hex(&obj->oid)); + die("missing %s object '%s'", + type_name(obj->type), oid_to_hex(&obj->oid)); return; case MA_ALLOW_ANY: @@@ -224,8 -223,8 +225,8 @@@ case MA_ALLOW_PROMISOR: if (is_promisor_object(&obj->oid)) return; - die("unexpected missing blob object '%s'", - oid_to_hex(&obj->oid)); + die("unexpected missing %s object '%s'", + type_name(obj->type), oid_to_hex(&obj->oid)); return; default: @@@ -237,7 -236,7 +238,7 @@@ static int finish_object(struct object *obj, const char *name, void *cb_data) { struct rev_list_info *info = cb_data; - if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) { + if (!has_object_file(&obj->oid)) { finish_object__ma(obj); return 1; } @@@ -374,9 -373,7 +375,9 @@@ int cmd_rev_list(int argc, const char * 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; /* * Scan the argument list before invoking setup_revisions(), so that we diff --combined cache.h index ca36b44ee0,8864d7ec15..b7acd81d2e --- a/cache.h +++ b/cache.h @@@ -486,8 -486,6 +486,8 @@@ static inline enum object_type object_t #define INFOATTRIBUTES_FILE "info/attributes" #define ATTRIBUTE_MACRO_PREFIX "[attr]" #define GITMODULES_FILE ".gitmodules" +#define GITMODULES_INDEX ":.gitmodules" +#define GITMODULES_HEAD "HEAD:.gitmodules" #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF" #define GIT_NOTES_DEFAULT_REF "refs/notes/commits" #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF" @@@ -661,9 -659,6 +661,9 @@@ extern int daemonize(void) /* Initialize and use the cache information */ struct lock_file; extern int read_index(struct index_state *); +extern void preload_index(struct index_state *index, + const struct pathspec *pathspec, + unsigned int refresh_flags); extern int read_index_preload(struct index_state *, const struct pathspec *pathspec, unsigned int refresh_flags); @@@ -788,8 -783,6 +788,8 @@@ extern void *read_blob_data_from_index( #define CE_MATCH_REFRESH 0x10 /* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */ #define CE_MATCH_IGNORE_FSMONITOR 0X20 +extern int is_racy_timestamp(const struct index_state *istate, + const struct cache_entry *ce); extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); @@@ -911,6 -904,14 +911,6 @@@ int use_optional_locks(void) extern char comment_line_char; extern int auto_comment_line_char; -/* Windows only */ -enum hide_dotfiles_type { - HIDE_DOTFILES_FALSE = 0, - HIDE_DOTFILES_TRUE, - HIDE_DOTFILES_DOTGITONLY -}; -extern enum hide_dotfiles_type hide_dotfiles; - enum log_refs_config { LOG_REFS_UNSET = -1, LOG_REFS_NONE = 0, @@@ -959,13 -960,11 +959,13 @@@ extern int grafts_replace_parents extern int repository_format_precious_objects; extern char *repository_format_partial_clone; extern const char *core_partial_clone_filter_default; +extern int repository_format_worktree_config; struct repository_format { int version; int precious_objects; char *partial_clone; /* value of extensions.partialclone */ + int worktree_config; int is_bare; int hash_algo; char *work_tree; @@@ -1034,6 -1033,8 +1034,8 @@@ static inline int hashcmp(const unsigne * * This will need to be extended or ripped out when we learn about * hashes of different sizes. + * + * When ripping this out, see TODO in test-repository.c. */ if (the_hash_algo->rawsz != 20) BUG("hash size not yet supported by hashcmp"); @@@ -1486,7 -1487,6 +1488,7 @@@ extern const char *fmt_name(const char extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); +extern const char *git_sequence_editor(void); extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); diff --combined commit-reach.c index d5a39defd3,8715008fef..3ea174788a --- a/commit-reach.c +++ b/commit-reach.c @@@ -30,7 -30,8 +30,8 @@@ static int queue_has_nonstale(struct pr } /* all input commits in one and twos[] must have been parsed! */ - static struct commit_list *paint_down_to_common(struct commit *one, int n, + static struct commit_list *paint_down_to_common(struct repository *r, + struct commit *one, int n, struct commit **twos, int min_generation) { @@@ -83,7 -84,7 +84,7 @@@ parents = parents->next; if ((p->object.flags & flags) == flags) continue; - if (parse_commit(p)) + if (repo_parse_commit(r, p)) return NULL; p->object.flags |= flags; prio_queue_put(&queue, p); @@@ -94,7 -95,9 +95,9 @@@ return result; } - static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos) + static struct commit_list *merge_bases_many(struct repository *r, + struct commit *one, int n, + struct commit **twos) { struct commit_list *list = NULL; struct commit_list *result = NULL; @@@ -109,14 -112,14 +112,14 @@@ return commit_list_insert(one, &result); } - if (parse_commit(one)) + if (repo_parse_commit(r, one)) return NULL; for (i = 0; i < n; i++) { - if (parse_commit(twos[i])) + if (repo_parse_commit(r, twos[i])) return NULL; } - list = paint_down_to_common(one, n, twos, 0); + list = paint_down_to_common(r, one, n, twos, 0); while (list) { struct commit *commit = pop_commit(&list); @@@ -153,7 -156,7 +156,7 @@@ struct commit_list *get_octopus_merge_b return ret; } - static int remove_redundant(struct commit **array, int cnt) + static int remove_redundant(struct repository *r, struct commit **array, int cnt) { /* * Some commit in the array may be an ancestor of @@@ -171,7 -174,7 +174,7 @@@ ALLOC_ARRAY(filled_index, cnt - 1); for (i = 0; i < cnt; i++) - parse_commit(array[i]); + repo_parse_commit(r, array[i]); for (i = 0; i < cnt; i++) { struct commit_list *common; uint32_t min_generation = array[i]->generation; @@@ -187,8 -190,8 +190,8 @@@ if (array[j]->generation < min_generation) min_generation = array[j]->generation; } - common = paint_down_to_common(array[i], filled, work, - min_generation); + common = paint_down_to_common(r, array[i], filled, + work, min_generation); if (array[i]->object.flags & PARENT2) redundant[i] = 1; for (j = 0; j < filled; j++) @@@ -213,7 -216,8 +216,8 @@@ return filled; } - static struct commit_list *get_merge_bases_many_0(struct commit *one, + static struct commit_list *get_merge_bases_many_0(struct repository *r, + struct commit *one, int n, struct commit **twos, int cleanup) @@@ -223,7 -227,7 +227,7 @@@ struct commit_list *result; int cnt, i; - result = merge_bases_many(one, n, twos); + result = merge_bases_many(r, one, n, twos); for (i = 0; i < n; i++) { if (one == twos[i]) return result; @@@ -246,7 -250,7 +250,7 @@@ clear_commit_marks(one, all_flags); clear_commit_marks_many(n, twos, all_flags); - cnt = remove_redundant(rslt, cnt); + cnt = remove_redundant(r, rslt, cnt); result = NULL; for (i = 0; i < cnt; i++) commit_list_insert_by_date(rslt[i], &result); @@@ -254,23 -258,27 +258,27 @@@ return result; } - struct commit_list *get_merge_bases_many(struct commit *one, - int n, - struct commit **twos) + struct commit_list *repo_get_merge_bases_many(struct repository *r, + struct commit *one, + int n, + struct commit **twos) { - return get_merge_bases_many_0(one, n, twos, 1); + return get_merge_bases_many_0(r, one, n, twos, 1); } - struct commit_list *get_merge_bases_many_dirty(struct commit *one, - int n, - struct commit **twos) + struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r, + struct commit *one, + int n, + struct commit **twos) { - return get_merge_bases_many_0(one, n, twos, 0); + return get_merge_bases_many_0(r, one, n, twos, 0); } - struct commit_list *get_merge_bases(struct commit *one, struct commit *two) + struct commit_list *repo_get_merge_bases(struct repository *r, + struct commit *one, + struct commit *two) { - return get_merge_bases_many_0(one, 1, &two, 1); + return get_merge_bases_many_0(r, one, 1, &two, 1); } /* @@@ -304,16 -312,17 +312,17 @@@ int is_descendant_of(struct commit *com /* * Is "commit" an ancestor of one of the "references"? */ - int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference) + int repo_in_merge_bases_many(struct repository *r, struct commit *commit, + int nr_reference, struct commit **reference) { struct commit_list *bases; int ret = 0, i; uint32_t min_generation = GENERATION_NUMBER_INFINITY; - if (parse_commit(commit)) + if (repo_parse_commit(r, commit)) return ret; for (i = 0; i < nr_reference; i++) { - if (parse_commit(reference[i])) + if (repo_parse_commit(r, reference[i])) return ret; if (reference[i]->generation < min_generation) min_generation = reference[i]->generation; @@@ -322,7 -331,9 +331,9 @@@ if (commit->generation > min_generation) return ret; - bases = paint_down_to_common(commit, nr_reference, reference, commit->generation); + bases = paint_down_to_common(r, commit, + nr_reference, reference, + commit->generation); if (commit->object.flags & PARENT2) ret = 1; clear_commit_marks(commit, all_flags); @@@ -334,9 -345,11 +345,11 @@@ /* * Is "commit" an ancestor of (i.e. reachable from) the "reference"? */ - int in_merge_bases(struct commit *commit, struct commit *reference) + int repo_in_merge_bases(struct repository *r, + struct commit *commit, + struct commit *reference) { - return in_merge_bases_many(commit, 1, &reference); + return repo_in_merge_bases_many(r, commit, 1, &reference); } struct commit_list *reduce_heads(struct commit_list *heads) @@@ -365,7 -378,7 +378,7 @@@ p->item->object.flags &= ~STALE; } } - num_head = remove_redundant(array, num_head); + num_head = remove_redundant(the_repository, array, num_head); for (i = 0; i < num_head; i++) tail = &commit_list_insert(array[i], tail)->next; free(array); @@@ -529,8 -542,8 +542,8 @@@ int commit_contains(struct ref_filter * static int compare_commits_by_gen(const void *_a, const void *_b) { - const struct commit *a = (const struct commit *)_a; - const struct commit *b = (const struct commit *)_b; + const struct commit *a = *(const struct commit * const *)_a; + const struct commit *b = *(const struct commit * const *)_b; if (a->generation < b->generation) return -1; @@@ -593,10 -606,8 +606,10 @@@ int can_all_from_reach_with_flag(struc while (stack) { struct commit_list *parent; - if (stack->item->object.flags & with_flag) { + if (stack->item->object.flags & (with_flag | RESULT)) { pop_commit(&stack); + if (stack) + stack->item->object.flags |= RESULT; continue; } @@@ -690,72 -701,3 +703,72 @@@ int can_all_from_reach(struct commit_li object_array_clear(&from_objs); return result; } + +struct commit_list *get_reachable_subset(struct commit **from, int nr_from, + struct commit **to, int nr_to, + unsigned int reachable_flag) +{ + struct commit **item; + struct commit *current; + struct commit_list *found_commits = NULL; + struct commit **to_last = to + nr_to; + struct commit **from_last = from + nr_from; + uint32_t min_generation = GENERATION_NUMBER_INFINITY; + int num_to_find = 0; + + struct prio_queue queue = { compare_commits_by_gen_then_commit_date }; + + for (item = to; item < to_last; item++) { + struct commit *c = *item; + + parse_commit(c); + if (c->generation < min_generation) + min_generation = c->generation; + + if (!(c->object.flags & PARENT1)) { + c->object.flags |= PARENT1; + num_to_find++; + } + } + + for (item = from; item < from_last; item++) { + struct commit *c = *item; + if (!(c->object.flags & PARENT2)) { + c->object.flags |= PARENT2; + parse_commit(c); + + prio_queue_put(&queue, *item); + } + } + + while (num_to_find && (current = prio_queue_get(&queue)) != NULL) { + struct commit_list *parents; + + if (current->object.flags & PARENT1) { + current->object.flags &= ~PARENT1; + current->object.flags |= reachable_flag; + commit_list_insert(current, &found_commits); + num_to_find--; + } + + for (parents = current->parents; parents; parents = parents->next) { + struct commit *p = parents->item; + + parse_commit(p); + + if (p->generation < min_generation) + continue; + + if (p->object.flags & PARENT2) + continue; + + p->object.flags |= PARENT2; + prio_queue_put(&queue, p); + } + } + + clear_commit_marks_many(nr_to, to, PARENT1); + clear_commit_marks_many(nr_from, from, PARENT2); + + return found_commits; +} diff --combined commit-reach.h index fb8082a2ec,a0d4a29d25..99a43e8b64 --- a/commit-reach.h +++ b/commit-reach.h @@@ -1,29 -1,42 +1,43 @@@ -#ifndef __COMMIT_REACH_H__ -#define __COMMIT_REACH_H__ +#ifndef COMMIT_REACH_H +#define COMMIT_REACH_H +#include "commit.h" #include "commit-slab.h" -struct commit; struct commit_list; -struct contains_cache; struct ref_filter; +struct object_id; +struct object_array; - struct commit_list *get_merge_bases_many(struct commit *one, - int n, - struct commit **twos); - struct commit_list *get_merge_bases_many_dirty(struct commit *one, - int n, - struct commit **twos); - struct commit_list *get_merge_bases(struct commit *one, struct commit *two); - struct commit_list *get_octopus_merge_bases(struct commit_list *in); - + struct commit_list *repo_get_merge_bases(struct repository *r, + struct commit *rev1, + struct commit *rev2); + struct commit_list *repo_get_merge_bases_many(struct repository *r, + struct commit *one, int n, + struct commit **twos); /* To be used only when object flags after this call no longer matter */ - struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos); + struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r, + struct commit *one, int n, + struct commit **twos); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define get_merge_bases(r1, r2) repo_get_merge_bases(the_repository, r1, r2) + #define get_merge_bases_many(one, n, two) repo_get_merge_bases_many(the_repository, one, n, two) + #define get_merge_bases_many_dirty(one, n, twos) repo_get_merge_bases_many_dirty(the_repository, one, n, twos) + #endif + + struct commit_list *get_octopus_merge_bases(struct commit_list *in); int is_descendant_of(struct commit *commit, struct commit_list *with_commit); - int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference); - int in_merge_bases(struct commit *commit, struct commit *reference); + int repo_in_merge_bases(struct repository *r, + struct commit *commit, + struct commit *reference); + int repo_in_merge_bases_many(struct repository *r, + struct commit *commit, + int nr_reference, struct commit **reference); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define in_merge_bases(c1, c2) repo_in_merge_bases(the_repository, c1, c2) + #define in_merge_bases_many(c1, n, cs) repo_in_merge_bases_many(the_repository, c1, n, cs) + #endif /* * Takes a list of commits and returns a new list where those @@@ -75,17 -88,4 +89,17 @@@ int can_all_from_reach_with_flag(struc int can_all_from_reach(struct commit_list *from, struct commit_list *to, int commit_date_cutoff); + +/* + * Return a list of commits containing the commits in the 'to' array + * that are reachable from at least one commit in the 'from' array. + * Also add the given 'flag' to each of the commits in the returned list. + * + * This method uses the PARENT1 and PARENT2 flags during its operation, + * so be sure these flags are not set before calling the method. + */ +struct commit_list *get_reachable_subset(struct commit **from, int nr_from, + struct commit **to, int nr_to, + unsigned int reachable_flag); + #endif diff --combined commit.c index d13a7bc374,4fe74aa4bc..a5333c7ac6 --- a/commit.c +++ b/commit.c @@@ -17,8 -17,6 +17,8 @@@ #include "sha1-lookup.h" #include "wt-status.h" #include "advice.h" +#include "refs.h" +#include "commit-reach.h" static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); @@@ -299,13 -297,15 +299,15 @@@ const void *get_cached_commit_buffer(st return v->buffer; } - const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep) + const void *repo_get_commit_buffer(struct repository *r, + const struct commit *commit, + unsigned long *sizep) { - const void *ret = get_cached_commit_buffer(the_repository, commit, sizep); + const void *ret = get_cached_commit_buffer(r, commit, sizep); if (!ret) { enum object_type type; unsigned long size; - ret = read_object_file(&commit->object.oid, &type, &size); + ret = repo_read_object_file(r, &commit->object.oid, &type, &size); if (!ret) die("cannot read commit object %s", oid_to_hex(&commit->object.oid)); @@@ -318,18 -318,20 +320,20 @@@ return ret; } - void unuse_commit_buffer(const struct commit *commit, const void *buffer) + void repo_unuse_commit_buffer(struct repository *r, + const struct commit *commit, + const void *buffer) { struct commit_buffer *v = buffer_slab_peek( - the_repository->parsed_objects->buffer_slab, commit); + r->parsed_objects->buffer_slab, commit); if (!(v && v->buffer == buffer)) free((void *)buffer); } - void free_commit_buffer(struct commit *commit) + void free_commit_buffer(struct parsed_object_pool *pool, struct commit *commit) { struct commit_buffer *v = buffer_slab_peek( - the_repository->parsed_objects->buffer_slab, commit); + pool->buffer_slab, commit); if (v) { FREE_AND_NULL(v->buffer); v->size = 0; @@@ -352,13 -354,12 +356,12 @@@ struct object_id *get_commit_tree_oid(c return &get_commit_tree(commit)->object.oid; } - void release_commit_memory(struct commit *c) + void release_commit_memory(struct parsed_object_pool *pool, struct commit *c) { c->maybe_tree = NULL; c->index = 0; - free_commit_buffer(c); + free_commit_buffer(pool, c); free_commit_list(c->parents); - /* TODO: what about commit->util? */ c->object.parsed = 0; } @@@ -445,7 -446,10 +448,10 @@@ int parse_commit_buffer(struct reposito return 0; } - int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph) + int repo_parse_commit_internal(struct repository *r, + struct commit *item, + int quiet_on_missing, + int use_commit_graph) { enum object_type type; void *buffer; @@@ -456,9 -460,9 +462,9 @@@ return -1; if (item->object.parsed) return 0; - if (use_commit_graph && parse_commit_in_graph(the_repository, item)) + if (use_commit_graph && parse_commit_in_graph(r, item)) return 0; - buffer = read_object_file(&item->object.oid, &type, &size); + buffer = repo_read_object_file(r, &item->object.oid, &type, &size); if (!buffer) return quiet_on_missing ? -1 : error("Could not read %s", @@@ -469,18 -473,19 +475,19 @@@ oid_to_hex(&item->object.oid)); } - ret = parse_commit_buffer(the_repository, item, buffer, size, 0); + ret = parse_commit_buffer(r, item, buffer, size, 0); if (save_commit_buffer && !ret) { - set_commit_buffer(the_repository, item, buffer, size); + set_commit_buffer(r, item, buffer, size); return 0; } free(buffer); return ret; } - int parse_commit_gently(struct commit *item, int quiet_on_missing) + int repo_parse_commit_gently(struct repository *r, + struct commit *item, int quiet_on_missing) { - return parse_commit_internal(item, quiet_on_missing, 1); + return repo_parse_commit_internal(r, item, quiet_on_missing, 1); } void parse_commit_or_die(struct commit *item) @@@ -657,10 -662,11 +664,10 @@@ struct commit *pop_commit(struct commit /* count number of children that have not been emitted */ define_commit_slab(indegree_slab, int); -/* record author-date for each commit object */ define_commit_slab(author_date_slab, timestamp_t); -static void record_author_date(struct author_date_slab *author_date, - struct commit *commit) +void record_author_date(struct author_date_slab *author_date, + struct commit *commit) { const char *buffer = get_commit_buffer(commit, NULL); struct ident_split ident; @@@ -685,8 -691,8 +692,8 @@@ fail_exit unuse_commit_buffer(commit, buffer); } -static int compare_commits_by_author_date(const void *a_, const void *b_, - void *cb_data) +int compare_commits_by_author_date(const void *a_, const void *b_, + void *cb_data) { const struct commit *a = a_, *b = b_; struct author_date_slab *author_date = cb_data; @@@ -844,86 -850,6 +851,86 @@@ void sort_in_topological_order(struct c clear_author_date_slab(&author_date); } +struct rev_collect { + struct commit **commit; + int nr; + int alloc; + unsigned int initial : 1; +}; + +static void add_one_commit(struct object_id *oid, struct rev_collect *revs) +{ + struct commit *commit; + + if (is_null_oid(oid)) + return; + + commit = lookup_commit(the_repository, oid); + if (!commit || + (commit->object.flags & TMP_MARK) || + parse_commit(commit)) + return; + + ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc); + revs->commit[revs->nr++] = commit; + commit->object.flags |= TMP_MARK; +} + +static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid, + const char *ident, timestamp_t timestamp, + int tz, const char *message, void *cbdata) +{ + struct rev_collect *revs = cbdata; + + if (revs->initial) { + revs->initial = 0; + add_one_commit(ooid, revs); + } + add_one_commit(noid, revs); + return 0; +} + +struct commit *get_fork_point(const char *refname, struct commit *commit) +{ + struct object_id oid; + struct rev_collect revs; + struct commit_list *bases; + int i; + struct commit *ret = NULL; + + memset(&revs, 0, sizeof(revs)); + revs.initial = 1; + for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); + + if (!revs.nr && !get_oid(refname, &oid)) + add_one_commit(&oid, &revs); + + for (i = 0; i < revs.nr; i++) + revs.commit[i]->object.flags &= ~TMP_MARK; + + bases = get_merge_bases_many(commit, revs.nr, revs.commit); + + /* + * There should be one and only one merge base, when we found + * a common ancestor among reflog entries. + */ + if (!bases || bases->next) + goto cleanup_return; + + /* And the found one must be one of the reflog entries */ + for (i = 0; i < revs.nr; i++) + if (&bases->item->object == &revs.commit[i]->object) + break; /* found */ + if (revs.nr <= i) + goto cleanup_return; + + ret = bases->item; + +cleanup_return: + free_commit_list(bases); + return ret; +} + static const char gpg_sig_header[] = "gpgsig"; static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1; @@@ -1099,33 -1025,7 +1106,33 @@@ int check_commit_signature(const struc return ret; } +void verify_merge_signature(struct commit *commit, int verbosity) +{ + char hex[GIT_MAX_HEXSZ + 1]; + struct signature_check signature_check; + memset(&signature_check, 0, sizeof(signature_check)); + + check_commit_signature(commit, &signature_check); + find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV); + switch (signature_check.result) { + case 'G': + break; + case 'U': + die(_("Commit %s has an untrusted GPG signature, " + "allegedly by %s."), hex, signature_check.signer); + case 'B': + die(_("Commit %s has a bad GPG signature " + "allegedly by %s."), hex, signature_check.signer); + default: /* 'N' */ + die(_("Commit %s does not have a GPG signature."), hex); + } + if (verbosity >= 0 && signature_check.result == 'G') + printf(_("Commit %s has a good GPG signature by %s\n"), + hex, signature_check.signer); + + signature_check_clear(&signature_check); +} void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail) diff --combined commit.h index 98664536cb,d2779a23f6..42728c2906 --- a/commit.h +++ b/commit.h @@@ -8,7 -8,6 +8,7 @@@ #include "gpg-interface.h" #include "string-list.h" #include "pretty.h" +#include "commit-slab.h" #define COMMIT_NOT_FROM_GRAPH 0xFFFFFFFF #define GENERATION_NUMBER_INFINITY 0xFFFFFFFF @@@ -80,12 -79,21 +80,21 @@@ struct commit *lookup_commit_reference_ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name); int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph); - int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph); - int parse_commit_gently(struct commit *item, int quiet_on_missing); - static inline int parse_commit(struct commit *item) + int repo_parse_commit_internal(struct repository *r, struct commit *item, + int quiet_on_missing, int use_commit_graph); + int repo_parse_commit_gently(struct repository *r, + struct commit *item, + int quiet_on_missing); + static inline int repo_parse_commit(struct repository *r, struct commit *item) { - return parse_commit_gently(item, 0); + return repo_parse_commit_gently(r, item, 0); } + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define parse_commit_internal(item, quiet, use) repo_parse_commit_internal(the_repository, item, quiet, use) + #define parse_commit_gently(item, quiet) repo_parse_commit_gently(the_repository, item, quiet) + #define parse_commit(item) repo_parse_commit(the_repository, item) + #endif + void parse_commit_or_die(struct commit *item); struct buffer_slab; @@@ -109,7 -117,12 +118,12 @@@ const void *get_cached_commit_buffer(st * from disk. The resulting memory should not be modified, and must be given * to unuse_commit_buffer when the caller is done. */ - const void *get_commit_buffer(const struct commit *, unsigned long *size); + const void *repo_get_commit_buffer(struct repository *r, + const struct commit *, + unsigned long *size); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define get_commit_buffer(c, s) repo_get_commit_buffer(the_repository, c, s) + #endif /* * Tell the commit subsytem that we are done with a particular commit buffer. @@@ -117,12 -130,17 +131,17 @@@ * from an earlier call to get_commit_buffer. The buffer may or may not be * freed by this call; callers should not access the memory afterwards. */ - void unuse_commit_buffer(const struct commit *, const void *buffer); + void repo_unuse_commit_buffer(struct repository *r, + const struct commit *, + const void *buffer); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define unuse_commit_buffer(c, b) repo_unuse_commit_buffer(the_repository, c, b) + #endif /* * Free any cached object buffer associated with the commit. */ - void free_commit_buffer(struct commit *); + void free_commit_buffer(struct parsed_object_pool *pool, struct commit *); struct tree *get_commit_tree(const struct commit *); struct object_id *get_commit_tree_oid(const struct commit *); @@@ -131,7 -149,7 +150,7 @@@ * Release memory related to a commit, including the parent list and * any cached object buffer. */ - void release_commit_memory(struct commit *c); + void release_commit_memory(struct parsed_object_pool *pool, struct commit *c); /* * Disassociate any cached object buffer from the commit, but do not free it. @@@ -162,6 -180,14 +181,14 @@@ extern int has_non_ascii(const char *te extern const char *logmsg_reencode(const struct commit *commit, char **commit_encoding, const char *output_encoding); + const char *repo_logmsg_reencode(struct repository *r, + const struct commit *commit, + char **commit_encoding, + const char *output_encoding); + #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS + #define logmsg_reencode(c, enc, out) repo_logmsg_reencode(the_repository, c, enc, out) + #endif + extern const char *skip_blank_lines(const char *msg); /** Removes the first commit from a list sorted by date, and adds all @@@ -206,8 -232,6 +233,8 @@@ int register_commit_graft(struct reposi void prepare_commit_graft(struct repository *r); struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid); +struct commit *get_fork_point(const char *refname, struct commit *commit); + /* largest positive number a signed 32-bit integer can contain */ #define INFINITE_DEPTH 0x7fffffff @@@ -252,9 -276,7 +279,9 @@@ extern void assign_shallow_commits_to_r uint32_t **used, int *ref_status); extern int delayed_reachability_test(struct shallow_info *si, int c); -extern void prune_shallow(int show_only); +#define PRUNE_SHOW_ONLY 1 +#define PRUNE_QUICK 2 +extern void prune_shallow(unsigned options); extern struct trace_key trace_shallow; extern int interactive_add(int argc, const char **argv, const char *prefix, int patch); @@@ -334,20 -356,6 +361,20 @@@ extern int remove_signature(struct strb */ extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc); +/* record author-date for each commit object */ +struct author_date_slab; +void record_author_date(struct author_date_slab *author_date, + struct commit *commit); + +int compare_commits_by_author_date(const void *a_, const void *b_, void *unused); + +/* + * Verify a single commit with check_commit_signature() and die() if it is not + * a good signature. This isn't really suitable for general use, but is a + * helper to implement consistent logic for pull/merge --verify-signatures. + */ +void verify_merge_signature(struct commit *commit, int verbose); + int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused); int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused); diff --combined packfile.c index d1e6683ffe,bc2e0f5043..570adfc3c6 --- a/packfile.c +++ b/packfile.c @@@ -80,8 -80,10 +80,8 @@@ void pack_report(void static int check_packed_git_idx(const char *path, struct packed_git *p) { void *idx_map; - struct pack_idx_header *hdr; size_t idx_size; - uint32_t version, nr, i, *index; - int fd = git_open(path); + int fd = git_open(path), ret; struct stat st; const unsigned int hashsz = the_hash_algo->rawsz; @@@ -99,32 -101,16 +99,32 @@@ idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - hdr = idx_map; + ret = load_idx(path, hashsz, idx_map, idx_size, p); + + if (ret) + munmap(idx_map, idx_size); + + return ret; +} + +int load_idx(const char *path, const unsigned int hashsz, void *idx_map, + size_t idx_size, struct packed_git *p) +{ + struct pack_idx_header *hdr = idx_map; + uint32_t version, nr, i, *index; + + if (idx_size < 4 * 256 + hashsz + hashsz) + return error("index file %s is too small", path); + if (idx_map == NULL) + return error("empty data"); + if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) { version = ntohl(hdr->idx_version); - if (version < 2 || version > 2) { - munmap(idx_map, idx_size); + if (version < 2 || version > 2) return error("index file %s is version %"PRIu32 " and is not supported by this binary" " (try upgrading GIT to a newer version)", path, version); - } } else version = 1; @@@ -134,8 -120,10 +134,8 @@@ index += 2; /* skip index header */ for (i = 0; i < 256; i++) { uint32_t n = ntohl(index[i]); - if (n < nr) { - munmap(idx_map, idx_size); + if (n < nr) return error("non-monotonic index %s", path); - } nr = n; } @@@ -147,8 -135,10 +147,8 @@@ * - hash of the packfile * - file checksum */ - if (idx_size != 4*256 + nr * (hashsz + 4) + hashsz + hashsz) { - munmap(idx_map, idx_size); + if (idx_size != 4 * 256 + nr * (hashsz + 4) + hashsz + hashsz) return error("wrong index v1 file size in %s", path); - } } else if (version == 2) { /* * Minimum size: @@@ -167,16 -157,20 +167,16 @@@ unsigned long max_size = min_size; if (nr) max_size += (nr - 1)*8; - if (idx_size < min_size || idx_size > max_size) { - munmap(idx_map, idx_size); + if (idx_size < min_size || idx_size > max_size) return error("wrong index v2 file size in %s", path); - } if (idx_size != min_size && /* * make sure we can deal with large pack offsets. * 31-bit signed offset won't be enough, neither * 32-bit unsigned one will be. */ - (sizeof(off_t) <= 4)) { - munmap(idx_map, idx_size); + (sizeof(off_t) <= 4)) return error("pack too large for current definition of off_t in %s", path); - } } p->index_version = version; @@@ -345,11 -339,6 +345,11 @@@ void close_all_packs(struct raw_object_ BUG("want to close pack marked 'do-not-close'"); else close_pack(p); + + if (o->multi_pack_index) { + close_midx(o->multi_pack_index); + o->multi_pack_index = NULL; + } } /* @@@ -1132,23 -1121,23 +1132,24 @@@ int unpack_object_header(struct packed_ void mark_bad_packed_object(struct packed_git *p, const unsigned char *sha1) { unsigned i; + const unsigned hashsz = the_hash_algo->rawsz; for (i = 0; i < p->num_bad_objects; i++) - if (hasheq(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i)) + if (hasheq(sha1, p->bad_object_sha1 + hashsz * i)) return; p->bad_object_sha1 = xrealloc(p->bad_object_sha1, 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); + hashcpy(p->bad_object_sha1 + hashsz * p->num_bad_objects, sha1); p->num_bad_objects++; } - const struct packed_git *has_packed_and_bad(const unsigned char *sha1) + const struct packed_git *has_packed_and_bad(struct repository *r, + const unsigned char *sha1) { struct packed_git *p; unsigned i; - for (p = the_repository->objects->packed_git; p; p = p->next) + for (p = r->objects->packed_git; p; p = p->next) for (i = 0; i < p->num_bad_objects; i++) if (hasheq(sha1, p->bad_object_sha1 + the_hash_algo->rawsz * i)) diff --combined packfile.h index 6c4037605d,7a62d72231..d70c6d9afb --- a/packfile.h +++ b/packfile.h @@@ -146,7 -146,7 +146,7 @@@ extern int packed_object_info(struct re off_t offset, struct object_info *); extern void mark_bad_packed_object(struct packed_git *p, const unsigned char *sha1); - extern const struct packed_git *has_packed_and_bad(const unsigned char *sha1); + extern const struct packed_git *has_packed_and_bad(struct repository *r, const unsigned char *sha1); /* * Iff a pack file in the given repository contains the object named by sha1, @@@ -164,17 -164,4 +164,17 @@@ extern int has_pack_index(const unsigne */ extern int is_promisor_object(const struct object_id *oid); +/* + * Expose a function for fuzz testing. + * + * load_idx() parses a block of memory as a packfile index and puts the results + * into a struct packed_git. + * + * This function should not be used directly. It is exposed here only so that we + * have a convenient entry-point for fuzz testing. For real uses, you should + * probably use open_pack_index() or parse_pack_index() instead. + */ +extern int load_idx(const char *path, const unsigned int hashsz, void *idx_map, + size_t idx_size, struct packed_git *p); + #endif diff --combined pretty.c index b83a3ecd23,3240495308..e89b89248e --- a/pretty.c +++ b/pretty.c @@@ -595,14 -595,15 +595,15 @@@ static char *replace_encoding_header(ch return strbuf_detach(&tmp, NULL); } - const char *logmsg_reencode(const struct commit *commit, - char **commit_encoding, - const char *output_encoding) + const char *repo_logmsg_reencode(struct repository *r, + const struct commit *commit, + char **commit_encoding, + const char *output_encoding) { static const char *utf8 = "UTF-8"; const char *use_encoding; char *encoding; - const char *msg = get_commit_buffer(commit, NULL); + const char *msg = repo_get_commit_buffer(r, commit, NULL); char *out; if (!output_encoding || !*output_encoding) { @@@ -630,7 -631,7 +631,7 @@@ * the cached copy from get_commit_buffer, we need to duplicate it * to avoid munging the cached copy. */ - if (msg == get_cached_commit_buffer(the_repository, commit, NULL)) + if (msg == get_cached_commit_buffer(r, commit, NULL)) out = xstrdup(msg); else out = (char *)msg; @@@ -644,7 -645,7 +645,7 @@@ */ out = reencode_string(msg, output_encoding, use_encoding); if (out) - unuse_commit_buffer(commit, msg); + repo_unuse_commit_buffer(r, commit, msg); } /* @@@ -1256,14 -1257,6 +1257,14 @@@ static size_t format_commit_one(struct if (c->signature_check.key) strbuf_addstr(sb, c->signature_check.key); break; + case 'F': + if (c->signature_check.fingerprint) + strbuf_addstr(sb, c->signature_check.fingerprint); + break; + case 'P': + if (c->signature_check.primary_key_fingerprint) + strbuf_addstr(sb, c->signature_check.primary_key_fingerprint); + break; default: return 0; } @@@ -1515,9 -1508,10 +1516,10 @@@ void userformat_find_requirements(cons strbuf_release(&dummy); } - void format_commit_message(const struct commit *commit, - const char *format, struct strbuf *sb, - const struct pretty_print_context *pretty_ctx) + void repo_format_commit_message(struct repository *r, + const struct commit *commit, + const char *format, struct strbuf *sb, + const struct pretty_print_context *pretty_ctx) { struct format_commit_context context; const char *output_enc = pretty_ctx->output_encoding; @@@ -1531,9 -1525,9 +1533,9 @@@ * convert a commit message to UTF-8 first * as far as 'format_commit_item' assumes it in UTF-8 */ - context.message = logmsg_reencode(commit, - &context.commit_encoding, - utf8); + context.message = repo_logmsg_reencode(r, commit, + &context.commit_encoding, + utf8); strbuf_expand(sb, format, format_commit_item, &context); rewrap_message_tail(sb, &context, 0, 0, 0); @@@ -1557,7 -1551,7 +1559,7 @@@ } free(context.commit_encoding); - unuse_commit_buffer(commit, context.message); + repo_unuse_commit_buffer(r, commit, context.message); } static void pp_header(struct pretty_print_context *pp, diff --combined sha1-file.c index 5bd11c85bc,e77273ccfd..cc952864b2 --- a/sha1-file.c +++ b/sha1-file.c @@@ -833,7 -833,7 +833,7 @@@ int check_object_signature(const struc return -1; /* Generate the header */ - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(obj_type), size) + 1; + hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(obj_type), (uintmax_t)size) + 1; /* Sha1.. */ the_hash_algo->init_fn(&c); @@@ -1361,7 -1361,9 +1361,9 @@@ int oid_object_info(struct repository * return type; } - static void *read_object(const unsigned char *sha1, enum object_type *type, + static void *read_object(struct repository *r, + const unsigned char *sha1, + enum object_type *type, unsigned long *size) { struct object_id oid; @@@ -1373,7 -1375,7 +1375,7 @@@ hashcpy(oid.hash, sha1); - if (oid_object_info_extended(the_repository, &oid, &oi, 0) < 0) + if (oid_object_info_extended(r, &oid, &oi, 0) < 0) return NULL; return content; } @@@ -1401,7 -1403,8 +1403,8 @@@ int pretend_object_file(void *buf, unsi * deal with them should arrange to call read_object() and give error * messages themselves. */ - void *read_object_file_extended(const struct object_id *oid, + void *read_object_file_extended(struct repository *r, + const struct object_id *oid, enum object_type *type, unsigned long *size, int lookup_replace) @@@ -1411,10 -1414,10 +1414,10 @@@ const char *path; struct stat st; const struct object_id *repl = lookup_replace ? - lookup_replace_object(the_repository, oid) : oid; + lookup_replace_object(r, oid) : oid; errno = 0; - data = read_object(repl->hash, type, size); + data = read_object(r, repl->hash, type, size); if (data) return data; @@@ -1426,11 -1429,11 +1429,11 @@@ die(_("replacement %s not found for %s"), oid_to_hex(repl), oid_to_hex(oid)); - if (!stat_sha1_file(the_repository, repl->hash, &st, &path)) + if (!stat_sha1_file(r, repl->hash, &st, &path)) die(_("loose object %s (stored in %s) is corrupt"), oid_to_hex(repl), path); - if ((p = has_packed_and_bad(repl->hash)) != NULL) + if ((p = has_packed_and_bad(r, repl->hash)) != NULL) die(_("packed object %s (stored in %s) is corrupt"), oid_to_hex(repl), p->pack_name); @@@ -1492,7 -1495,7 +1495,7 @@@ static void write_object_file_prepare(c git_hash_ctx c; /* Generate the header */ - *hdrlen = xsnprintf(hdr, *hdrlen, "%s %lu", type, len)+1; + *hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1; /* Sha1.. */ the_hash_algo->init_fn(&c); @@@ -1755,34 -1758,37 +1758,37 @@@ int force_object_loose(const struct obj if (has_loose_object(oid)) return 0; - buf = read_object(oid->hash, &type, &len); + buf = read_object(the_repository, oid->hash, &type, &len); if (!buf) return error(_("cannot read sha1_file for %s"), oid_to_hex(oid)); - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), len) + 1; + hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1; ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime); free(buf); return ret; } - int has_sha1_file_with_flags(const unsigned char *sha1, int flags) + int repo_has_sha1_file_with_flags(struct repository *r, + const unsigned char *sha1, int flags) { struct object_id oid; if (!startup_info->have_repository) return 0; hashcpy(oid.hash, sha1); - return oid_object_info_extended(the_repository, &oid, NULL, + return oid_object_info_extended(r, &oid, NULL, flags | OBJECT_INFO_SKIP_CACHED) >= 0; } - int has_object_file(const struct object_id *oid) + int repo_has_object_file(struct repository *r, + const struct object_id *oid) { - return has_sha1_file(oid->hash); + return repo_has_sha1_file(r, oid->hash); } - int has_object_file_with_flags(const struct object_id *oid, int flags) + int repo_has_object_file_with_flags(struct repository *r, + const struct object_id *oid, int flags) { - return has_sha1_file_with_flags(oid->hash, flags); + return repo_has_sha1_file_with_flags(r, oid->hash, flags); } static void check_tree(const void *buf, size_t size) @@@ -2199,8 -2205,7 +2205,8 @@@ static int check_stream_sha1(git_zstrea * see the comment in unpack_sha1_rest for details. */ while (total_read <= size && - (status == Z_OK || status == Z_BUF_ERROR)) { + (status == Z_OK || + (status == Z_BUF_ERROR && !stream->avail_out))) { stream->next_out = buf; stream->avail_out = sizeof(buf); if (size - total_read < stream->avail_out) diff --combined streaming.c index ac7c7a22f9,c843a1230f..891f82f51a --- a/streaming.c +++ b/streaming.c @@@ -408,15 -408,6 +408,15 @@@ static read_method_decl(pack_non_delta st->z_state = z_done; break; } + + /* + * Unlike the loose object case, we do not have to worry here + * about running out of input bytes and spinning infinitely. If + * we get Z_BUF_ERROR due to too few input bytes, then we'll + * replenish them in the next use_pack() call when we loop. If + * we truly hit the end of the pack (i.e., because it's corrupt + * or truncated), then use_pack() catches that and will die(). + */ if (status != Z_OK && status != Z_BUF_ERROR) { git_inflate_end(&st->z); st->z_state = z_error; @@@ -499,7 -490,7 +499,7 @@@ static struct stream_vtbl incore_vtbl static open_method_decl(incore) { - st->u.incore.buf = read_object_file_extended(oid, type, &st->size, 0); + st->u.incore.buf = read_object_file_extended(the_repository, oid, type, &st->size, 0); st->u.incore.read_ptr = 0; st->vtbl = &incore_vtbl; diff --combined submodule.c index 6415cc5580,d9c06767a1..aa7854f3f9 --- a/submodule.c +++ b/submodule.c @@@ -51,24 -51,6 +51,24 @@@ int is_gitmodules_unmerged(const struc return 0; } +/* + * Check if the .gitmodules file is safe to write. + * + * Writing to the .gitmodules file requires that the file exists in the + * working tree or, if it doesn't, that a brand new .gitmodules file is going + * to be created (i.e. it's neither in the index nor in the current branch). + * + * It is not safe to write to .gitmodules if it's not in the working tree but + * it is in the index or in the current branch, because writing new values + * (and staging them) would blindly overwrite ALL the old content. + */ +int is_writing_gitmodules_ok(void) +{ + struct object_id oid; + return file_exists(GITMODULES_FILE) || + (get_oid(GITMODULES_INDEX, &oid) < 0 && get_oid(GITMODULES_HEAD, &oid) < 0); +} + /* * Check if the .gitmodules file has unstaged modifications. This must be * checked before allowing modifications to the .gitmodules file with the @@@ -107,7 -89,6 +107,7 @@@ int update_path_in_gitmodules(const cha { struct strbuf entry = STRBUF_INIT; const struct submodule *submodule; + int ret; if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */ return -1; @@@ -123,9 -104,14 +123,9 @@@ strbuf_addstr(&entry, "submodule."); strbuf_addstr(&entry, submodule->name); strbuf_addstr(&entry, ".path"); - if (git_config_set_in_file_gently(GITMODULES_FILE, entry.buf, newpath) < 0) { - /* Maybe the user already did that, don't error out here */ - warning(_("Could not update .gitmodules entry %s"), entry.buf); - strbuf_release(&entry); - return -1; - } + ret = config_set_in_gitmodules_file_gently(entry.buf, newpath); strbuf_release(&entry); - return 0; + return ret; } /* @@@ -457,7 -443,7 +457,7 @@@ static int prepare_submodule_summary(st return prepare_revision_walk(rev); } - static void print_submodule_summary(struct rev_info *rev, struct diff_options *o) + static void print_submodule_summary(struct repository *r, struct rev_info *rev, struct diff_options *o) { static const char format[] = " %m %s"; struct strbuf sb = STRBUF_INIT; @@@ -468,7 -454,8 +468,8 @@@ ctx.date_mode = rev->date_mode; ctx.output_encoding = get_log_output_encoding(); strbuf_setlen(&sb, 0); - format_commit_message(commit, format, &sb, &ctx); + repo_format_commit_message(r, commit, format, &sb, + &ctx); strbuf_addch(&sb, '\n'); if (commit->object.flags & SYMMETRIC_LEFT) diff_emit_submodule_del(o, sb.buf); @@@ -495,14 -482,46 +496,46 @@@ void prepare_submodule_repo_env(struct 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 - * left and right pointers. + /* + * Initialize a repository struct for a submodule based on the provided 'path'. + * + * Unlike repo_submodule_init, this tolerates submodules not present + * in .gitmodules. This function exists only to preserve historical behavior, + * + * Returns the repository struct on success, + * NULL when the submodule is not present. */ - static void show_submodule_header(struct diff_options *o, const char *path, + static struct repository *open_submodule(const char *path) + { + struct strbuf sb = STRBUF_INIT; + struct repository *out = xmalloc(sizeof(*out)); + + if (submodule_to_gitdir(&sb, path) || repo_init(out, sb.buf, NULL)) { + strbuf_release(&sb); + free(out); + return NULL; + } + + /* Mark it as a submodule */ + out->submodule_prefix = xstrdup(path); + + strbuf_release(&sb); + return out; + } + + /* + * Helper function to display the submodule header line prior to the full + * summary output. + * + * If it can locate the submodule git directory it will create a repository + * handle for the submodule and lookup both the left and right commits and + * put them into the left and right pointers. + */ + static void show_submodule_header(struct diff_options *o, + const char *path, struct object_id *one, struct object_id *two, unsigned dirty_submodule, + struct repository *sub, struct commit **left, struct commit **right, struct commit_list **merge_bases) { @@@ -521,7 -540,7 +554,7 @@@ else if (is_null_oid(two)) message = "(submodule deleted)"; - if (add_submodule_odb(path)) { + if (!sub) { if (!message) message = "(commits not present)"; goto output_header; @@@ -531,8 -550,8 +564,8 @@@ * Attempt to lookup the commit references, and determine if this is * a fast forward or fast backwards update. */ - *left = lookup_commit_reference(the_repository, one); - *right = lookup_commit_reference(the_repository, two); + *left = lookup_commit_reference(sub, one); + *right = lookup_commit_reference(sub, two); /* * Warn about missing commits in the submodule project, but only if @@@ -542,7 -561,7 +575,7 @@@ (!is_null_oid(two) && !*right)) message = "(commits not present)"; - *merge_bases = get_merge_bases(*left, *right); + *merge_bases = repo_get_merge_bases(sub, *left, *right); if (*merge_bases) { if ((*merge_bases)->item == *left) fast_forward = 1; @@@ -576,16 -595,18 +609,18 @@@ void show_submodule_summary(struct diff struct rev_info rev; struct commit *left = NULL, *right = NULL; struct commit_list *merge_bases = NULL; + struct repository *sub; + sub = open_submodule(path); show_submodule_header(o, path, one, two, dirty_submodule, - &left, &right, &merge_bases); + sub, &left, &right, &merge_bases); /* * If we don't have both a left and a right pointer, there is no * reason to try and display a summary. The header line should contain * all the information the user needs. */ - if (!left || !right) + if (!left || !right || !sub) goto out; /* Treat revision walker failure the same as missing commits */ @@@ -594,13 -615,17 +629,17 @@@ goto out; } - print_submodule_summary(&rev, o); + print_submodule_summary(sub, &rev, o); out: if (merge_bases) free_commit_list(merge_bases); clear_commit_marks(left, ~0); clear_commit_marks(right, ~0); + if (sub) { + repo_clear(sub); + free(sub); + } } void show_submodule_inline_diff(struct diff_options *o, const char *path, @@@ -612,9 -637,11 +651,11 @@@ struct commit_list *merge_bases = NULL; struct child_process cp = CHILD_PROCESS_INIT; struct strbuf sb = STRBUF_INIT; + struct repository *sub; + sub = open_submodule(path); show_submodule_header(o, path, one, two, dirty_submodule, - &left, &right, &merge_bases); + sub, &left, &right, &merge_bases); /* We need a valid left and right commit to display a difference */ if (!(left || is_null_oid(one)) || @@@ -675,6 -702,10 +716,10 @@@ done clear_commit_marks(left, ~0); if (right) clear_commit_marks(right, ~0); + if (sub) { + repo_clear(sub); + free(sub); + } } int should_update_submodules(void) @@@ -708,7 -739,6 +753,7 @@@ static struct oid_array *submodule_comm } struct collect_changed_submodules_cb_data { + struct repository *repo; struct string_list *changed; const struct object_id *commit_oid; }; @@@ -748,7 -778,7 +793,7 @@@ static void collect_changed_submodules_ if (!S_ISGITLINK(p->two->mode)) continue; - submodule = submodule_from_path(the_repository, + submodule = submodule_from_path(me->repo, commit_oid, p->two->path); if (submodule) name = submodule->name; @@@ -756,7 -786,7 +801,7 @@@ name = default_name_or_path(p->two->path); /* make sure name does not collide with existing one */ if (name) - submodule = submodule_from_name(the_repository, + submodule = submodule_from_name(me->repo, commit_oid, name); if (submodule) { warning("Submodule in commit %s at path: " @@@ -781,14 -811,14 +826,14 @@@ * have a corresponding 'struct oid_array' (in the 'util' field) which lists * what the submodule pointers were updated to during the change. */ -static void collect_changed_submodules(struct index_state *istate, +static void collect_changed_submodules(struct repository *r, struct string_list *changed, struct argv_array *argv) { struct rev_info rev; const struct commit *commit; - repo_init_revisions(the_repository, &rev, NULL); + repo_init_revisions(r, &rev, NULL); setup_revisions(argv->argc, argv->argv, &rev, NULL); if (prepare_revision_walk(&rev)) die("revision walk setup failed"); @@@ -796,11 -826,10 +841,11 @@@ while ((commit = get_revision(&rev))) { struct rev_info diff_rev; struct collect_changed_submodules_cb_data data; + data.repo = r; data.changed = changed; data.commit_oid = &commit->object.oid; - repo_init_revisions(the_repository, &diff_rev, NULL); + repo_init_revisions(r, &diff_rev, NULL); diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; diff_rev.diffopt.format_callback = collect_changed_submodules_cb; diff_rev.diffopt.format_callback_data = &data; @@@ -832,7 -861,6 +877,7 @@@ static int append_oid_to_argv(const str } struct has_commit_data { + struct repository *repo; int result; const char *path; }; @@@ -841,7 -869,7 +886,7 @@@ static int check_has_commit(const struc { struct has_commit_data *cb = data; - enum object_type type = oid_object_info(the_repository, oid, NULL); + enum object_type type = oid_object_info(cb->repo, oid, NULL); switch (type) { case OBJ_COMMIT: @@@ -859,11 -887,9 +904,11 @@@ } } -static int submodule_has_commits(const char *path, struct oid_array *commits) +static int submodule_has_commits(struct repository *r, + const char *path, + struct oid_array *commits) { - struct has_commit_data has_commit = { 1, path }; + struct has_commit_data has_commit = { r, 1, path }; /* * Perform a cheap, but incorrect check for the existence of 'commits'. @@@ -906,11 -932,9 +951,11 @@@ return has_commit.result; } -static int submodule_needs_pushing(const char *path, struct oid_array *commits) +static int submodule_needs_pushing(struct repository *r, + const char *path, + struct oid_array *commits) { - if (!submodule_has_commits(path, commits)) + if (!submodule_has_commits(r, path, commits)) /* * NOTE: We do consider it safe to return "no" here. The * correct answer would be "We do not know" instead of @@@ -952,7 -976,7 +997,7 @@@ return 0; } -int find_unpushed_submodules(struct index_state *istate, +int find_unpushed_submodules(struct repository *r, struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing) @@@ -967,14 -991,14 +1012,14 @@@ argv_array_push(&argv, "--not"); argv_array_pushf(&argv, "--remotes=%s", remotes_name); - collect_changed_submodules(istate, &submodules, &argv); + collect_changed_submodules(r, &submodules, &argv); for_each_string_list_item(name, &submodules) { struct oid_array *commits = name->util; const struct submodule *submodule; const char *path = NULL; - submodule = submodule_from_name(the_repository, &null_oid, name->string); + submodule = submodule_from_name(r, &null_oid, name->string); if (submodule) path = submodule->path; else @@@ -983,7 -1007,7 +1028,7 @@@ if (!path) continue; - if (submodule_needs_pushing(path, commits)) + if (submodule_needs_pushing(r, path, commits)) string_list_insert(needs_pushing, path); } @@@ -999,9 -1023,6 +1044,6 @@@ static int push_submodule(const char *p const struct string_list *push_options, int dry_run) { - if (add_submodule_odb(path)) - return 1; - if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) { struct child_process cp = CHILD_PROCESS_INIT; argv_array_push(&cp.args, "push"); @@@ -1068,7 -1089,7 +1110,7 @@@ static void submodule_push_check(const die("process for submodule '%s' failed", path); } -int push_unpushed_submodules(struct index_state *istate, +int push_unpushed_submodules(struct repository *r, struct oid_array *commits, const struct remote *remote, const struct refspec *rs, @@@ -1078,7 -1099,7 +1120,7 @@@ int i, ret = 1; struct string_list needs_pushing = STRING_LIST_INIT_DUP; - if (!find_unpushed_submodules(istate, commits, + if (!find_unpushed_submodules(r, commits, remote->name, &needs_pushing)) return 1; @@@ -1136,14 -1157,14 +1178,14 @@@ void check_for_new_submodule_commits(st oid_array_append(&ref_tips_after_fetch, oid); } -static void calculate_changed_submodule_paths(struct index_state *istate) +static void calculate_changed_submodule_paths(struct repository *r) { struct argv_array argv = ARGV_ARRAY_INIT; struct string_list changed_submodules = STRING_LIST_INIT_DUP; const struct string_list_item *name; /* No need to check if there are no submodules configured */ - if (!submodule_from_path(the_repository, NULL, NULL)) + if (!submodule_from_path(r, NULL, NULL)) return; argv_array_push(&argv, "--"); /* argv[0] program name */ @@@ -1157,14 -1178,14 +1199,14 @@@ * Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_names". */ - collect_changed_submodules(istate, &changed_submodules, &argv); + collect_changed_submodules(r, &changed_submodules, &argv); for_each_string_list_item(name, &changed_submodules) { struct oid_array *commits = name->util; const struct submodule *submodule; const char *path = NULL; - submodule = submodule_from_name(the_repository, &null_oid, name->string); + submodule = submodule_from_name(r, &null_oid, name->string); if (submodule) path = submodule->path; else @@@ -1173,7 -1194,7 +1215,7 @@@ if (!path) continue; - if (!submodule_has_commits(path, commits)) + if (!submodule_has_commits(r, path, commits)) string_list_append(&changed_submodule_names, name->string); } @@@ -1184,7 -1205,7 +1226,7 @@@ initialized_fetch_ref_tips = 0; } -int submodule_touches_in_range(struct index_state *istate, +int submodule_touches_in_range(struct repository *r, struct object_id *excl_oid, struct object_id *incl_oid) { @@@ -1193,7 -1214,7 +1235,7 @@@ int ret; /* No need to check if there are no submodules configured */ - if (!submodule_from_path(the_repository, NULL, NULL)) + if (!submodule_from_path(r, NULL, NULL)) return 0; argv_array_push(&args, "--"); /* args[0] program name */ @@@ -1203,7 -1224,7 +1245,7 @@@ argv_array_push(&args, oid_to_hex(excl_oid)); } - collect_changed_submodules(istate, &subs, &args); + collect_changed_submodules(r, &subs, &args); ret = subs.nr; argv_array_clear(&args); @@@ -1373,7 -1394,7 +1415,7 @@@ int fetch_populated_submodules(struct r argv_array_push(&spf.args, "--recurse-submodules-default"); /* default value, "--submodule-prefix" and its value are added later */ - calculate_changed_submodule_paths(r->index); + calculate_changed_submodule_paths(r); run_processes_parallel(max_parallel_jobs, get_next_submodule, fetch_start_failure,