git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [BUG] git checkout <branch> allowed with uncommitted changes

From
Junio C Hamano <gitster@pobox.com>
Date
Oct 16, 2011, 20:37 UTC
Message-ID
<7vy5wkptan.fsf@alter.siamese.dyndns.org>
In-Reply-To
<loom.20111016T201930-426@post.gmane.org>
arQon <arqon@gmx.com> writes:
> ... better *behavior* is a
> clear win either way.

I doubt the full status output is better behaviour. For one thing, you do not need full status as by definition branch switching would only have local changes as a result (i.e. you will not see "Changes to be committed" section).

But if you really do not want to learn how to read "diff --name-status" output, here is a patch to allow you say "git checkout -v other_branch". Hopefully it will help you convince yourself why it is not a better behaviour.

 builtin/checkout.c |   46 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 49a547a..0c21556 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -28,7 +28,7 @@ static const char * const checkout_usage[] = {
 };
 
 struct checkout_opts {
-	int quiet;
+	int verbosity;
 	int merge;
 	int force;
 	int force_detach;
@@ -291,10 +291,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
 	return errs;
 }
 
-static void show_local_changes(struct object *head, struct diff_options *opts)
+static void show_local_changes_brief(struct object *head, struct diff_options *opts)
 {
 	struct rev_info rev;
-	/* I think we want full paths, even if we're in a subdirectory. */
+
 	init_revisions(&rev, NULL);
 	rev.diffopt.flags = opts->flags;
 	rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
@@ -304,6 +304,26 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
 	run_diff_index(&rev, 0);
 }
 
+static void show_local_changes_status(void)
+{
+	const char *argv[] = { "status", NULL };
+
+	run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static void show_local_changes(struct checkout_opts *opts,
+			       struct object *head,
+			       struct diff_options *diffopts)
+{
+	if (opts->force || opts->verbosity < 0)
+		return;
+
+	if (0 < opts->verbosity)
+		show_local_changes_status();
+	else
+		show_local_changes_brief(head, diffopts);
+}
+
 static void describe_detached_head(const char *msg, struct commit *commit)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -326,7 +346,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
 	opts.reset = 1;
 	opts.merge = 1;
 	opts.fn = oneway_merge;
-	opts.verbose_update = !o->quiet;
+	opts.verbose_update = (0 <= o->verbosity);
 	opts.src_index = &the_index;
 	opts.dst_index = &the_index;
 	parse_tree(tree);
@@ -403,7 +423,7 @@ static int merge_working_tree(struct checkout_opts *opts,
 		topts.update = 1;
 		topts.merge = 1;
 		topts.gently = opts->merge && old->commit;
-		topts.verbose_update = !opts->quiet;
+		topts.verbose_update = (0 <= opts->verbosity);
 		topts.fn = twoway_merge;
 		topts.dir = xcalloc(1, sizeof(*topts.dir));
 		topts.dir->flags |= DIR_SHOW_IGNORED;
@@ -478,9 +498,6 @@ static int merge_working_tree(struct checkout_opts *opts,
 	    commit_locked_index(lock_file))
 		die(_("unable to write new index file"));
 
-	if (!opts->force && !opts->quiet)
-		show_local_changes(&new->commit->object, &opts->diff_options);
-
 	return 0;
 }
 
@@ -552,14 +569,14 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 	} else if (opts->force_detach || !new->path) {	/* No longer on any branch. */
 		update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 			   REF_NODEREF, DIE_ON_ERR);
-		if (!opts->quiet) {
+		if (0 <= opts->verbosity) {
 			if (old->path && advice_detached_head)
 				detach_advice(old->path, new->name);
 			describe_detached_head(_("HEAD is now at"), new->commit);
 		}
 	} else if (new->path) {	/* Switch branches. */
 		create_symref("HEAD", new->path, msg.buf);
-		if (!opts->quiet) {
+		if (0 <= opts->verbosity) {
 			if (old->path && !strcmp(new->path, old->path)) {
 				fprintf(stderr, _("Already on '%s'\n"),
 					new->name);
@@ -584,7 +601,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 	}
 	remove_branch_state();
 	strbuf_release(&msg);
-	if (!opts->quiet &&
+	if (0 <= opts->verbosity &&
 	    (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
 		report_tracking(new);
 }
@@ -717,13 +734,16 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	if (ret)
 		return ret;
 
-	if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
+	if (0 <= opts->verbosity && !old.path && old.commit && new->commit != old.commit)
 		orphaned_commit_warning(old.commit);
 
 	update_refs_for_switch(opts, &old, new);
 
 	ret = post_checkout_hook(old.commit, new->commit, 1);
 	free((char *)old.path);
+
+	show_local_changes(opts, &new->commit->object, &opts->diff_options);
+
 	return ret || opts->writeout_error;
 }
 
@@ -906,7 +926,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	int patch_mode = 0;
 	int dwim_new_local_branch = 1;
 	struct option options[] = {
-		OPT__QUIET(&opts.quiet, "suppress progress reporting"),
+		OPT__VERBOSITY(&opts.verbosity),
 		OPT_STRING('b', NULL, &opts.new_branch, "branch",
 			   "create and checkout a new branch"),
 		OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
Previous: arQonNext: Holger Hellmuth
Message 25 of 36 in “[BUG] git checkout <branch> allowed with uncommitted changes”
  1. arQonOct 13, 2011
  2. Nguyen Thai Ngoc DuyOct 13, 2011
  3. Alexey ShumkinOct 13, 2011
  4. arQonOct 13, 2011
  5. Andreas EricssonOct 13, 2011
  6. arQonOct 13, 2011
  7. Carlos Martín NietoOct 13, 2011
  8. arQonOct 13, 2011
  9. Alexey ShumkinOct 13, 2011
  10. Jakub NarebskiOct 13, 2011
  11. arQonOct 13, 2011
  12. Carlos Martín NietoOct 13, 2011
  13. arQonOct 13, 2011
  14. Alexey ShumkinOct 13, 2011
  15. Alexey ShumkinOct 14, 2011
  16. Holger HellmuthOct 13, 2011
  17. Carlos Martín NietoOct 13, 2011
  18. arQonOct 13, 2011
  19. Junio C HamanoOct 13, 2011
  20. arQonOct 13, 2011
  21. Jeff KingOct 14, 2011
  22. Holger HellmuthOct 14, 2011
  23. Victor EngmarkOct 14, 2011
  24. arQonOct 16, 2011
  25. Junio C HamanoOct 16, 2011
  26. Holger HellmuthOct 16, 2011
  27. Carlos Martín NietoOct 13, 2011
  28. Sergei OrganovOct 13, 2011
  29. PJ WeisbergOct 13, 2011
  30. Holger HellmuthOct 13, 2011
  31. arQonOct 13, 2011
  32. Holger HellmuthOct 13, 2011
  33. Victor EngmarkOct 13, 2011
  34. arQonOct 13, 2011
  35. Victor EngmarkOct 14, 2011
  36. Michael J GruberOct 13, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.