static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { const char **args; int i = 0, ret; struct commit_list *j; struct strbuf buf; args = xmalloc((4 + commit_list_count(common) + commit_list_count(remoteheads)) * sizeof(char *)); strbuf_init(&buf, 0); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (j = common; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i++] = "--"; args[i++] = head_arg; for (j = remoteheads; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); i = 1; for (j = common; j; j = j->next) free((void *)args[i++]); i += 2; for (j = remoteheads; j; j = j->next) free((void *)args[i++]); free(args); return -ret; }
static int try_parent_shorthands(const char *arg) { char *dotdot; unsigned char sha1[20]; struct commit *commit; struct commit_list *parents; int parent_number; int include_rev = 0; int include_parents = 0; int exclude_parent = 0; if ((dotdot = strstr(arg, "^!"))) { include_rev = 1; if (dotdot[2]) return 0; } else if ((dotdot = strstr(arg, "^@"))) { include_parents = 1; if (dotdot[2]) return 0; } else if ((dotdot = strstr(arg, "^-"))) { include_rev = 1; exclude_parent = 1; if (dotdot[2]) { char *end; exclude_parent = strtoul(dotdot + 2, &end, 10); if (*end != '\0' || !exclude_parent) return 0; } } else return 0; *dotdot = 0; if (get_sha1_committish(arg, sha1)) { *dotdot = '^'; return 0; } commit = lookup_commit_reference(sha1); if (exclude_parent && exclude_parent > commit_list_count(commit->parents)) { *dotdot = '^'; return 0; } if (include_rev) show_rev(NORMAL, sha1, arg); for (parents = commit->parents, parent_number = 1; parents; parents = parents->next, parent_number++) { if (exclude_parent && parent_number != exclude_parent) continue; show_rev(include_parents ? NORMAL : REVERSED, parents->item->object.oid.hash, arg); } *dotdot = '^'; return 1; }
int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes) { const char **args; int i = 0, x = 0, ret; struct commit_list *j; struct strbuf buf = STRBUF_INIT; args = xmalloc((4 + xopts_nr + commit_list_count(common) + commit_list_count(remotes)) * sizeof(char *)); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (x = 0; x < xopts_nr; x++) { char *s = xmalloc(strlen(xopts[x])+2+1); strcpy(s, "--"); strcpy(s+2, xopts[x]); args[i++] = s; } for (j = common; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i++] = "--"; args[i++] = head_arg; for (j = remotes; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); i = 1; for (x = 0; x < xopts_nr; x++) free((void *)args[i++]); for (j = common; j; j = j->next) free((void *)args[i++]); i += 2; for (j = remotes; j; j = j->next) free((void *)args[i++]); free(args); discard_cache(); if (read_cache() < 0) die(_("failed to read the cache")); resolve_undo_clear(); return ret; }
static void pp_header(struct pretty_print_context *pp, const char *encoding, const struct commit *commit, const char **msg_p, struct strbuf *sb) { int parents_shown = 0; for (;;) { const char *line = *msg_p; int linelen = get_one_line(*msg_p); if (!linelen) return; *msg_p += linelen; if (linelen == 1) /* End of header */ return; if (pp->fmt == CMIT_FMT_RAW) { strbuf_add(sb, line, linelen); continue; } if (starts_with(line, "parent ")) { if (linelen != 48) die("bad parent line in commit"); continue; } if (!parents_shown) { unsigned num = commit_list_count(commit->parents); /* with enough slop */ strbuf_grow(sb, num * 50 + 20); add_merge_info(pp, sb, commit); parents_shown = 1; } /* * MEDIUM == DEFAULT shows only author with dates. * FULL shows both authors but not dates. * FULLER shows both authors and dates. */ if (starts_with(line, "author ")) { strbuf_grow(sb, linelen + 80); pp_user_info(pp, "Author", sb, line + 7, encoding); } if (starts_with(line, "committer ") && (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) { strbuf_grow(sb, linelen + 80); pp_user_info(pp, "Commit", sb, line + 10, encoding); } } }
static int fsck_commit_buffer(struct commit *commit, const char *buffer, fsck_error error_func) { unsigned char tree_sha1[20], sha1[20]; struct commit_graft *graft; unsigned parent_count, parent_line_count = 0; int err; if (!skip_prefix(buffer, "tree ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line"); if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1"); buffer += 41; while (skip_prefix(buffer, "parent ", &buffer)) { if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1"); buffer += 41; parent_line_count++; } graft = lookup_commit_graft(commit->object.sha1); parent_count = commit_list_count(commit->parents); if (graft) { if (graft->nr_parent == -1 && !parent_count) ; /* shallow commit */ else if (graft->nr_parent != parent_count) return error_func(&commit->object, FSCK_ERROR, "graft objects missing"); } else { if (parent_count != parent_line_count) return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); } if (!skip_prefix(buffer, "author ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) return err; if (!skip_prefix(buffer, "committer ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) return err; if (!commit->tree) return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1)); return 0; }
static void commit_need_pushing(struct commit *commit, struct commit_list *parent, int *needs_pushing) { const unsigned char (*parents)[20]; unsigned int i, n; struct rev_info rev; n = commit_list_count(parent); parents = xmalloc(n * sizeof(*parents)); for (i = 0; i < n; i++) { hashcpy((unsigned char *)(parents + i), parent->item->object.sha1); parent = parent->next; } init_revisions(&rev, NULL); rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = collect_submodules_from_diff; rev.diffopt.format_callback_data = needs_pushing; diff_tree_combined(commit->object.sha1, parents, n, 1, &rev); free(parents); }
static int fsck_commit_buffer(struct commit *commit, const char *buffer, unsigned long size, struct fsck_options *options) { unsigned char tree_sha1[20], sha1[20]; struct commit_graft *graft; unsigned parent_count, parent_line_count = 0, author_count; int err; if (verify_headers(buffer, size, &commit->object, options)) return -1; if (!skip_prefix(buffer, "tree ", &buffer)) return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line"); if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') { err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1"); if (err) return err; } buffer += 41; while (skip_prefix(buffer, "parent ", &buffer)) { if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') { err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1"); if (err) return err; } buffer += 41; parent_line_count++; } graft = lookup_commit_graft(commit->object.oid.hash); parent_count = commit_list_count(commit->parents); if (graft) { if (graft->nr_parent == -1 && !parent_count) ; /* shallow commit */ else if (graft->nr_parent != parent_count) { err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing"); if (err) return err; } } else { if (parent_count != parent_line_count) { err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing"); if (err) return err; } } author_count = 0; while (skip_prefix(buffer, "author ", &buffer)) { author_count++; err = fsck_ident(&buffer, &commit->object, options); if (err) return err; } if (author_count < 1) err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line"); else if (author_count > 1) err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines"); if (err) return err; if (!skip_prefix(buffer, "committer ", &buffer)) return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, options); if (err) return err; if (!commit->tree) return report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1)); return 0; }
static int try_merge_strategy(const char *strategy, struct commit_list *common, const char *head_arg) { const char **args; int i = 0, ret; struct commit_list *j; struct strbuf buf = STRBUF_INIT; int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); index_fd = hold_locked_index(lock, 1); refresh_cache(REFRESH_QUIET); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) return error("Unable to write index."); rollback_lock_file(lock); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { int clean; struct commit *result; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd; struct commit_list *reversed = NULL; struct merge_options o; if (remoteheads->next) { error("Not handling anything other than two heads merge."); return 2; } init_merge_options(&o); if (!strcmp(strategy, "subtree")) o.subtree_merge = 1; o.branch1 = head_arg; o.branch2 = remoteheads->item->util; for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); index_fd = hold_locked_index(lock, 1); clean = merge_recursive(&o, lookup_commit(head), remoteheads->item, reversed, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) die ("unable to write %s", get_index_file()); rollback_lock_file(lock); return clean ? 0 : 1; } else { args = xmalloc((4 + commit_list_count(common) + commit_list_count(remoteheads)) * sizeof(char *)); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (j = common; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i++] = "--"; args[i++] = head_arg; for (j = remoteheads; j; j = j->next) args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); args[i] = NULL; ret = run_command_v_opt(args, RUN_GIT_CMD); strbuf_release(&buf); i = 1; for (j = common; j; j = j->next) free((void *)args[i++]); i += 2; for (j = remoteheads; j; j = j->next) free((void *)args[i++]); free(args); discard_cache(); if (read_cache() < 0) die("failed to read the cache"); return ret; } }
/* * Merge the commits h1 and h2, return the resulting virtual * commit object and a flag indicating the cleanness of the merge. */ int merge_recursive(struct merge_options *o, struct commit *h1, struct commit *h2, struct commit_list *ca, struct commit **result) { struct commit_list *iter; struct commit *merged_common_ancestors; struct tree *mrtree = mrtree; int clean; if (show(o, 4)) { output(o, 4, "Merging:"); output_commit_title(o, h1); output_commit_title(o, h2); } if (!ca) { ca = get_merge_bases(h1, h2, 1); ca = reverse_commit_list(ca); } if (show(o, 5)) { output(o, 5, "found %u common ancestor(s):", commit_list_count(ca)); for (iter = ca; iter; iter = iter->next) output_commit_title(o, iter->item); } merged_common_ancestors = pop_commit(&ca); if (merged_common_ancestors == NULL) { /* if there is no common ancestor, make an empty tree */ struct tree *tree = xcalloc(1, sizeof(struct tree)); tree->object.parsed = 1; tree->object.type = OBJ_TREE; pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } for (iter = ca; iter; iter = iter->next) { const char *saved_b1, *saved_b2; o->call_depth++; /* * When the merge fails, the result contains files * with conflict markers. The cleanness flag is * ignored, it was never actually used, as result of * merge_trees has always overwritten it: the committed * "conflicts" were already resolved. */ discard_cache(); saved_b1 = o->branch1; saved_b2 = o->branch2; o->branch1 = "Temporary merge branch 1"; o->branch2 = "Temporary merge branch 2"; merge_recursive(o, merged_common_ancestors, iter->item, NULL, &merged_common_ancestors); o->branch1 = saved_b1; o->branch2 = saved_b2; o->call_depth--; if (!merged_common_ancestors) die("merge returned no commit"); } discard_cache(); if (!o->call_depth) read_cache(); clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree, &mrtree); if (o->call_depth) { *result = make_virtual_commit(mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } flush_output(o); return clean; }
static int try_parent_shorthands(const char *arg) { char *dotdot; struct object_id oid; struct commit *commit; struct commit_list *parents; int parent_number; int include_rev = 0; int include_parents = 0; int exclude_parent = 0; if ((dotdot = strstr(arg, "^!"))) { include_rev = 1; if (dotdot[2]) return 0; } else if ((dotdot = strstr(arg, "^@"))) { include_parents = 1; if (dotdot[2]) return 0; } else if ((dotdot = strstr(arg, "^-"))) { include_rev = 1; exclude_parent = 1; if (dotdot[2]) { char *end; exclude_parent = strtoul(dotdot + 2, &end, 10); if (*end != '\0' || !exclude_parent) return 0; } } else return 0; *dotdot = 0; if (get_oid_committish(arg, &oid)) { *dotdot = '^'; return 0; } commit = lookup_commit_reference(&oid); if (exclude_parent && exclude_parent > commit_list_count(commit->parents)) { *dotdot = '^'; return 0; } if (include_rev) show_rev(NORMAL, &oid, arg); for (parents = commit->parents, parent_number = 1; parents; parents = parents->next, parent_number++) { char *name = NULL; if (exclude_parent && parent_number != exclude_parent) continue; if (symbolic) name = xstrfmt("%s^%d", arg, parent_number); show_rev(include_parents ? NORMAL : REVERSED, &parents->item->object.oid, name); free(name); } *dotdot = '^'; return 1; }
static int fsck_commit_buffer(struct commit *commit, const char *buffer, unsigned long size, struct fsck_options *options) { struct object_id tree_oid, oid; struct commit_graft *graft; unsigned parent_count, parent_line_count = 0, author_count; int err; const char *buffer_begin = buffer; const char *p; if (verify_headers(buffer, size, &commit->object, options)) return -1; if (!skip_prefix(buffer, "tree ", &buffer)) return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line"); if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') { err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1"); if (err) return err; } buffer = p + 1; while (skip_prefix(buffer, "parent ", &buffer)) { if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') { err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1"); if (err) return err; } buffer = p + 1; parent_line_count++; } graft = lookup_commit_graft(&commit->object.oid); parent_count = commit_list_count(commit->parents); if (graft) { if (graft->nr_parent == -1 && !parent_count) ; /* shallow commit */ else if (graft->nr_parent != parent_count) { err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing"); if (err) return err; } } else { if (parent_count != parent_line_count) { err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing"); if (err) return err; } } author_count = 0; while (skip_prefix(buffer, "author ", &buffer)) { author_count++; err = fsck_ident(&buffer, &commit->object, options); if (err) return err; } if (author_count < 1) err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line"); else if (author_count > 1) err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines"); if (err) return err; if (!skip_prefix(buffer, "committer ", &buffer)) return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, options); if (err) return err; if (!get_commit_tree(commit)) { err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", oid_to_hex(&tree_oid)); if (err) return err; } if (memchr(buffer_begin, '\0', size)) { err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT, "NUL byte in the commit object body"); if (err) return err; } return 0; }
static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reverse) { struct commit_list *l = first_scapegoat(revs, commit, reverse); return commit_list_count(l); }