Re: [PATCH v5 3/3] ls-files.c: add --deduplicate option
From: 胡哲宁 <hidden>
Date: 2021-01-22 10:25:22
Junio C Hamano [off-list ref] 于2021年1月22日周五 上午4:45写道:
胡哲宁 [off-list ref] writes:quoted
quoted
OK. When show_stage is set, skipping_duplicates is automatically turned off (and show_unmerged is automatically covered as it turns show_stage on automatically). So this feature has really become "are we showing only names, and if so, did we show an entry of the same name before?".Yeah,showing only names,so I yesterday ask such question :)quoted
quoted
if (!show_unmerged || ce_stage(ce)) show_ce(repo, dir, ce, fullname.buf, ce_stage(ce) ? tag_unmerged : (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached)); + if (show_cached && skipping_duplicates) + last_shown_ce = ce;The code that calls show_ce() belonging to a totally separate if() statement makes my stomach hurt---how are we going to guarantee that "last shown" really will keep track of what was shown last? Shouldn't the above be more like this? - if (!show_unmerged || ce_stage(ce)) + if (!show_unmerged || ce_stage(ce)) { show_ce(repo, dir, ce, fullname.buf, ce_stage(ce) ? tag_unmerged : (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached)); + last_shown_ce = ce; + }well,I am also thinking about this question :"last_shown_ce" is not true last shown ce,but may be If "last_shown_ce" truly seen every last shown ce ,We may need more cumbersome logic to make the program correct. I have tried the processing method of your above code before, but found that some errors may have occurred.I think judicious use of "goto" without introducing the last_shown would probably result in a much more maintainable code. It may look somewhat like so: for (i = 0; i < repo->index->cache_nr; i++) { const struct cache_entry *ce = repo->index->cache[i]; struct stat st; int stat_err; construct_fullname(&fullname, repo, ce); if ((dir->flags & DIR_SHOW_IGNORED) && !ce_excluded(dir, repo->index, fullname.buf, ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; if ((show_cached || show_stage) && (!show_unmerged || ce_stage(ce))) { show_ce(repo, dir, ce, fullname.buf, ce_stage(ce) ? tag_unmerged : (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached)); if (skip_duplicates) goto skip_to_next_name; } if (!show_deleted && !show_modified) continue; if (ce_skip_worktree(ce)) continue; stat_err = lstat(fullname.buf, &st); if (stat_err && (errno != ENOENT && errno != ENOTDIR)) error_errno("cannot lstat '%s'", fullname.buf); if (show_deleted) { show_ce(repo, dir, ce, fullname.buf, tag_removed); if (skip_duplicates) goto skip_to_next_name; } if (show_modified && (stat_err || ie_modified(repo->index, ce, &st, 0))) show_ce(repo, dir, ce, fullname.buf, tag_modified); continue; skip_to_next_name: { int j; const struct cache_entry **cache = repo->index->cache; for (j = i + 1; j < repo->index->cache_nr; j++) if (strcmp(ce->ce_name, cache[j]->ce_name)) break; i = j - 1; /* compensate for outer for loop */ } }
I have to admit that this is indeed a good way to skip with "goto". Thanks for your help. And should I still use gitgitgadget PR on my origin branch "dedup"or send patch on branch "zh/ls-files-deduplicate"?