Re: What's cooking in git.git (Apr 2013, #02; Fri, 5)

6 messages, 1 author, 2016-06-15 · open the first message on its own page

Re: What's cooking in git.git (Apr 2013, #02; Fri, 5)

From: Thomas Rast <hidden>
Date: 2016-06-15 22:56:48

Junio C Hamano [off-list ref] writes:
* tr/line-log (2013-04-05) 7 commits
  (merged to 'next' on 2013-04-05 at 5afb00c)
 + log -L: fix overlapping input ranges
 + log -L: check range set invariants when we look it up
  (merged to 'next' on 2013-04-01 at 5be920c)
 + Speed up log -L... -M
 + log -L: :pattern:file syntax to find by funcname
 + Implement line-history search (git log -L)
 + Export rewrite_parents() for 'log -L'
 + Refactor parse_loc

 Will merge down to 'master'
I did some fuzz-testing, choosing random commits and ranges from files
and running log -L on them.

While the good news is that I couldn't break ordinary log -L, there's a
rather embarassing pair of bugs: -M is completely broken (at least when
it would do any good) and the tests that claim to look at move support
actually don't pass -M.

So please hold off merging, I'll try to get this fixed this weekend.

Sorry for the trouble!

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

[PATCH 0/4] fix log -L -M

From: Thomas Rast <hidden>
Date: 2016-06-15 22:56:48

Ok, so this was not quite as bad as I feared.  The move support as far
as I had thought to test it previously actually worked ok, it just
wasn't tested (which is embarrassing enough).

The bug fixed in patch 3 is a bit more involved and only triggered by
history that merges a rename with a modification to the original
filename.  Luckily -- I guess -- there are several cases of this
happening in git.git around the big builtin/ move in 81b50f3 (Move
'builtin-*' into a 'builtin/' subdirectory, 2010-02-22).  So my fuzz
tests found that problem.  You can reproduce with e.g.

  git log -M -L:cmd_format_patch:builtin/log.c

in any git.git.


Thomas Rast (4):
  t4211: pass -M to 'git log -M -L...' test
  log -L: test merge of parallel modify/rename
  log -L: store the path instead of a diff_filespec
  log -L: improve comments in process_all_files()

 line-log.c                               |  62 +++++++-----
 line-log.h                               |   8 +-
 t/t4211-line-log.sh                      |  18 +++-
 t/t4211/expect.move-support-f            |  56 +++++++++--
 t/t4211/expect.parallel-change-f-to-main | 160 +++++++++++++++++++++++++++++++
 t/t4211/history.export                   |  80 +++++++++++++++-
 6 files changed, 344 insertions(+), 40 deletions(-)
 create mode 100644 t/t4211/expect.parallel-change-f-to-main

-- 
1.8.2.1.567.g8ad0f43

[PATCH 2/4] log -L: test merge of parallel modify/rename

From: Thomas Rast <hidden>
Date: 2016-06-15 22:56:48

This tests a toy example of a history like

  * Merge
  | \
  |  * Modify foo
  |  |
  *  | Rename foo->bar
  | /
  * Create foo

Current log -L fails on this; we'll fix it in the next commit.

Signed-off-by: Thomas Rast <redacted>
---
 t/t4211-line-log.sh                      |  16 +++-
 t/t4211/expect.parallel-change-f-to-main | 160 +++++++++++++++++++++++++++++++
 t/t4211/history.export                   |  80 +++++++++++++++-
 3 files changed, 250 insertions(+), 6 deletions(-)
 create mode 100644 t/t4211/expect.parallel-change-f-to-main
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 2a67e31..bba0b09 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -8,13 +8,20 @@ test_expect_success 'setup (import history)' '
 	git reset --hard
 '
 
