checkout: print something when checking out paths

One of the problems with "git checkout" is that it does so many different things and could confuse people specially when we fail to handle ambiguation correctly. One way to help with that is tell the user what sort of operation is actually carried out. When switching branches, we always print something unless --quiet, either - "HEAD is now at ..." - "Reset branch ..." - "Already on ..." - "Switched to and reset ..." - "Switched to a new branch ..." - "Switched to branch ..." Checking out paths however is silent. Print something so that if we got the user intention wrong, they won't waste too much time to find that out. For the remaining cases of checkout we now print either - "Checked out ... paths out of the index" - "Checked out ... paths out of <abbrev hash>" Since the purpose of printing this is to help disambiguate. Only do it when "--" is missing. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Nov 13, 2018 at 19:28 UTC 0f086e6dcabfbf059e7483ebd7d41080faec3d77
7 files changed +49 -21
apply.c
+2 -1
@@ -3352,7 +3352,8 @@ static int checkout_target(struct index_state *istate,
3352
3353 costate.refresh_cache = 1;
3354 costate.istate = istate;
3355 - if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
3355 + if (checkout_entry(ce, &costate, NULL, NULL) ||
3356 + lstat(ce->name, st))
3357 return error(_("cannot checkout %s"), ce->name);
3358 return 0;
3359 }
builtin/checkout-index.c
+4 -2
@@ -67,7 +67,8 @@ static int checkout_file(const char *name, const char *prefix)
67 continue;
68 did_checkout = 1;
69 if (checkout_entry(ce, &state,
70 - to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
70 + to_tempfile ? topath[ce_stage(ce)] : NULL,
71 + NULL) < 0)
72 errs++;
73 }
74
@@ -111,7 +112,8 @@ static void checkout_all(const char *prefix, int prefix_length)
112 write_tempfile_record(last_ce->name, prefix);
113 }
114 if (checkout_entry(ce, &state,
114 - to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
115 + to_tempfile ? topath[ce_stage(ce)] : NULL,
116 + NULL) < 0)
117 errs++;
118 last_ce = ce;
119 }
builtin/checkout.c
+31 -8
@@ -44,6 +44,7 @@ struct checkout_opts {
44 int ignore_skipworktree;
45 int ignore_other_worktrees;
46 int show_progress;
47 + int count_checkout_paths;
48 /*
49 * If new checkout options are added, skip_merge_working_tree
50 * should be updated accordingly.
@@ -165,12 +166,13 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)
166 }
167
168 static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
168 - const struct checkout *state)
169 + const struct checkout *state, int *nr_checkouts)
170 {
171 while (pos < active_nr &&
172 !strcmp(active_cache[pos]->name, ce->name)) {
173 if (ce_stage(active_cache[pos]) == stage)
173 - return checkout_entry(active_cache[pos], state, NULL);
174 + return checkout_entry(active_cache[pos], state,
175 + NULL, nr_checkouts);
176 pos++;
177 }
178 if (stage == 2)
@@ -179,7 +181,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
181 return error(_("path '%s' does not have their version"), ce->name);
182 }
183
182 -static int checkout_merged(int pos, const struct checkout *state)
184 +static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts)
185 {
186 struct cache_entry *ce = active_cache[pos];
187 const char *path = ce->name;
@@ -242,7 +244,7 @@ static int checkout_merged(int pos, const struct checkout *state)
244 ce = make_transient_cache_entry(mode, &oid, path, 2);
245 if (!ce)
246 die(_("make_cache_entry failed for path '%s'"), path);
245 - status = checkout_entry(ce, state, NULL);
247 + status = checkout_entry(ce, state, NULL, nr_checkouts);
248 discard_cache_entry(ce);
249 return status;
250 }
@@ -257,6 +259,7 @@ static int checkout_paths(const struct checkout_opts *opts,
259 struct commit *head;
260 int errs = 0;
261 struct lock_file lock_file = LOCK_INIT;
262 + int nr_checkouts = 0;
263
264 if (opts->track != BRANCH_TRACK_UNSPECIFIED)
265 die(_("'%s' cannot be used with updating paths"), "--track");
@@ -371,17 +374,36 @@ static int checkout_paths(const struct checkout_opts *opts,
374 struct cache_entry *ce = active_cache[pos];
375 if (ce->ce_flags & CE_MATCHED) {
376 if (!ce_stage(ce)) {
374 - errs |= checkout_entry(ce, &state, NULL);
377 + errs |= checkout_entry(ce, &state,
378 + NULL, &nr_checkouts);
379 continue;
380 }
381 if (opts->writeout_stage)
378 - errs |= checkout_stage(opts->writeout_stage, ce, pos, &state);
382 + errs |= checkout_stage(opts->writeout_stage,
383 + ce, pos,
384 + &state, &nr_checkouts);
385 else if (opts->merge)
380 - errs |= checkout_merged(pos, &state);
386 + errs |= checkout_merged(pos, &state,
387 + &nr_checkouts);
388 pos = skip_same_name(ce, pos) - 1;
389 }
390 }
384 - errs |= finish_delayed_checkout(&state);
391 + errs |= finish_delayed_checkout(&state, &nr_checkouts);
392 +
393 + if (opts->count_checkout_paths) {
394 + if (opts->source_tree)
395 + fprintf_ln(stderr, Q_("Checked out %d path out of %s",
396 + "Checked out %d paths out of %s",
397 + nr_checkouts),
398 + nr_checkouts,
399 + find_unique_abbrev(&opts->source_tree->object.oid,
400 + DEFAULT_ABBREV));
401 + else
402 + fprintf_ln(stderr, Q_("Checked out %d path out of the index",
403 + "Checked out %d paths out of the index",
404 + nr_checkouts),
405 + nr_checkouts);
406 + }
407
408 if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
409 die(_("unable to write new index file"));
@@ -1064,6 +1086,7 @@ static int parse_branchname_arg(int argc, const char **argv,
1086 has_dash_dash = 1; /* case (3) or (1) */
1087 else if (dash_dash_pos >= 2)
1088 die(_("only one reference expected, %d given."), dash_dash_pos);
1089 + opts->count_checkout_paths = !opts->quiet && !has_dash_dash;
1090
1091 if (!strcmp(arg, "-"))
1092 arg = "@{-1}";
builtin/difftool.c
+1 -1
@@ -323,7 +323,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,
323 int ret;
324
325 ce = make_transient_cache_entry(mode, oid, path, 0);
326 - ret = checkout_entry(ce, state, NULL);
326 + ret = checkout_entry(ce, state, NULL, NULL);
327
328 discard_cache_entry(ce);
329 return ret;
cache.h
+2 -2
@@ -1539,9 +1539,9 @@ struct checkout {
1539 #define CHECKOUT_INIT { NULL, "" }
1540
1541 #define TEMPORARY_FILENAME_LENGTH 25
1542 -extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
1542 +extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts);
1543 extern void enable_delayed_checkout(struct checkout *state);
1544 -extern int finish_delayed_checkout(struct checkout *state);
1544 +extern int finish_delayed_checkout(struct checkout *state, int *nr_checkouts);
1545
1546 struct cache_def {
1547 struct strbuf path;
entry.c
+6 -4
@@ -161,7 +161,7 @@ static int remove_available_paths(struct string_list_item *item, void *cb_data)
161 return !available;
162 }
163
164 -int finish_delayed_checkout(struct checkout *state)
164 +int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
165 {
166 int errs = 0;
167 unsigned delayed_object_count;
@@ -226,7 +226,7 @@ int finish_delayed_checkout(struct checkout *state)
226 ce = index_file_exists(state->istate, path->string,
227 strlen(path->string), 0);
228 if (ce) {
229 - errs |= checkout_entry(ce, state, NULL);
229 + errs |= checkout_entry(ce, state, NULL, nr_checkouts);
230 filtered_bytes += ce->ce_stat_data.sd_size;
231 display_throughput(progress, filtered_bytes);
232 } else
@@ -435,8 +435,8 @@ static void mark_colliding_entries(const struct checkout *state,
435 * its name is returned in topath[], which must be able to hold at
436 * least TEMPORARY_FILENAME_LENGTH bytes long.
437 */
438 -int checkout_entry(struct cache_entry *ce,
439 - const struct checkout *state, char *topath)
438 +int checkout_entry(struct cache_entry *ce, const struct checkout *state,
439 + char *topath, int *nr_checkouts)
440 {
441 static struct strbuf path = STRBUF_INIT;
442 struct stat st;
@@ -506,5 +506,7 @@ int checkout_entry(struct cache_entry *ce,
506 return 0;
507
508 create_directories(path.buf, path.len, state);
509 + if (nr_checkouts)
510 + (*nr_checkouts)++;
511 return write_entry(ce, path.buf, state, 0);
512 }
unpack-trees.c
+3 -3
@@ -294,7 +294,7 @@ static void load_gitmodules_file(struct index_state *index,
294 repo_read_gitmodules(the_repository);
295 } else if (state && (ce->ce_flags & CE_UPDATE)) {
296 submodule_free(the_repository);
297 - checkout_entry(ce, state, NULL);
297 + checkout_entry(ce, state, NULL, NULL);
298 repo_read_gitmodules(the_repository);
299 }
300 }
@@ -450,12 +450,12 @@ static int check_updates(struct unpack_trees_options *o)
450 display_progress(progress, ++cnt);
451 ce->ce_flags &= ~CE_UPDATE;
452 if (o->update && !o->dry_run) {
453 - errs |= checkout_entry(ce, &state, NULL);
453 + errs |= checkout_entry(ce, &state, NULL, NULL);
454 }
455 }
456 }
457 stop_progress(&progress);
458 - errs |= finish_delayed_checkout(&state);
458 + errs |= finish_delayed_checkout(&state, NULL);
459 if (o->update)
460 git_attr_set_direction(GIT_ATTR_CHECKIN);
461