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

Re: [PATCH] git-gui: give more advice when detaching HEAD

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 17, 2011, 23:13 UTC
Message-ID
<7vvd0i8dbc.fsf@alter.siamese.dyndns.org>
In-Reply-To
<20110212082108.GA19656@sigill.intra.peff.net>
Jeff King <peff@peff.net> writes:
> Want to do a proof-of-concept patch? Then we can get some real timings.
This was about 
Show 5 quoted lines
> >   2. When leaving the detached state, notice that we have commits not
> >      contained in any other ref and pop up an "are you sure you want to
> >      lose these commits" dialog, with an option to create a branch. This
> >      is something we considered and rejected for the CLI, but I wonder
> >      if it makes more sense for git-gui.

I thought about counting remaining commits, but decided against it. The cost has already paid (the "limited" traversal already has happend), so it may not be too bad to show each of them in oneline format if somebody really wanted to to tell the user "here are the stuff you are about to lose".

Also it might make sense to have a training wheel option of forcing "checkout -f branch-I-wanted-to-go" in this case as an extra safety valve, and it would be even Ok to enable the training wheel by default, as long as annoyed experts can turn it off via configuration.

 builtin/checkout.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index cd7f56e..1f5376f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -503,6 +503,17 @@ static void detach_advice(const char *old_path, const char *new_name)
 	fprintf(stderr, fmt, new_name);
 }
 
+static void suggest_reattach(struct commit *commit)
+{
+	const char fmt[] =
+	"Note: you are about to abandon commit %1$s\n\n"
+	"None of your branches nor tags refer to this commit. If you want to\n"
+	"keep this commit, you can do so by creating a new branch. Example:\n\n"
+	" git branch new_branch_name %1$s\n\n";
+
+	fprintf(stderr, fmt, sha1_to_hex(commit->object.sha1));
+}
+
 static void update_refs_for_switch(struct checkout_opts *opts,
 				   struct branch_info *old,
 				   struct branch_info *new)
@@ -578,6 +589,54 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 		report_tracking(new);
 }
 
+struct rev_list_args {
+	int argc;
+	int alloc;
+	const char **argv;
+};
+
+static void add_one_rev_list_arg(struct rev_list_args *args, const char *s)
+{
+	ALLOC_GROW(args->argv, args->argc + 1, args->alloc);
+	args->argv[args->argc++] = s;
+}
+
+static int add_one_ref_to_rev_list_arg(const char *refname,
+				       const unsigned char *sha1,
+				       int flags,
+				       void *cb_data)
+{
+	add_one_rev_list_arg(cb_data, refname);
+	return 0;
+}
+
+/*
+ * We are about to leave commit that was at the tip of a detached
+ * HEAD.  If it is not reachable from any ref, this is the last chance
+ * for the user to do so without resorting to reflog.
+ */
+static void orphaned_commit_warning(struct commit *commit)
+{
+	struct rev_list_args args = { 0, 0, NULL };
+	struct rev_info revs;
+
+	add_one_rev_list_arg(&args, "(internal)");
+	add_one_rev_list_arg(&args, sha1_to_hex(commit->object.sha1));
+	add_one_rev_list_arg(&args, "--not");
+	for_each_ref(add_one_ref_to_rev_list_arg, &args);
+	add_one_rev_list_arg(&args, "--");
+	add_one_rev_list_arg(&args, NULL);
+
+	init_revisions(&revs, NULL);
+	if (setup_revisions(args.argc - 1, args.argv, &revs, NULL) != 1)
+		die("internal error: only -- alone should have been left");
+	if (prepare_revision_walk(&revs))
+		die("internal error in revision walk");
+	if (!(commit->object.flags & UNINTERESTING))
+		suggest_reattach(commit);
+	describe_detached_head("Previous HEAD position was", commit);
+}
+
 static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 {
 	int ret = 0;
@@ -605,13 +664,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	if (ret)
 		return ret;
 
-	/*
-	 * If we were on a detached HEAD, but have now moved to
-	 * a new commit, we want to mention the old commit once more
-	 * to remind the user that it might be lost.
-	 */
 	if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
-		describe_detached_head("Previous HEAD position was", old.commit);
+		orphaned_commit_warning(old.commit);
 
 	update_refs_for_switch(opts, &old, new);
 
Previous: Jeff KingNext: Junio C Hamano
Message 6 of 19 in “git-gui: give more advice when detaching HEAD”
  1. git-gui: give more advice when detaching HEADJeff King, Feb 12, 2011
  2. Junio C HamanoFeb 12, 2011
  3. Jeff KingFeb 12, 2011
  4. Junio C HamanoFeb 12, 2011
  5. Jeff KingFeb 12, 2011
  6. Junio C HamanoFeb 17, 2011
  7. Junio C HamanoFeb 12, 2011
  8. Sverre RabbelierFeb 13, 2011
  9. Johannes SixtFeb 13, 2011
  10. Junio C HamanoFeb 13, 2011
  11. Heiko VoigtFeb 13, 2011
  12. Jeff KingFeb 15, 2011
  13. Heiko VoigtFeb 15, 2011
  14. Pat ThoytsFeb 15, 2011
  15. Jeff KingFeb 16, 2011
  16. Heiko VoigtFeb 17, 2011
  17. Jeff KingFeb 16, 2011
  18. Heiko VoigtFeb 17, 2011
  19. Victor EngmarkFeb 16, 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.