Beispiel #1
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;

	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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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);
		}
	}
}
Beispiel #5
0
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;
}
Beispiel #6
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);
}
Beispiel #7
0
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;
}
Beispiel #8
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;
	}
}
Beispiel #9
0
/*
 * 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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
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);
}