From: Junio C Hamano <hidden> Date: 2016-06-15 22:51:00
Linus Torvalds [off-list ref] writes:
On Fri, Apr 8, 2011 at 7:46 AM, Johan Herland [off-list ref] wrote:
quoted
#2: Improve --dirstat-by-file. It doesn't really care about the per-file
analysis done by --dirstat, but only whether or not a file has changed
at all. Since the diff queue does not contain unchanged files (<- this
is an assumption that I hope someone with more diffcore knowledge can
verify),
Hmm.
I think that with renames, the diff queue _can_ contain unchanged
files (ie pure renames).
Also, I think -CC (aka --find-copies-harder), _every_ file ends up in
the diff queue because that's how it does the detection.
Both are correct, but the output phase happens after diffcore_std() cleans
up the unused and unchanged filepairs thrown into the queue for the
purpose of find-copies-harder, so you shouldn't have to worry about them.
When you rename a file without changing its contents, what do you want to
see in --dirstat-by-file output? I assume that you do not want to show
anything, so it would be sufficient to compare the two object names.
From: Johan Herland <hidden> Date: 2016-06-15 22:51:01
Here's a reroll of the previous series. Changes since v1:
- Adopt Junio's phrasing of the differences between --dirstat and
regular diff (--stat)
- Detect and ignore pure renames in the diff queue. This is done by
comparing the SHA1s of each file pair, and if they are equal, we
know the files are identical, and should not show up in --dirstat.
As an extra bonus in this version, when the SHA1s do match, we can
bypass the usual --dirstat analysis, because we know it would find
no changes. Instead, we can directly set damage = 0 in that case.
I've looked at the contents of the diff queue and resulting output in
a variety of cases:
- files with no changes, rearranged lines, and other changes
- files that are copied, moved, or not moved
- unstaged changes, staged changes, committed changes
- diff options: (none), --stat, --dirstat, and --dirstat-by-file
- diff options: (none), -M, and -C -C
(324 variations in total) and I'm fairly sure about the current patches
and how they interact with the diff queue.
A remaining question AFAICS is if there's a different (i.e. better) way
to (cheaply) estimate the damage contributed by code movements within a
file. The current "damage = 1" approach is somewhat crude, but IMHO
still better that ignoring code movements altogether.
Have fun! :)
...Johan
Johan Herland (3):
--dirstat: Describe non-obvious differences relative to --stat or regular diff
--dirstat-by-file: Make it faster and more correct
Teach --dirstat to not completely ignore rearranged lines within a file
Documentation/diff-options.txt | 4 ++
diff.c | 40 ++++++++++++++++++--
t/t4013-diff-various.sh | 27 ++++++++++---
.../diff.diff_--dirstat-by-file_initial_rearrange | 3 +
t/t4013/diff.diff_--dirstat_initial_rearrange | 3 +
...tch_--stdout_--cover-letter_-n_initial..master^ | 2 +-
t/t4013/diff.log_--decorate=full_--all | 6 +++
t/t4013/diff.log_--decorate_--all | 6 +++
8 files changed, 80 insertions(+), 11 deletions(-)
create mode 100644 t/t4013/diff.diff_--dirstat-by-file_initial_rearrange
create mode 100644 t/t4013/diff.diff_--dirstat_initial_rearrange
--
1.7.5.rc1.3.g4d7b
@@ -72,6 +72,10 @@ endif::git-format-patch[] a cut-off percent (3% by default) are not shown. The cut-off percent can be set with `--dirstat=<limit>`. Changes in a child directory are not counted for the parent directory, unless `--cumulative` is used.+++Note that the `--dirstat` option computes the changes while ignoring+pure code movements within a file. In other words, rearranging lines+in a file is not counted as a change. --dirstat-by-file[=<limit>]:: Same as `--dirstat`, but counts changed files instead of lines.
From: Johan Herland <hidden> Date: 2016-06-15 22:51:01
Currently, when using --dirstat-by-file, it first does the full --dirstat
analysis (using diffcore_count_changes()), and then resets 'damage' to 1,
if any damage was found by diffcore_count_changes().
But --dirstat-by-file is not interested in the file damage per se. It only
cares if the file changed at all. In that sense it only cares if the blob
SHA1 for a file has changed. We therefore only need to compare the SHA1s
of each file pair in the diff queue. As a result, we can skip the entire
--dirstat analysis and simply set 'damage' to 1 for each entry where the
SHA1 has changed.
This makes --dirstat-by-file faster, and also bypasses --dirstat's practice
of ignoring rearranged lines within a file.
The patch also contains an added testcase verifying that --dirstat-by-file
now detects changes that only rearrange lines within a file.
Signed-off-by: Johan Herland <redacted>
---
diff.c | 25 ++++++++++++++++----
t/t4013-diff-various.sh | 2 +
.../diff.diff_--dirstat-by-file_initial_rearrange | 3 ++
3 files changed, 25 insertions(+), 5 deletions(-)
create mode 100644 t/t4013/diff.diff_--dirstat-by-file_initial_rearrange
From: Johan Herland <hidden> Date: 2016-06-15 22:51:01
Currently, the --dirstat analysis fails to detect when lines within a
file are rearranged, because the "damage" calculated by show_dirstat()
is 0. However, if the SHA1 sum has changed, we already now that there
should be at least some minimum amount of damage.
This patch teaches show_dirstat() to assign a minimum amount of damage
(== 1) to entries for which the analysis otherwise yields zero damage.
Obviously this is not a complete fix, but it's at least better to
underrepresent these changes, rather than simply pretending that they
don't exist.
Also, with the added SHA1 comparison, we can safely skip the --dirstat
analysis when the SHA1s do happen to match (e.g. for a pure file rename)
Signed-off-by: Johan Herland <redacted>
---
Documentation/diff-options.txt | 4 ++--
diff.c | 19 ++++++++++++++++++-
t/t4013-diff-various.sh | 2 --
t/t4013/diff.diff_--dirstat_initial_rearrange | 1 +
4 files changed, 21 insertions(+), 5 deletions(-)
@@ -74,8 +74,8 @@ endif::git-format-patch[] counted for the parent directory, unless `--cumulative` is used. + Note that the `--dirstat` option computes the changes while ignoring-pure code movements within a file. In other words, rearranging lines-in a file is not counted as a change.+the amount of pure code movements within a file. In other words,+rearranging lines in a file is not counted as much as other changes. --dirstat-by-file[=<limit>]:: Same as `--dirstat`, but counts changed files instead of lines.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:51:01
Johan Herland [off-list ref] writes:
Currently, the --dirstat analysis fails to detect when lines within a
file are rearranged, because the "damage" calculated by show_dirstat()
is 0. However, if the SHA1 sum has changed, we already now that there
should be at least some minimum amount of damage.
This logic is sensible, modulo that "fails to detect" is actually "ignores
mere line movements on purpose".
In any case, if the object names are different, we already know that there
is _some_ damage, and it is very unintiutive to claim that there is _no_
damage.
This patch teaches show_dirstat() to assign a minimum amount of damage
(== 1) to entries for which the analysis otherwise yields zero damage.
So it is perfectly in line with the above logic to give a minimum here.
Zero was simply just unintuitive, and this is a good fix to the problem.
Obviously this is not a complete fix, but it's at least better to
I however do not understand what "a complete fix" means in this context.
You've fixed the unintuitiveness, and as far as the description in the
introductory paragraph of the problem goes, I think this already is a
complete fix.
From: Johan Herland <hidden> Date: 2016-06-15 22:51:01
On Monday 11 April 2011, Junio C Hamano wrote:
Johan Herland [off-list ref] writes:
quoted
Currently, the --dirstat analysis fails to detect when lines within a
file are rearranged, because the "damage" calculated by show_dirstat()
is 0. However, if the SHA1 sum has changed, we already now that there
should be at least some minimum amount of damage.
This logic is sensible, modulo that "fails to detect" is actually
"ignores mere line movements on purpose".
I apologize for my commit message not having caught up with discussion
around this issue. I came into the discussion from the POV of "--dirstat
does not pick up what --stat picks up; there must be a bug in --dirstat",
and my original objective was therefore to "fix" --dirstat to be "more like
--stat". Obviously, I now know exactly why --dirstat is different, and that
we don't want to fundamentally change it. My commit message should have been
rephrased in a more positive light as a result. Feel free to fix before
applying.
In any case, if the object names are different, we already know that
there is _some_ damage, and it is very unintiutive to claim that there
is _no_ damage.
Agreed.
quoted
This patch teaches show_dirstat() to assign a minimum amount of damage
(== 1) to entries for which the analysis otherwise yields zero damage.
So it is perfectly in line with the above logic to give a minimum here.
Zero was simply just unintuitive, and this is a good fix to the problem.
quoted
Obviously this is not a complete fix, but it's at least better to
I however do not understand what "a complete fix" means in this context.
You've fixed the unintuitiveness, and as far as the description in the
introductory paragraph of the problem goes, I think this already is a
complete fix.
I still feel that a file with 1000 rearranged lines should somehow count
"more" than a file with only 1 rearranged line, but it's hard to get there
without futzing with diffcore_count_changes(), probably making the whole
thing considerably more expensive... So in that sense, I agree that the
current solution is probably as complete as we can get.
...Johan
--
Johan Herland, [off-list ref]
www.herland.net