diff options
Diffstat (limited to 'src/diff.c')
| -rw-r--r-- | src/diff.c | 77 | 
1 files changed, 64 insertions, 13 deletions
diff --git a/src/diff.c b/src/diff.c index f829fb07c..765956a29 100644 --- a/src/diff.c +++ b/src/diff.c @@ -327,6 +327,22 @@ static const char *diff_mnemonic_prefix(  	return pfx;  } +static int diff_entry_cmp(const void *a, const void *b) +{ +	const git_index_entry *entry_a = a; +	const git_index_entry *entry_b = b; + +	return strcmp(entry_a->path, entry_b->path); +} + +static int diff_entry_icmp(const void *a, const void *b) +{ +	const git_index_entry *entry_a = a; +	const git_index_entry *entry_b = b; + +	return strcasecmp(entry_a->path, entry_b->path); +} +  static void diff_set_ignore_case(git_diff *diff, bool ignore_case)  {  	if (!ignore_case) { @@ -335,7 +351,7 @@ static void diff_set_ignore_case(git_diff *diff, bool ignore_case)  		diff->strcomp    = git__strcmp;  		diff->strncomp   = git__strncmp;  		diff->pfxcomp    = git__prefixcmp; -		diff->entrycomp  = git_index_entry_cmp; +		diff->entrycomp  = diff_entry_cmp;  		git_vector_set_cmp(&diff->deltas, git_diff_delta__cmp);  	} else { @@ -344,7 +360,7 @@ static void diff_set_ignore_case(git_diff *diff, bool ignore_case)  		diff->strcomp    = git__strcasecmp;  		diff->strncomp   = git__strncasecmp;  		diff->pfxcomp    = git__prefixcmp_icase; -		diff->entrycomp  = git_index_entry_icmp; +		diff->entrycomp  = diff_entry_icmp;  		git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp);  	} @@ -731,8 +747,12 @@ static int maybe_modified(  		new_is_workdir)  		nmode = (nmode & ~MODE_BITS_MASK) | (omode & MODE_BITS_MASK); +	/* if one side is a conflict, mark the whole delta as conflicted */ +	if (git_index_entry_stage(oitem) > 0 || git_index_entry_stage(nitem) > 0) +		status = GIT_DELTA_CONFLICTED; +  	/* support "assume unchanged" (poorly, b/c we still stat everything) */ -	if ((oitem->flags & GIT_IDXENTRY_VALID) != 0) +	else if ((oitem->flags & GIT_IDXENTRY_VALID) != 0)  		status = GIT_DELTA_UNMODIFIED;  	/* support "skip worktree" index bit */ @@ -875,9 +895,29 @@ static int iterator_advance(  	const git_index_entry **entry,  	git_iterator *iterator)  { -	int error; +	const git_index_entry *prev_entry = *entry; +	int cmp, error; + +	/* if we're looking for conflicts, we only want to report +	 * one conflict for each file, instead of all three sides. +	 * so if this entry is a conflict for this file, and the +	 * previous one was a conflict for the same file, skip it. +	 */ +	while ((error = git_iterator_advance(entry, iterator)) == 0) { +		if (!(iterator->flags & GIT_ITERATOR_INCLUDE_CONFLICTS) || +			git_index_entry_stage(prev_entry) == 0 || +			git_index_entry_stage(*entry) == 0) +			break; + +		cmp = (iterator->flags & GIT_ITERATOR_IGNORE_CASE) ? +			strcasecmp(prev_entry->path, (*entry)->path) : +			strcmp(prev_entry->path, (*entry)->path); + +		if (cmp) +			break; +	} -	if ((error = git_iterator_advance(entry, iterator)) == GIT_ITEROVER) { +	if (error == GIT_ITEROVER) {  		*entry = NULL;  		error = 0;  	} @@ -926,8 +966,12 @@ static int handle_unmatched_new_item(  	/* check if this is a prefix of the other side */  	contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); +	/* update delta_type if this item is conflicted */ +	if (git_index_entry_stage(nitem)) +		delta_type = GIT_DELTA_CONFLICTED; +  	/* update delta_type if this item is ignored */ -	if (git_iterator_current_is_ignored(info->new_iter)) +	else if (git_iterator_current_is_ignored(info->new_iter))  		delta_type = GIT_DELTA_IGNORED;  	if (nitem->mode == GIT_FILEMODE_TREE) { @@ -1067,8 +1111,14 @@ static int handle_unmatched_new_item(  static int handle_unmatched_old_item(  	git_diff *diff, diff_in_progress *info)  { -	int error = diff_delta__from_one(diff, GIT_DELTA_DELETED, info->oitem); -	if (error != 0) +	git_delta_t delta_type = GIT_DELTA_DELETED; +	int error; + +	/* update delta_type if this item is conflicted */ +	if (git_index_entry_stage(info->oitem)) +		delta_type = GIT_DELTA_CONFLICTED; + +	if ((error = diff_delta__from_one(diff, delta_type, info->oitem)) < 0)  		return error;  	/* if we are generating TYPECHANGE records then check for that @@ -1234,6 +1284,8 @@ int git_diff_tree_to_index(  {  	int error = 0;  	bool index_ignore_case = false; +	git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE | +		GIT_ITERATOR_INCLUDE_CONFLICTS;  	assert(diff && repo); @@ -1243,10 +1295,8 @@ int git_diff_tree_to_index(  	index_ignore_case = index->ignore_case;  	DIFF_FROM_ITERATORS( -		git_iterator_for_tree( -			&a, old_tree, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx), -		git_iterator_for_index( -			&b, index, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx) +		git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx), +		git_iterator_for_index(&b, index, iflag, pfx, pfx)  	);  	/* if index is in case-insensitive order, re-sort deltas to match */ @@ -1270,7 +1320,8 @@ int git_diff_index_to_workdir(  		return error;  	DIFF_FROM_ITERATORS( -		git_iterator_for_index(&a, index, 0, pfx, pfx), +		git_iterator_for_index( +			&a, index, GIT_ITERATOR_INCLUDE_CONFLICTS, pfx, pfx),  		git_iterator_for_workdir(  			&b, repo, index, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)  	);  | 
