Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
git
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security
Insights
Files
abcb865
Documentation
block-sha1
builtin
compat
contrib
ewah
git-gui
gitk-git
gitweb
mergetools
perl
po
ppc
t
templates
vcs-svn
xdiff
.gitattributes
.gitignore
.mailmap
COPYING
GIT-VERSION-GEN
INSTALL
LGPL-2.1
Makefile
README
RelNotes
abspath.c
aclocal.m4
advice.c
advice.h
alias.c
alloc.c
archive-tar.c
archive-zip.c
archive.c
archive.h
argv-array.c
argv-array.h
attr.c
attr.h
base85.c
bisect.c
bisect.h
blob.c
blob.h
branch.c
branch.h
builtin.h
bulk-checkin.c
bulk-checkin.h
bundle.c
bundle.h
cache-tree.c
cache-tree.h
cache.h
check-builtins.sh
check-racy.c
check_bindir
color.c
color.h
column.c
column.h
combine-diff.c
command-list.txt
commit-slab.h
commit.c
commit.h
config.c
config.mak.in
config.mak.uname
configure.ac
connect.c
connect.h
connected.c
connected.h
convert.c
convert.h
copy.c
credential-cache--daemon.c
credential-cache.c
credential-store.c
credential.c
credential.h
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
decorate.c
decorate.h
delta.h
diff-delta.c
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
dir.c
dir.h
editor.c
entry.c
environment.c
exec_cmd.c
exec_cmd.h
fast-import.c
fetch-pack.c
fetch-pack.h
fmt-merge-msg.h
fsck.c
fsck.h
generate-cmdlist.sh
gettext.c
gettext.h
git-add--interactive.perl
git-am.sh
git-archimport.perl
git-bisect.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-difftool--helper.sh
git-difftool.perl
git-filter-branch.sh
git-instaweb.sh
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-resolve.sh
git-mergetool--lib.sh
git-mergetool.sh
git-p4.py
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
git-relink.perl
git-remote-testgit.sh
git-request-pull.sh
git-send-email.perl
git-sh-i18n.sh
git-sh-setup.sh
git-stash.sh
git-submodule.sh
git-svn.perl
git-web--browse.sh
git.c
git.rc
git.spec.in
gpg-interface.c
gpg-interface.h
graph.c
graph.h
grep.c
grep.h
hashmap.c
hashmap.h
help.c
help.h
hex.c
http-backend.c
http-fetch.c
http-push.c
http-walker.c
http.c
http.h
ident.c
imap-send.c
khash.h
kwset.c
kwset.h
levenshtein.c
levenshtein.h
line-log.c
line-log.h
line-range.c
line-range.h
list-objects.c
list-objects.h
ll-merge.c
ll-merge.h
lockfile.c
log-tree.c
log-tree.h
mailmap.c
mailmap.h
match-trees.c
merge-blobs.c
merge-blobs.h
merge-recursive.c
merge-recursive.h
merge.c
mergesort.c
mergesort.h
name-hash.c
notes-cache.c
notes-cache.h
notes-merge.c
notes-merge.h
notes-utils.c
notes-utils.h
notes.c
notes.h
object.c
object.h
pack-bitmap-write.c
pack-bitmap.c
pack-bitmap.h
pack-check.c
pack-objects.c
pack-objects.h
pack-revindex.c
pack-revindex.h
pack-write.c
pack.h
pager.c
parse-options-cb.c
parse-options.c
parse-options.h
patch-delta.c
patch-ids.c
patch-ids.h
path.c
pathspec.c
pathspec.h
pkt-line.c
pkt-line.h
preload-index.c
pretty.c
prio-queue.c
prio-queue.h
progress.c
progress.h
prompt.c
prompt.h
quote.c
quote.h
reachable.c
reachable.h
read-cache.c
reflog-walk.c
reflog-walk.h
refs.c
refs.h
remote-curl.c
remote-testsvn.c
remote.c
remote.h
replace_object.c
rerere.c
rerere.h
resolve-undo.c
resolve-undo.h
revision.c
revision.h
run-command.c
run-command.h
send-pack.c
send-pack.h
sequencer.c
sequencer.h
server-info.c
setup.c
sh-i18n--envsubst.c
sha1-array.c
sha1-array.h
sha1-lookup.c
sha1-lookup.h
sha1_file.c
sha1_name.c
shallow.c
shell.c
shortlog.h
show-index.c
sideband.c
sideband.h
sigchain.c
sigchain.h
split-index.c
split-index.h
strbuf.c
strbuf.h
streaming.c
streaming.h
string-list.c
string-list.h
submodule.c
submodule.h
symlinks.c
tag.c
tag.h
tar.h
test-chmtime.c
test-config.c
test-ctype.c
test-date.c
test-delta.c
test-dump-cache-tree.c
test-dump-split-index.c
test-genrandom.c
test-hashmap.c
test-index-version.c
test-line-buffer.c
test-match-trees.c
test-mergesort.c
test-mktemp.c
test-parse-options.c
test-path-utils.c
test-prio-queue.c
test-read-cache.c
test-regex.c
test-revision-walking.c
test-run-command.c
test-scrap-cache-tree.c
test-sha1.c
test-sha1.sh
test-sigchain.c
test-string-list.c
test-subprocess.c
test-svn-fe.c
test-urlmatch-normalization.c
test-wildmatch.c
thread-utils.c
thread-utils.h
trace.c
trace.h
transport-helper.c
transport.c
transport.h
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unicode_width.h
unimplemented.sh
unix-socket.c
unix-socket.h
unpack-trees.c
unpack-trees.h
update_unicode.sh
upload-pack.c
url.c
url.h
urlmatch.c
urlmatch.h
usage.c
userdiff.c
userdiff.h
utf8.c
utf8.h
varint.c
varint.h
version.c
version.h
versioncmp.c
walker.c
walker.h
wildmatch.c
wildmatch.h
wrap-for-bin.sh
wrapper.c
write_or_die.c
ws.c
wt-status.c
wt-status.h
xdiff-interface.c
xdiff-interface.h
zlib.c
Breadcrumbs
git
/
diffcore-break.c
Blame
Blame
Latest commit
History
History
297 lines (265 loc) · 8.77 KB
Breadcrumbs
git
/
diffcore-break.c
Top
File metadata and controls
Code
Blame
297 lines (265 loc) · 8.77 KB
Raw
/* * Copyright (C) 2005 Junio C Hamano */ #include "cache.h" #include "diff.h" #include "diffcore.h" static int should_break(struct diff_filespec *src, struct diff_filespec *dst, int break_score, int *merge_score_p) { /* dst is recorded as a modification of src. Are they so * different that we are better off recording this as a pair * of delete and create? * * There are two criteria used in this algorithm. For the * purposes of helping later rename/copy, we take both delete * and insert into account and estimate the amount of "edit". * If the edit is very large, we break this pair so that * rename/copy can pick the pieces up to match with other * files. * * On the other hand, we would want to ignore inserts for the * pure "complete rewrite" detection. As long as most of the * existing contents were removed from the file, it is a * complete rewrite, and if sizable chunk from the original * still remains in the result, it is not a rewrite. It does * not matter how much or how little new material is added to * the file. * * The score we leave for such a broken filepair uses the * latter definition so that later clean-up stage can find the * pieces that should not have been broken according to the * latter definition after rename/copy runs, and merge the * broken pair that have a score lower than given criteria * back together. The break operation itself happens * according to the former definition. * * The minimum_edit parameter tells us when to break (the * amount of "edit" required for us to consider breaking the * pair). We leave the amount of deletion in *merge_score_p * when we return. * * The value we return is 1 if we want the pair to be broken, * or 0 if we do not. */ unsigned long delta_size, max_size; unsigned long src_copied, literal_added, src_removed; *merge_score_p = 0; /* assume no deletion --- "do not break" * is the default. */ if (S_ISREG(src->mode) != S_ISREG(dst->mode)) { *merge_score_p = (int)MAX_SCORE; return 1; /* even their types are different */ } if (src->sha1_valid && dst->sha1_valid && !hashcmp(src->sha1, dst->sha1)) return 0; /* they are the same */ if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) return 0; /* error but caught downstream */ max_size = ((src->size > dst->size) ? src->size : dst->size); if (max_size < MINIMUM_BREAK_SIZE) return 0; /* we do not break too small filepair */ if (!src->size) return 0; /* we do not let empty files get renamed */ if (diffcore_count_changes(src, dst, &src->cnt_data, &dst->cnt_data, 0, &src_copied, &literal_added)) return 0; /* sanity */ if (src->size < src_copied) src_copied = src->size; if (dst->size < literal_added + src_copied) { if (src_copied < dst->size) literal_added = dst->size - src_copied; else literal_added = 0; } src_removed = src->size - src_copied; /* Compute merge-score, which is "how much is removed * from the source material". The clean-up stage will * merge the surviving pair together if the score is * less than the minimum, after rename/copy runs. */ *merge_score_p = (int)(src_removed * MAX_SCORE / src->size); if (*merge_score_p > break_score) return 1; /* Extent of damage, which counts both inserts and * deletes. */ delta_size = src_removed + literal_added; if (delta_size * MAX_SCORE / max_size < break_score) return 0; /* If you removed a lot without adding new material, that is * not really a rewrite. */ if ((src->size * break_score < src_removed * MAX_SCORE) && (literal_added * 20 < src_removed) && (literal_added * 20 < src_copied)) return 0; return 1; } void diffcore_break(int break_score) { struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; /* When the filepair has this much edit (insert and delete), * it is first considered to be a rewrite and broken into a * create and delete filepair. This is to help breaking a * file that had too much new stuff added, possibly from * moving contents from another file, so that rename/copy can * match it with the other file. * * int break_score; we reuse incoming parameter for this. */ /* After a pair is broken according to break_score and * subjected to rename/copy, both of them may survive intact, * due to lack of suitable rename/copy peer. Or, the caller * may be calling us without using rename/copy. When that * happens, we merge the broken pieces back into one * modification together if the pair did not have more than * this much delete. For this computation, we do not take * insert into account at all. If you start from a 100-line * file and delete 97 lines of it, it does not matter if you * add 27 lines to it to make a new 30-line file or if you add * 997 lines to it to make a 1000-line file. Either way what * you did was a rewrite of 97%. On the other hand, if you * delete 3 lines, keeping 97 lines intact, it does not matter * if you add 3 lines to it to make a new 100-line file or if * you add 903 lines to it to make a new 1000-line file. * Either way you did a lot of additions and not a rewrite. * This merge happens to catch the latter case. A merge_score * of 80% would be a good default value (a broken pair that * has score lower than merge_score will be merged back * together). */ int merge_score; int i; /* See comment on DEFAULT_BREAK_SCORE and * DEFAULT_MERGE_SCORE in diffcore.h */ merge_score = (break_score >> 16) & 0xFFFF; break_score = (break_score & 0xFFFF); if (!break_score) break_score = DEFAULT_BREAK_SCORE; if (!merge_score) merge_score = DEFAULT_MERGE_SCORE; DIFF_QUEUE_CLEAR(&outq); for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; int score; /* * We deal only with in-place edit of blobs. * We do not break anything else. */ if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two) && object_type(p->one->mode) == OBJ_BLOB && object_type(p->two->mode) == OBJ_BLOB && !strcmp(p->one->path, p->two->path)) { if (should_break(p->one, p->two, break_score, &score)) { /* Split this into delete and create */ struct diff_filespec *null_one, *null_two; struct diff_filepair *dp; /* Set score to 0 for the pair that * needs to be merged back together * should they survive rename/copy. * Also we do not want to break very * small files. */ if (score < merge_score) score = 0; /* deletion of one */ null_one = alloc_filespec(p->one->path); dp = diff_queue(&outq, p->one, null_one); dp->score = score; dp->broken_pair = 1; /* creation of two */ null_two = alloc_filespec(p->two->path); dp = diff_queue(&outq, null_two, p->two); dp->score = score; dp->broken_pair = 1; diff_free_filespec_blob(p->one); diff_free_filespec_blob(p->two); free(p); /* not diff_free_filepair(), we are * reusing one and two here. */ continue; } } diff_free_filespec_data(p->one); diff_free_filespec_data(p->two); diff_q(&outq, p); } free(q->queue); *q = outq; return; } static void merge_broken(struct diff_filepair *p, struct diff_filepair *pp, struct diff_queue_struct *outq) { /* p and pp are broken pairs we want to merge */ struct diff_filepair *c = p, *d = pp, *dp; if (DIFF_FILE_VALID(p->one)) { /* this must be a delete half */ d = p; c = pp; } /* Sanity check */ if (!DIFF_FILE_VALID(d->one)) die("internal error in merge #1"); if (DIFF_FILE_VALID(d->two)) die("internal error in merge #2"); if (DIFF_FILE_VALID(c->one)) die("internal error in merge #3"); if (!DIFF_FILE_VALID(c->two)) die("internal error in merge #4"); dp = diff_queue(outq, d->one, c->two); dp->score = p->score; diff_free_filespec_data(d->two); diff_free_filespec_data(c->one); free(d); free(c); } void diffcore_merge_broken(void) { struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; int i, j; DIFF_QUEUE_CLEAR(&outq); for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (!p) /* we already merged this with its peer */ continue; else if (p->broken_pair && !strcmp(p->one->path, p->two->path)) { /* If the peer also survived rename/copy, then * we merge them back together. */ for (j = i + 1; j < q->nr; j++) { struct diff_filepair *pp = q->queue[j]; if (pp->broken_pair && !strcmp(pp->one->path, pp->two->path) && !strcmp(p->one->path, pp->two->path)) { /* Peer survived. Merge them */ merge_broken(p, pp, &outq); q->queue[j] = NULL; break; } } if (q->nr <= j) /* The peer did not survive, so we keep * it in the output. */ diff_q(&outq, p); } else diff_q(&outq, p); } free(q->queue); *q = outq; return; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
You can’t perform that action at this time.