Beispiel #1
0
int git_patch_get_line_in_hunk(
	const git_diff_line **out,
	git_patch *patch,
	size_t hunk_idx,
	size_t line_of_hunk)
{
	git_patch_hunk *hunk;
	git_diff_line *line;

	assert(patch);

	if (!(hunk = git_array_get(patch->hunks, hunk_idx))) {
		if (out) *out = NULL;
		return patch_error_outofrange("hunk");
	}

	if (line_of_hunk >= hunk->line_count ||
		!(line = git_array_get(
			patch->lines, hunk->line_start + line_of_hunk))) {
		if (out) *out = NULL;
		return patch_error_outofrange("line");
	}

	if (out) *out = line;
	return 0;
}
Beispiel #2
0
static int rebase_setupfiles_merge(git_rebase *rebase)
{
	git_buf commit_filename = GIT_BUF_INIT;
	char id_str[GIT_OID_HEXSZ];
	git_rebase_operation *operation;
	size_t i;
	int error = 0;

	if ((error = rebase_setupfile(rebase, END_FILE, -1, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 ||
		(error = rebase_setupfile(rebase, ONTO_NAME_FILE, -1, "%s\n", rebase->onto_name)) < 0)
		goto done;

	for (i = 0; i < git_array_size(rebase->operations); i++) {
		operation = git_array_get(rebase->operations, i);

		git_buf_clear(&commit_filename);
		git_buf_printf(&commit_filename, CMT_FILE_FMT, i+1);

		git_oid_fmt(id_str, &operation->id);

		if ((error = rebase_setupfile(rebase, commit_filename.ptr, -1,
				"%.*s\n", GIT_OID_HEXSZ, id_str)) < 0)
			goto done;
	}

done:
	git_buf_free(&commit_filename);
	return error;
}
Beispiel #3
0
static const git_oid *commit_parent_for_amend(size_t curr, void *payload)
{
	const git_commit *commit_to_amend = payload;
	if (curr >= git_array_size(commit_to_amend->parent_ids))
		return NULL;
	return git_array_get(commit_to_amend->parent_ids, curr);
}
Beispiel #4
0
static int rebase_commit_inmemory(
	git_oid *commit_id,
	git_rebase *rebase,
	const git_signature *author,
	const git_signature *committer,
	const char *message_encoding,
	const char *message)
{
	git_rebase_operation *operation;
	git_commit *commit = NULL;
	int error = 0;

	operation = git_array_get(rebase->operations, rebase->current);

	assert(operation);
	assert(rebase->index);
	assert(rebase->last_commit);

	if ((error = rebase_commit__create(&commit, rebase, rebase->index,
		rebase->last_commit, author, committer, message_encoding, message)) < 0)
		goto done;

	git_commit_free(rebase->last_commit);
	rebase->last_commit = commit;

	git_oid_cpy(commit_id, git_commit_id(commit));

done:
	if (error < 0)
		git_commit_free(commit);

	return error;
}
static int diff_context_line__pattern_match(
	git_diff_driver *driver, git_buf *line)
{
	size_t i, maxi = git_array_size(driver->fn_patterns);
	regmatch_t pmatch[2];

	for (i = 0; i < maxi; ++i) {
		git_diff_driver_pattern *pat = git_array_get(driver->fn_patterns, i);

		if (!regexec(&pat->re, line->ptr, 2, pmatch, 0)) {
			if (pat->flags & REG_NEGATE)
				return false;

			/* use pmatch data to trim line data */
			i = (pmatch[1].rm_so >= 0) ? 1 : 0;
			git_buf_consume(line, git_buf_cstr(line) + pmatch[i].rm_so);
			git_buf_truncate(line, pmatch[i].rm_eo - pmatch[i].rm_so);
			git_buf_rtrim(line);

			return true;
		}
	}

	return false;
}
Beispiel #6
0
const git_oid *git_commit_parent_id(
	const git_commit *commit, unsigned int n)
{
	assert(commit);

	return git_array_get(commit->parent_ids, n);
}
Beispiel #7
0
int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx)
{
	git_patch_hunk *hunk;
	assert(patch);

	if (!(hunk = git_array_get(patch->hunks, hunk_idx)))
		return patch_error_outofrange("hunk");
	return (int)hunk->line_count;
}
Beispiel #8
0
int git_patch__invoke_callbacks(
	git_patch *patch,
	git_diff_file_cb file_cb,
	git_diff_binary_cb binary_cb,
	git_diff_hunk_cb hunk_cb,
	git_diff_line_cb line_cb,
	void *payload)
{
	int error = 0;
	uint32_t i, j;

	if (file_cb)
		error = file_cb(patch->delta, 0, payload);

	if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
		if (binary_cb)
			error = binary_cb(patch->delta, &patch->binary, payload);

		return error;
	}

	if (!hunk_cb && !line_cb)
		return error;

	for (i = 0; !error && i < git_array_size(patch->hunks); ++i) {
		git_patch_hunk *h = git_array_get(patch->hunks, i);

		if (hunk_cb)
			error = hunk_cb(patch->delta, &h->hunk, payload);

		if (!line_cb)
			continue;

		for (j = 0; !error && j < h->line_count; ++j) {
			git_diff_line *l =
				git_array_get(patch->lines, h->line_start + j);

			error = line_cb(patch->delta, &h->hunk, l, payload);
		}
	}

	return error;
}
Beispiel #9
0
static int rebase_next_inmemory(
	git_rebase_operation **out,
	git_rebase *rebase)
{
	git_commit *current_commit = NULL, *parent_commit = NULL;
	git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL;
	git_rebase_operation *operation;
	git_index *index = NULL;
	unsigned int parent_count;
	int error;

	*out = NULL;

	operation = git_array_get(rebase->operations, rebase->current);

	if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
		(error = git_commit_tree(&current_tree, current_commit)) < 0)
		goto done;

	if ((parent_count = git_commit_parentcount(current_commit)) > 1) {
		giterr_set(GITERR_REBASE, "Cannot rebase a merge commit");
		error = -1;
		goto done;
	} else if (parent_count) {
		if ((error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 ||
			(error = git_commit_tree(&parent_tree, parent_commit)) < 0)
			goto done;
	}

	if ((error = git_commit_tree(&head_tree, rebase->last_commit)) < 0 ||
		(error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0)
		goto done;

	if (!rebase->index) {
		rebase->index = index;
		index = NULL;
	} else {
		if ((error = git_index_read_index(rebase->index, index)) < 0)
			goto done;
	}

	*out = operation;

done:
	git_commit_free(current_commit);
	git_commit_free(parent_commit);
	git_tree_free(current_tree);
	git_tree_free(head_tree);
	git_tree_free(parent_tree);
	git_index_free(index);

	return error;
}
Beispiel #10
0
void git_diff_driver_free(git_diff_driver *driver)
{
	size_t i;

	if (!driver)
		return;

	for (i = 0; i < git_array_size(driver->fn_patterns); ++i)
		regfree(& git_array_get(driver->fn_patterns, i)->re);
	git_array_clear(driver->fn_patterns);

	regfree(&driver->word_pattern);

	git__free(driver);
}
Beispiel #11
0
static bool interesting_arr(commit_list_node_array arr)
{
	git_commit_list_node **n;
	size_t i = 0, size;

	size = git_array_size(arr);
	for (i = 0; i < size; i++) {
		n = git_array_get(arr, i);
		if (!*n)
			break;

		if (!(*n)->uninteresting)
			return true;
	}

	return false;
}
Beispiel #12
0
static int rebase_commit_merge(
	git_oid *commit_id,
	git_rebase *rebase,
	const git_signature *author,
	const git_signature *committer,
	const char *message_encoding,
	const char *message)
{
	git_rebase_operation *operation;
	git_reference *head = NULL;
	git_commit *head_commit = NULL, *commit = NULL;
	git_index *index = NULL;
	char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ];
	int error;

	operation = git_array_get(rebase->operations, rebase->current);
	assert(operation);

	if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 ||
		(error = git_repository_head(&head, rebase->repo)) < 0 ||
		(error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 ||
		(error = git_repository_index(&index, rebase->repo)) < 0 ||
		(error = rebase_commit__create(&commit, rebase, index, head_commit,
			author, committer, message_encoding, message)) < 0 ||
		(error = git_reference__update_for_commit(
			rebase->repo, NULL, "HEAD", git_commit_id(commit), "rebase")) < 0)
		goto done;

	git_oid_fmt(old_idstr, &operation->id);
	git_oid_fmt(new_idstr, git_commit_id(commit));

	if ((error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND,
		"%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr)) < 0)
		goto done;

	git_oid_cpy(commit_id, git_commit_id(commit));

done:
	git_index_free(index);
	git_reference_free(head);
	git_commit_free(head_commit);
	git_commit_free(commit);
	return error;
}
Beispiel #13
0
int git_patch_get_hunk(
	const git_diff_hunk **out,
	size_t *lines_in_hunk,
	git_patch *patch,
	size_t hunk_idx)
{
	git_patch_hunk *hunk;
	assert(patch);

	hunk = git_array_get(patch->hunks, hunk_idx);

	if (!hunk) {
		if (out) *out = NULL;
		if (lines_in_hunk) *lines_in_hunk = 0;
		return patch_error_outofrange("hunk");
	}

	if (out) *out = &hunk->hunk;
	if (lines_in_hunk) *lines_in_hunk = hunk->line_count;
	return 0;
}
Beispiel #14
0
static int git_commit__create_buffer_internal(
	git_buf *out,
	const git_signature *author,
	const git_signature *committer,
	const char *message_encoding,
	const char *message,
	const git_oid *tree,
	git_array_oid_t *parents)
{
	size_t i = 0;
	const git_oid *parent;

	assert(out && tree);

	git_oid__writebuf(out, "tree ", tree);

	for (i = 0; i < git_array_size(*parents); i++) {
		parent = git_array_get(*parents, i);
		git_oid__writebuf(out, "parent ", parent);
	}

	git_signature__writebuf(out, "author ", author);
	git_signature__writebuf(out, "committer ", committer);

	if (message_encoding != NULL)
		git_buf_printf(out, "encoding %s\n", message_encoding);

	git_buf_putc(out, '\n');

	if (git_buf_puts(out, message) < 0)
		goto on_error;

	return 0;

on_error:
	git_buf_dispose(out);
	return -1;
}
Beispiel #15
0
static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree,
				     git_commit_parent_callback parent_cb, void *parent_payload,
				     const git_oid *current_id, bool validate)
{
	size_t i;
	int error;
	git_oid *parent_cpy;
	const git_oid *parent;

	if (validate && !git_object__is_valid(repo, tree, GIT_OBJECT_TREE))
		return -1;

	i = 0;
	while ((parent = parent_cb(i, parent_payload)) != NULL) {
		if (validate && !git_object__is_valid(repo, parent, GIT_OBJECT_COMMIT)) {
			error = -1;
			goto on_error;
		}

		parent_cpy = git_array_alloc(*parents);
		GITERR_CHECK_ALLOC(parent_cpy);

		git_oid_cpy(parent_cpy, parent);
		i++;
	}

	if (current_id && (parents->size == 0 || git_oid_cmp(current_id, git_array_get(*parents, 0)))) {
		giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent");
		error = GIT_EMODIFIED;
		goto on_error;
	}

	return 0;

on_error:
	git_array_clear(*parents);
	return error;
}
Beispiel #16
0
int git_patch_line_stats(
	size_t *total_ctxt,
	size_t *total_adds,
	size_t *total_dels,
	const git_patch *patch)
{
	size_t totals[3], idx;

	memset(totals, 0, sizeof(totals));

	for (idx = 0; idx < git_array_size(patch->lines); ++idx) {
		git_diff_line *line = git_array_get(patch->lines, idx);
		if (!line)
			continue;

		switch (line->origin) {
		case GIT_DIFF_LINE_CONTEXT:  totals[0]++; break;
		case GIT_DIFF_LINE_ADDITION: totals[1]++; break;
		case GIT_DIFF_LINE_DELETION: totals[2]++; break;
		default:
			/* diff --stat and --numstat don't count EOFNL marks because
			* they will always be paired with a ADDITION or DELETION line.
			*/
			break;
		}
	}

	if (total_ctxt)
		*total_ctxt = totals[0];
	if (total_adds)
		*total_adds = totals[1];
	if (total_dels)
		*total_dels = totals[2];

	return 0;
}
Beispiel #17
0
static int rebase_commit_merge(
	git_oid *commit_id,
	git_rebase *rebase,
	const git_signature *author,
	const git_signature *committer,
	const char *message_encoding,
	const char *message)
{
	git_index *index = NULL;
	git_reference *head = NULL;
	git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL;
	git_rebase_operation *operation;
	git_tree *head_tree = NULL, *tree = NULL;
	git_diff *diff = NULL;
	git_oid tree_id;
	git_buf reflog_msg = GIT_BUF_INIT;
	char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ];
	int error;

	operation = git_array_get(rebase->operations, rebase->current);
	assert(operation);

	if ((error = git_repository_index(&index, rebase->repo)) < 0)
		goto done;

	if (git_index_has_conflicts(index)) {
		giterr_set(GITERR_REBASE, "Conflicts have not been resolved");
		error = GIT_EMERGECONFLICT;
		goto done;
	}

	if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
		(error = git_repository_head(&head, rebase->repo)) < 0 ||
		(error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 ||
		(error = git_commit_tree(&head_tree, head_commit)) < 0 ||
		(error = git_diff_tree_to_index(&diff, rebase->repo, head_tree, index, NULL)) < 0)
		goto done;

	if (git_diff_num_deltas(diff) == 0) {
		giterr_set(GITERR_REBASE, "This patch has already been applied");
		error = GIT_EAPPLIED;
		goto done;
	}

	if ((error = git_index_write_tree(&tree_id, index)) < 0 ||
		(error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0)
		goto done;

	if (!author)
		author = git_commit_author(current_commit);

	if (!message) {
		message_encoding = git_commit_message_encoding(current_commit);
		message = git_commit_message(current_commit);
	}

	if ((error = git_commit_create(commit_id, rebase->repo, NULL, author,
			committer, message_encoding, message, tree, 1,
			(const git_commit **)&head_commit)) < 0 ||
		(error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 ||
		(error = git_reference__update_for_commit(
			rebase->repo, NULL, "HEAD", commit_id, "rebase")) < 0)
		goto done;

	git_oid_fmt(old_idstr, git_commit_id(current_commit));
	git_oid_fmt(new_idstr, commit_id);

	error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND,
		"%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr);

done:
	git_buf_free(&reflog_msg);
	git_commit_free(commit);
	git_diff_free(diff);
	git_tree_free(tree);
	git_tree_free(head_tree);
	git_commit_free(head_commit);
	git_commit_free(current_commit);
	git_reference_free(head);
	git_index_free(index);

	return error;
}
Beispiel #18
0
static int rebase_commit__create(
	git_commit **out,
	git_rebase *rebase,
	git_index *index,
	git_commit *parent_commit,
	const git_signature *author,
	const git_signature *committer,
	const char *message_encoding,
	const char *message)
{
	git_rebase_operation *operation;
	git_commit *current_commit = NULL, *commit = NULL;
	git_tree *parent_tree = NULL, *tree = NULL;
	git_oid tree_id, commit_id;
	int error;

	operation = git_array_get(rebase->operations, rebase->current);

	if (git_index_has_conflicts(index)) {
		giterr_set(GITERR_REBASE, "conflicts have not been resolved");
		error = GIT_EUNMERGED;
		goto done;
	}

	if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
		(error = git_commit_tree(&parent_tree, parent_commit)) < 0 ||
		(error = git_index_write_tree_to(&tree_id, index, rebase->repo)) < 0 ||
		(error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0)
		goto done;

	if (git_oid_equal(&tree_id, git_tree_id(parent_tree))) {
		giterr_set(GITERR_REBASE, "this patch has already been applied");
		error = GIT_EAPPLIED;
		goto done;
	}

	if (!author)
		author = git_commit_author(current_commit);

	if (!message) {
		message_encoding = git_commit_message_encoding(current_commit);
		message = git_commit_message(current_commit);
	}

	if ((error = git_commit_create(&commit_id, rebase->repo, NULL, author,
		committer, message_encoding, message, tree, 1,
		(const git_commit **)&parent_commit)) < 0 ||
		(error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0)
		goto done;

	*out = commit;

done:
	if (error < 0)
		git_commit_free(commit);

	git_commit_free(current_commit);
	git_tree_free(parent_tree);
	git_tree_free(tree);

	return error;
}
Beispiel #19
0
static int rebase_next_merge(
	git_rebase_operation **out,
	git_rebase *rebase)
{
	git_buf path = GIT_BUF_INIT;
	git_commit *current_commit = NULL, *parent_commit = NULL;
	git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL;
	git_index *index = NULL;
	git_indexwriter indexwriter = GIT_INDEXWRITER_INIT;
	git_rebase_operation *operation;
	git_checkout_options checkout_opts;
	char current_idstr[GIT_OID_HEXSZ];
	unsigned int parent_count;
	int error;

	*out = NULL;

	operation = git_array_get(rebase->operations, rebase->current);

	if ((error = git_commit_lookup(&current_commit, rebase->repo, &operation->id)) < 0 ||
		(error = git_commit_tree(&current_tree, current_commit)) < 0 ||
		(error = git_repository_head_tree(&head_tree, rebase->repo)) < 0)
		goto done;

	if ((parent_count = git_commit_parentcount(current_commit)) > 1) {
		giterr_set(GITERR_REBASE, "Cannot rebase a merge commit");
		error = -1;
		goto done;
	} else if (parent_count) {
		if ((error = git_commit_parent(&parent_commit, current_commit, 0)) < 0 ||
			(error = git_commit_tree(&parent_tree, parent_commit)) < 0)
			goto done;
	}

	git_oid_fmt(current_idstr, &operation->id);

	normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit);

	if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 ||
		(error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%" PRIuZ "\n", rebase->current+1)) < 0 ||
		(error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 ||
		(error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 ||
		(error = git_merge__check_result(rebase->repo, index)) < 0 ||
		(error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 ||
		(error = git_indexwriter_commit(&indexwriter)) < 0)
		goto done;

	*out = operation;

done:
	git_indexwriter_cleanup(&indexwriter);
	git_index_free(index);
	git_tree_free(current_tree);
	git_tree_free(head_tree);
	git_tree_free(parent_tree);
	git_commit_free(parent_commit);
	git_commit_free(current_commit);
	git_buf_free(&path);

	return error;
}
Beispiel #20
0
static int parse_hunk_body(
	git_patch_parsed *patch,
	git_patch_hunk *hunk,
	git_patch_parse_ctx *ctx)
{
	git_diff_line *line;
	int error = 0;

	int oldlines = hunk->hunk.old_lines;
	int newlines = hunk->hunk.new_lines;

	for (;
		ctx->parse_ctx.remain_len > 1 &&
		(oldlines || newlines) &&
		!git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -");
		git_parse_advance_line(&ctx->parse_ctx)) {

		char c;
		int origin;
		int prefix = 1;

		if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') {
			error = git_parse_err("invalid patch instruction at line %"PRIuZ,
				ctx->parse_ctx.line_num);
			goto done;
		}

		git_parse_peek(&c, &ctx->parse_ctx, 0);

		switch (c) {
		case '\n':
			prefix = 0;
			/* fall through */

		case ' ':
			origin = GIT_DIFF_LINE_CONTEXT;
			oldlines--;
			newlines--;
			break;

		case '-':
			origin = GIT_DIFF_LINE_DELETION;
			oldlines--;
			break;

		case '+':
			origin = GIT_DIFF_LINE_ADDITION;
			newlines--;
			break;

		default:
			error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}

		line = git_array_alloc(patch->base.lines);
		GITERR_CHECK_ALLOC(line);

		memset(line, 0x0, sizeof(git_diff_line));

		line->content = ctx->parse_ctx.line + prefix;
		line->content_len = ctx->parse_ctx.line_len - prefix;
		line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
		line->origin = origin;

		hunk->line_count++;
	}

	if (oldlines || newlines) {
		error = git_parse_err(
			"invalid patch hunk, expected %d old lines and %d new lines",
			hunk->hunk.old_lines, hunk->hunk.new_lines);
		goto done;
	}

	/* Handle "\ No newline at end of file".  Only expect the leading
	 * backslash, though, because the rest of the string could be
	 * localized.  Because `diff` optimizes for the case where you
	 * want to apply the patch by hand.
	 */
	if (git_parse_ctx_contains_s(&ctx->parse_ctx, "\\ ") &&
		git_array_size(patch->base.lines) > 0) {

		line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1);

		if (line->content_len < 1) {
			error = git_parse_err("cannot trim trailing newline of empty line");
			goto done;
		}

		line->content_len--;

		git_parse_advance_line(&ctx->parse_ctx);
	}

done:
	return error;
}
Beispiel #21
0
git_rebase_operation *git_rebase_operation_byindex(git_rebase *rebase, size_t idx)
{
	assert(rebase);

	return git_array_get(rebase->operations, idx);
}