diff mbox series

[04/11] merge-ort: implement compare_pairs() and collect_renames()

Message ID 207bb9a837cb855721daa88caaad80e37cb40ffe.1607542887.git.gitgitgadget@gmail.com (mailing list archive)
State Superseded
Headers show
Series merge-ort: add basic rename detection | expand

Commit Message

Elijah Newren Dec. 9, 2020, 7:41 p.m. UTC
From: Elijah Newren <newren@gmail.com>

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 merge-ort.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

Comments

Derrick Stolee Dec. 11, 2020, 3 a.m. UTC | #1
On 12/9/2020 2:41 PM, Elijah Newren via GitGitGadget wrote:
> From: Elijah Newren <newren@gmail.com>

Perhaps worth pointing out comparison to score_compare() 

> Signed-off-by: Elijah Newren <newren@gmail.com>
> ---
>  merge-ort.c | 27 +++++++++++++++++++++++++--
>  1 file changed, 25 insertions(+), 2 deletions(-)
> 
> diff --git a/merge-ort.c b/merge-ort.c
> index 1ff637e57af..3cdf8124b85 100644
> --- a/merge-ort.c
> +++ b/merge-ort.c
> @@ -625,7 +625,13 @@ static int process_renames(struct merge_options *opt,
>  
>  static int compare_pairs(const void *a_, const void *b_)
>  {
> -	die("Not yet implemented.");
> +	const struct diff_filepair *a = *((const struct diff_filepair **)a_);
> +	const struct diff_filepair *b = *((const struct diff_filepair **)b_);
> +
> +	int cmp = strcmp(a->one->path, b->one->path);
> +	if (cmp)
> +		return cmp;
> +	return a->score - b->score;

Hm. I wasn't sure what would happen when subtracting these
"unsigned short" scores, but I see that score_compare() does
the same. Any potential for an existing, hidden bug here?

Thanks,
-Stolee
Elijah Newren Dec. 11, 2020, 6:43 p.m. UTC | #2
On Thu, Dec 10, 2020 at 7:00 PM Derrick Stolee <stolee@gmail.com> wrote:
>
> On 12/9/2020 2:41 PM, Elijah Newren via GitGitGadget wrote:
> > From: Elijah Newren <newren@gmail.com>
>
> Perhaps worth pointing out comparison to score_compare()

That comparison might be slightly misleading due to this line from
collect_renames():
+               p->score = side_index;
Since diffcore-rename has already used the percentage similarity to
determine if two files are a rename and has recorded that in a
separate field, I don't need the percentage similarity anymore.  So
the score is no longer needful at this point.  However, I needed a way
to somehow record which side of the merge each diff_filepair came from
and I can't just add a field to the diff_filepair struct (especially
since its only use is in merge-ort).  I know, I know, I'm evil.
Creating a new struct just so I could have something that contained a
diff_filepair and another auxiliary field just felt so ugly, so I just
reused this one field instead.  And I did use that field to "rank" or
"sort" the pairs, so doesn't that make it a valid "score"?  :-)

I should probably add a big comment about this just above that line.
I've meant to do that a multiple different times, but oddly enough
this thought has only occurred to me while I'm out running or
otherwise away from the computer.  Until now, of course.

> > Signed-off-by: Elijah Newren <newren@gmail.com>
> > ---
> >  merge-ort.c | 27 +++++++++++++++++++++++++--
> >  1 file changed, 25 insertions(+), 2 deletions(-)
> >
> > diff --git a/merge-ort.c b/merge-ort.c
> > index 1ff637e57af..3cdf8124b85 100644
> > --- a/merge-ort.c
> > +++ b/merge-ort.c
> > @@ -625,7 +625,13 @@ static int process_renames(struct merge_options *opt,
> >
> >  static int compare_pairs(const void *a_, const void *b_)
> >  {
> > -     die("Not yet implemented.");
> > +     const struct diff_filepair *a = *((const struct diff_filepair **)a_);
> > +     const struct diff_filepair *b = *((const struct diff_filepair **)b_);
> > +
> > +     int cmp = strcmp(a->one->path, b->one->path);
> > +     if (cmp)
> > +             return cmp;
> > +     return a->score - b->score;
>
> Hm. I wasn't sure what would happen when subtracting these
> "unsigned short" scores, but I see that score_compare() does
> the same. Any potential for an existing, hidden bug here?

In the case of compare_pairs(), a->score and b->score have a minimum
value of 1 and a maximum value of 2 (note above where I set score to
the side index).  I believe most platforms will have an int big enough
to store the result of that subtraction.

I'm not sure why I bother with the secondary sort, though.  It shouldn't matter.

Which is probably a good thing, because strcmp(a, b) gives us
ascending order, and a - b gives us descending order.  That's messed
up.  Honestly, it doesn't matter because all I really needed from the
sort was for diff_filepairs with the same source name to be adjacent
(so that I can check for rename/rename(1to2) conflicts be comparing
adjacent pairs), but still it's annoying that the function contradicts
itself on the desired order.  And it'll trigger whenever the same path
is renamed by both sides of history, which we have a number of
testcases for in the testsuite.  So that confirms that the secondary
sort just doesn't matter.  I'll get rid of it and just use strcmp.
diff mbox series

Patch

diff --git a/merge-ort.c b/merge-ort.c
index 1ff637e57af..3cdf8124b85 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -625,7 +625,13 @@  static int process_renames(struct merge_options *opt,
 
 static int compare_pairs(const void *a_, const void *b_)
 {
-	die("Not yet implemented.");
+	const struct diff_filepair *a = *((const struct diff_filepair **)a_);
+	const struct diff_filepair *b = *((const struct diff_filepair **)b_);
+
+	int cmp = strcmp(a->one->path, b->one->path);
+	if (cmp)
+		return cmp;
+	return a->score - b->score;
 }
 
 /* Call diffcore_rename() to compute which files have changed on given side */
@@ -671,7 +677,24 @@  static int collect_renames(struct merge_options *opt,
 			   struct diff_queue_struct *result,
 			   unsigned side_index)
 {
-	die("Not yet implemented.");
+	int i, clean = 1;
+	struct diff_queue_struct *side_pairs;
+	struct rename_info *renames = opt->priv->renames;
+
+	side_pairs = &renames->pairs[side_index];
+
+	for (i = 0; i < side_pairs->nr; ++i) {
+		struct diff_filepair *p = side_pairs->queue[i];
+
+		if (p->status != 'R') {
+			diff_free_filepair(p);
+			continue;
+		}
+		p->score = side_index;
+		result->queue[result->nr++] = p;
+	}
+
+	return clean;
 }
 
 static int detect_and_process_renames(struct merge_options *opt,