-canned_test () {
-	test_expect_success "$1" "
-		git log $1 >actual &&
-		test_cmp \"\$TEST_DIRECTORY\"/t4211/expect.$2 actual
+canned_test_1 () {
+	test_expect_$1 "$2" "
+		git log $2 >actual &&
+		test_cmp \"\$TEST_DIRECTORY\"/t4211/expect.$3 actual
 	"
 }
 
+canned_test () {
+	canned_test_1 success "$@"
+}
+canned_test_failure () {
+	canned_test_1 failure "$@"
+}
+
 test_bad_opts () {
 	test_expect_success "invalid args: $1" "
 		test_must_fail git log $1 2>errors &&
@@ -38,6 +45,7 @@ canned_test "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple" two-ranges
 canned_test "-L 24,+1:a.c simple" vanishes-early
 
 canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f
+canned_test_failure "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main
 
 canned_test "-L 4,12:a.c -L :main:a.c simple" multiple
 canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping
diff --git a/t/t4211/expect.parallel-change-f-to-main b/t/t4211/expect.parallel-change-f-to-main
new file mode 100644
index 0000000..052def8
--- /dev/null
+++ b/t/t4211/expect.parallel-change-f-to-main
@@ -0,0 +1,160 @@
+commit 0469c60bc4837d52d97b1f081dec5f98dea20fed
+Merge: ba227c6 6ce3c4f
+Author: Thomas Rast <trast@inf.ethz.ch>
+Date:   Fri Apr 12 16:16:24 2013 +0200
+
+    Merge across the rename
+
+
+commit 6ce3c4ff690136099bb17e1a8766b75764726ea7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:49:50 2013 +0100
+
+    another simple change
+
+diff --git a/b.c b/b.c
+--- a/b.c
++++ b/b.c
+@@ -4,14 +4,14 @@
+ long f(long x)
+ {
+ 	int s = 0;
+ 	while (x) {
+-		x >>= 1;
++		x /= 2;
+ 		s++;
+ 	}
+ 	return s;
+ }
+ 
+ /*
+  * This is only an example!
+  */
+ 
+
+commit ba227c6632349700fbb957dec2b50f5e2358be3f
+Author: Thomas Rast <trast@inf.ethz.ch>
+Date:   Fri Apr 12 16:15:57 2013 +0200
+
+    change on another line of history while rename happens
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -4,14 +4,14 @@
+ long f(long x)
+ {
+ 	int s = 0;
+ 	while (x) {
+ 		x >>= 1;
+ 		s++;
+ 	}
+ 	return s;
+ }
+ 
+ /*
+- * This is only an example!
++ * This is only a short example!
+  */
+ 
+
+commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:45:41 2013 +0100
+
+    touch comment
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,14 +3,14 @@
+ long f(long x)
+ {
+ 	int s = 0;
+ 	while (x) {
+ 		x >>= 1;
+ 		s++;
+ 	}
+ 	return s;
+ }
+ 
+ /*
+- * A comment.
++ * This is only an example!
+  */
+ 
+
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:45:16 2013 +0100
+
+    touch both functions
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,14 +3,14 @@
+-int f(int x)
++long f(long x)
+ {
+ 	int s = 0;
+ 	while (x) {
+ 		x >>= 1;
+ 		s++;
+ 	}
+ 	return s;
+ }
+ 
+ /*
+  * A comment.
+  */
+ 
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:44:55 2013 +0100
+
+    change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,13 +3,14 @@
+ int f(int x)
+ {
+ 	int s = 0;
+ 	while (x) {
+ 		x >>= 1;
+ 		s++;
+ 	}
++	return s;
+ }
+ 
+ /*
+  * A comment.
+  */
+ 
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:44:48 2013 +0100
+
+    initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,13 @@
++int f(int x)
++{
++	int s = 0;
++	while (x) {
++		x >>= 1;
++		s++;
++	}
++}
++
++/*
++ * A comment.
++ */
++
diff --git a/t/t4211/history.export b/t/t4211/history.export
index c159794..f9f41e2 100644
--- a/t/t4211/history.export
+++ b/t/t4211/history.export
@@ -325,6 +325,82 @@ move within the file
 from :17
 M 100644 :18 b.c
 
-reset refs/heads/master
-from :19
+blob
+mark :20
+data 243
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+	int s = 0;
+	while (x) {
+		x >>= 1;
+		s++;
+	}
+	return s;
+}
+
+/*
+ * This is only a short example!
+ */
+
+int main ()
+{
+	printf("%ld\n", f(15));
+	return 0;
+}
+
+/* incomplete lines are bad! */
+
+commit refs/heads/parallel-change
+mark :21
+author Thomas Rast <trast@inf.ethz.ch> 1365776157 +0200
+committer Thomas Rast <trast@inf.ethz.ch> 1365776157 +0200
+data 55
+change on another line of history while rename happens
+from :14
+M 100644 :20 a.c
+
+blob
+mark :22
+data 242
+#include <unistd.h>
+#include <stdio.h>
+
+long f(long x)
+{
+	int s = 0;
+	while (x) {
+		x /= 2;
+		s++;
+	}
+	return s;
+}
+
+/*
+ * This is only a short example!
+ */
+
+int main ()
+{
+	printf("%ld\n", f(15));
+	return 0;
+}
+
+/* incomplete lines are bad! */
+
+commit refs/heads/parallel-change
+mark :23
+author Thomas Rast <trast@inf.ethz.ch> 1365776184 +0200
+committer Thomas Rast <trast@inf.ethz.ch> 1365776191 +0200
+data 24
+Merge across the rename
+from :21
+merge :17
+D a.c
+M 100644 :22 b.c
+
+reset refs/heads/parallel-change
+from :23
 
-- 
1.8.2.1.567.g8ad0f43

[PATCH 1/4] t4211: pass -M to 'git log -M -L...' test

From: Thomas Rast <hidden>
Date: 2016-06-15 22:56:48

Embarrassingly, the -M test did not actually invoke -M, and thus not
really test the feature.
---
 t/t4211-line-log.sh           |  2 +-
 t/t4211/expect.move-support-f | 56 ++++++++++++++++++++++++++++++++++++-------
 2 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 2341351..2a67e31 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -37,7 +37,7 @@ canned_test "-L 20:a.c simple" end-of-file
 canned_test "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple" two-ranges
 canned_test "-L 24,+1:a.c simple" vanishes-early
 
-canned_test "-L '/long f/,/^}/:b.c' move-support" move-support-f
+canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f
 
 canned_test "-L 4,12:a.c -L :main:a.c simple" multiple
 canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping
diff --git a/t/t4211/expect.move-support-f b/t/t4211/expect.move-support-f
index 78a8cf1..c905e01 100644
--- a/t/t4211/expect.move-support-f
+++ b/t/t4211/expect.move-support-f
@@ -19,22 +19,62 @@ diff --git a/b.c b/b.c
  	return s;
  }
 
