Junio C Hamano <gitster@xxxxxxxxx> 于2021年1月22日周五 上午4:45写道: > > 胡哲宁 <adlternative@xxxxxxxxx> writes: > > >> 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 :) > >> > >> > 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"?