-commit e6da343666244ea9e67cbe3f3bd26da860f9fe0e
+commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2
 Author: Thomas Rast <trast@student.ethz.ch>
-Date:   Thu Feb 28 10:49:28 2013 +0100
+Date:   Thu Feb 28 10:45:16 2013 +0100
 
-    move file
+    touch both functions
 
-diff --git a/b.c b/b.c
---- /dev/null
-+++ b/b.c
-@@ -0,0 +4,9 @@
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,9 +3,9 @@
+-int f(int x)
 +long f(long x)
+ {
+ 	int s = 0;
+ 	while (x) {
+ 		x >>= 1;
+ 		s++;
+ 	}
+ 	return s;
+ }
+
+commit f04fb20f2c77850996cba739709acc6faecc58f7
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:44:55 2013 +0100
+
+    change f()
+
+diff --git a/a.c b/a.c
+--- a/a.c
++++ b/a.c
+@@ -3,8 +3,9 @@
+ int f(int x)
+ {
+ 	int s = 0;
+ 	while (x) {
+ 		x >>= 1;
+ 		s++;
+ 	}
++	return s;
+ }
+
+commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a
+Author: Thomas Rast <trast@student.ethz.ch>
+Date:   Thu Feb 28 10:44:48 2013 +0100
+
+    initial
+
+diff --git a/a.c b/a.c
+--- /dev/null
++++ b/a.c
+@@ -0,0 +3,8 @@
++int f(int x)
 +{
 +	int s = 0;
 +	while (x) {
 +		x >>= 1;
 +		s++;
 +	}
-+	return s;
 +}
-- 
1.8.2.1.567.g8ad0f43

[PATCH 4/4] log -L: improve comments in process_all_files()

From: Thomas Rast <hidden>
Date: 2016-06-15 22:56:48

The funny range assignment in process_all_files() had me sidetracked
while investigating what led to the previous commit.  Let's improve
the comments.

Signed-off-by: Thomas Rast <redacted>
---
 line-log.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/line-log.c b/line-log.c
index 44d1cd5..4bbb09b 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1095,11 +1095,24 @@ static int process_all_files(struct line_log_data **range_out,
 
 	for (i = 0; i < queue->nr; i++) {
 		struct diff_ranges *pairdiff = NULL;
-		if (process_diff_filepair(rev, queue->queue[i], *range_out, &pairdiff)) {
+		struct diff_filepair *pair = queue->queue[i];
+		if (process_diff_filepair(rev, pair, *range_out, &pairdiff)) {
+			/*
+			 * Store away the diff for later output.  We
+			 * tuck it in the ranges we got as _input_,
+			 * since that's the commit that caused the
+			 * diff.
+			 *
+			 * NEEDSWORK not enough when we get around to
+			 * doing something interesting with merges;
+			 * currently each invocation on a merge parent
+			 * trashes the previous one's diff.
+			 *
+			 * NEEDSWORK tramples over data structures not owned here
+			 */
 			struct line_log_data *rg = range;
 			changed++;
-			/* NEEDSWORK tramples over data structures not owned here */
-			while (rg && strcmp(rg->path, queue->queue[i]->two->path))
+			while (rg && strcmp(rg->path, pair->two->path))
 				rg = rg->next;
 			assert(rg);
 			rg->pair = diff_filepair_dup(queue->queue[i]);
-- 
1.8.2.1.567.g8ad0f43

[PATCH 3/4] log -L: store the path instead of a diff_filespec

From: Thomas Rast <hidden>
Date: 2016-06-15 22:56:48

line_log_data has held a diff_filespec* since the very early versions
of the code.  However, the only place in the code where we actually
need the full filespec is parse_range_arg(); in all other cases, we
are only interested in the path, so there is hardly a reason to store
a filespec.  Even worse, it causes a lot of redundant ->spec->path
pointer dereferencing.

And *even* worse, it caused the following bug.  If you merge a rename
with a modification to the old filename, like so:

  * Merge
  | \
  |  * Modify foo
  |  |
  *  | Rename foo->bar
  | /
  * Create foo

we internally -- in process_ranges_merge_commit() -- scan all parents.
We are mainly looking for one that doesn't have any modifications, so
that we can assign all the blame to it and simplify away the merge.
In doing so, we run the normal machinery on all parents in a loop.
For each parent, we prepare a "working set" line_log_data by making a
copy with line_log_data_copy(), which does *not* make a copy of the
spec.

Now suppose the rename is the first parent.  The diff machinery tells
us that the filepair is ('foo', 'bar').  We duly update the path we
are interested in:

  rg->spec->path = xstrdup(pair->one->path);

But that 'struct spec' is shared between the output line_log_data and
the original input line_log_data.  So we just wrecked the state of
process_ranges_merge_commit().  When we get around to the second
parent, the ranges tell us we are interested in a file 'foo' while the
commits touch 'bar'.

So most of this patch is just s/->spec->path/->path/ and associated
management changes.  This implicitly fixes the bug because we removed
the shared parts between input and output of line_log_data_copy(); it
is now safe to overwrite the path in the copy.

There's one only somewhat related change: the comment in
process_all_files() explains the reasoning behind using 'range' there.
That bit of half-correct code had me sidetracked for a while.

Signed-off-by: Thomas Rast <redacted>
---
 line-log.c          | 45 ++++++++++++++++++++++++---------------------
 line-log.h          |  8 ++++++--
 t/t4211-line-log.sh |  2 +-
 3 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/line-log.c b/line-log.c
index 85c7c24..44d1cd5 100644
--- a/line-log.c
+++ b/line-log.c
@@ -265,7 +265,7 @@ static void free_line_log_data(struct line_log_data *r)
 	if (insertion_point)
 		*insertion_point = NULL;
 	while (p) {
-		int cmp = strcmp(p->spec->path, path);
+		int cmp = strcmp(p->path, path);
 		if (!cmp)
 			return p;
 		if (insertion_point && cmp < 0)
@@ -275,22 +275,26 @@ static void free_line_log_data(struct line_log_data *r)
 	return NULL;
 }
 
+/*
+ * Note: takes ownership of 'path', which happens to be what the only
+ * caller needs.
+ */
 static void line_log_data_insert(struct line_log_data **list,
-				 struct diff_filespec *spec,
+				 char *path,
 				 long begin, long end)
 {
 	struct line_log_data *ip;
-	struct line_log_data *p = search_line_log_data(*list, spec->path, &ip);
+	struct line_log_data *p = search_line_log_data(*list, path, &ip);
 
 	if (p) {
 		range_set_append_unsafe(&p->ranges, begin, end);
 		sort_and_merge_range_set(&p->ranges);
-		free_filespec(spec);
+		free(path);
 		return;
 	}
 
 	p = xcalloc(1, sizeof(struct line_log_data));
-	p->spec = spec;
+	p->path = path;
 	range_set_append(&p->ranges, begin, end);
 	if (ip) {
 		p->next = ip->next;
@@ -354,7 +358,7 @@ static void dump_line_log_data(struct line_log_data *r)
 {
 	char buf[4096];
 	while (r) {
-		snprintf(buf, 4096, "file %s\n", r->spec->path);
+		snprintf(buf, 4096, "file %s\n", r->path);
 		dump_range_set(&r->ranges, buf);
 		r = r->next;
 	}
@@ -561,7 +565,7 @@ static const char *nth_line(void *data, long line)
 
 	for_each_string_list_item(item, args) {
 		const char *name_part, *range_part;
-		const char *full_name;
+		char *full_name;
 		struct diff_filespec *spec;
 		long begin = 0, end = 0;
 
@@ -584,7 +588,7 @@ static const char *nth_line(void *data, long line)
 
 		if (parse_range_arg(range_part, nth_line, &cb_data,
 				    lines, &begin, &end,
-				    spec->path))
+				    full_name))
 			die("malformed -L argument '%s'", range_part);
 		if (begin < 1)
 			begin = 1;
@@ -593,8 +597,9 @@ static const char *nth_line(void *data, long line)
 		begin--;
 		if (lines < end || lines < begin)
 			die("file %s has only %ld lines", name_part, lines);
-		line_log_data_insert(&ranges, spec, begin, end);
+		line_log_data_insert(&ranges, full_name, begin, end);
 
+		free_filespec(spec);
 		free(ends);
 		ends = NULL;
 	}
@@ -610,9 +615,7 @@ static struct line_log_data *line_log_data_copy_one(struct line_log_data *r)
 	line_log_data_init(ret);
 	range_set_copy(&ret->ranges, &r->ranges);
 
-	ret->spec = r->spec;
-	assert(ret->spec);
-	ret->spec->count++;
+	ret->path = xstrdup(r->path);
 
 	return ret;
 }
@@ -652,7 +655,7 @@ static struct line_log_data *line_log_data_merge(struct line_log_data *a,
 		else if (!b)
 			cmp = -1;
 		else
-			cmp = strcmp(a->spec->path, b->spec->path);
+			cmp = strcmp(a->path, b->path);
 		if (cmp < 0) {
 			src = a;
 			a = a->next;
@@ -667,8 +670,7 @@ static struct line_log_data *line_log_data_merge(struct line_log_data *a,
 		}
 		d = xmalloc(sizeof(struct line_log_data));
 		line_log_data_init(d);
-		d->spec = src->spec;
-		d->spec->count++;
+		d->path = xstrdup(src->path);
 		*pp = d;
 		pp = &d->next;
 		if (src2)
@@ -741,7 +743,7 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list
 		paths = xmalloc((count+1)*sizeof(char *));
 		r = range;
 		for (i = 0; i < count; i++) {
-			paths[i] = xstrdup(r->spec->path);
+			paths[i] = xstrdup(r->path);
 			r = r->next;
 		}
 		paths[count] = NULL;
@@ -797,7 +799,7 @@ static void filter_diffs_for_paths(struct line_log_data *range, int keep_deletio
 			continue;
 		}
 		for (rg = range; rg; rg = rg->next) {
-			if (!strcmp(rg->spec->path, p->two->path))
+			if (!strcmp(rg->path, p->two->path))
 				break;
 		}
 		if (rg)
@@ -1021,8 +1023,8 @@ static int process_diff_filepair(struct rev_info *rev,
 
 	assert(pair->two->path);
 	while (rg) {
-		assert(rg->spec->path);
-		if (!strcmp(rg->spec->path, pair->two->path))
+		assert(rg->path);
+		if (!strcmp(rg->path, pair->two->path))
 			break;
 		rg = rg->next;
 	}
@@ -1050,7 +1052,8 @@ static int process_diff_filepair(struct rev_info *rev,
 	collect_diff(&file_parent, &file_target, &diff);
 
 	/* NEEDSWORK should apply some heuristics to prevent mismatches */
-	rg->spec->path = xstrdup(pair->one->path);
+	free(rg->path);
+	rg->path = xstrdup(pair->one->path);
 
 	range_set_init(&tmp, 0);
 	range_set_map_across_diff(&tmp, &rg->ranges, &diff, diff_out);
@@ -1096,7 +1099,7 @@ static int process_all_files(struct line_log_data **range_out,
 			struct line_log_data *rg = range;
 			changed++;
 			/* NEEDSWORK tramples over data structures not owned here */
-			while (rg && strcmp(rg->spec->path, queue->queue[i]->two->path))
+			while (rg && strcmp(rg->path, queue->queue[i]->two->path))
 				rg = rg->next;
 			assert(rg);
 			rg->pair = diff_filepair_dup(queue->queue[i]);
diff --git a/line-log.h b/line-log.h
index 9acd123..8bea45f 100644
--- a/line-log.h
+++ b/line-log.h
@@ -26,10 +26,14 @@ struct diff_ranges {
 };
 
 /* Linked list of interesting files and their associated ranges.  The
- * list must be kept sorted by spec->path */
+ * list must be kept sorted by path.
+ *
+ * For simplicity, even though this is highly redundant, each
+ * line_log_data owns its 'path'.
+ */
 struct line_log_data {
 	struct line_log_data *next;
-	struct diff_filespec *spec;
+	char *path;
 	char status;
 	struct range_set ranges;
 	int arg_alloc, arg_nr;
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index bba0b09..7776f93 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -45,7 +45,7 @@ canned_test "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple" two-ranges
 canned_test "-L 24,+1:a.c simple" vanishes-early
 
 canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f
-canned_test_failure "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main
+canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main
 
 canned_test "-L 4,12:a.c -L :main:a.c simple" multiple
 canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping
-- 
1.8.2.1.567.g8ad0f43
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help