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

Re: [RFC] Detached-HEAD reminder on commit?

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 5, 2008, 23:43 UTC
Message-ID
<7vabemupjb.fsf@gitster.siamese.dyndns.org>
In-Reply-To
<7vbpz479zs.fsf@gitster.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
Show 31 quoted lines
> "Avery Pennarun" <apenwarr@gmail.com> writes:
> ...
>> 1) Checking out a remote branch "git checkout origin/master" detaches
>> my HEAD, which is kind of bad, since it's such a common thing to want
>> to do.
>
> I do not think it is bad at all.  The feature to detach HEAD was designed
> for that kind of usage.  Start sightseeing, possibly futz with the code,
> and even create some snapshot commits, and then:
>
>  * if it starts to take a usable shape, say "git checkout -b my-topic",
>    from there, to give your exploration a lasting home; or
>    
>  * if it doesn't pan out, just discard it with "git checkout -f master"
>    (or whatever you wanted to switch back to).
>
> One thing that might help for downstream people would be to be able to say
> "I am making 'my-topic' branch out of a detached HEAD, but it really is
> meant to be a fork of origin/master that I detached my HEAD from, so
> please set up tracking for that one".
>
> You could force people to say "git checkout -b my-topic origin/master"
> from the beginning, but that is very unreasonable and unworkable.  When
> you are exploring, you more often than not do not know where your quest
> would lead to until spending some time.  It is quite important to be able
> to delay the decision to create a local branch to keep what you did, and
> (more importantly) to be able to delay deciding what to name that topic.
>
> Perhaps "git checkout -b my-topic" from a detached HEAD should inspect the
> HEAD reflog to see which remote (or local) branch you came from, and give
> that to the --track logic.
So here is a patch for discussion, not heavily tested, but:
	$ git checkout origin/master
        $ git commit; hack hack hack ...
        $ git checkout --track -b mybranch

sequence should result in mybranch tracking the 'master' branch from the 'origin'.

The patch is just a proof of concept; doing this for HEAD reflog that is several megabytes long might take nontrivial amount of time (at least from performance standard of git); if we wanted to go this route, we should add an API to read the reflog entries from more recent to older.

 branch.c |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)
diff --git c/branch.c w/branch.c
index b1e59f2..2ec6418 100644
--- c/branch.c
+++ w/branch.c
@@ -48,6 +48,62 @@ static int should_setup_rebase(const struct tracking *tracking)
 }
 
 /*
+ * A branch is created out of "HEAD" and we would want tracking;
+ * go back the reflog to figure out where we really came from.
+ */
+static int refine_head_one(const char *name, size_t namelen,
+			   struct strbuf *found_ref)
+{
+	char *real_ref;
+	unsigned char sha1[20];
+	if (dwim_ref(name, namelen, sha1, &real_ref) != 1)
+		return 0;
+	strbuf_reset(found_ref);
+	strbuf_addstr(found_ref, real_ref);
+	return 0;
+}
+
+static int one_head_ent(unsigned char *osha1, unsigned char *nsha1,
+			const char *ident, unsigned long timestamp, int zone,
+			const char *message, void *cbdata)
+{
+	/*
+	 * Look for signs of HEAD coming from elsewhere.
+	 *
+	 * "checkout: moving from %*s to %s" done by "git checkout"
+	 * "%s: updating HEAD" done by "git reset"
+	 */
+	struct strbuf *found_ref = cbdata;
+	char *cp;
+	size_t len;
+
+	if (!prefixcmp(message, "checkout: moving from ")) {
+		cp = strstr(message, " to ");
+		if (!cp)
+			return 0;
+		cp += 4;
+		len = strlen(cp);
+		if (cp[len-1] == '\n')
+			len--;
+		return refine_head_one(cp, len, found_ref);
+	}
+
+	cp = strstr(message, ": updating HEAD");
+	if (cp && !cp[15])
+		return refine_head_one(message, cp - message, found_ref);
+	return 0;
+}
+
+static const char *refine_head_ref(void)
+{
+	struct strbuf found = STRBUF_INIT;
+
+	strbuf_addstr(&found, "HEAD");
+	for_each_reflog_ent("HEAD", one_head_ent, &found);
+	return strbuf_detach(&found, NULL);
+}
+
+/*
  * This is called when new_ref is branched off of orig_ref, and tries
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
  * config.
@@ -58,6 +114,9 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
 	char key[1024];
 	struct tracking tracking;
 
+	if (!strcmp(orig_ref, "HEAD"))
+		orig_ref = refine_head_ref();
+
 	if (strlen(new_ref) > 1024 - 7 - 7 - 1)
 		return error("Tracking not set up: name too long: %s",
 				new_ref);
Previous: Junio C HamanoNext: Pieter de Bie
Message 28 of 67 in “[RFC] Detached-HEAD reminder on commit?”
  1. Pieter de BieSep 2, 2008
  2. Robin RosenbergSep 2, 2008
  3. Nicolas PitreSep 2, 2008
  4. Matthieu MoySep 2, 2008
  5. Nicolas PitreSep 2, 2008
  6. Junio C HamanoSep 2, 2008
  7. Stephan BeyerSep 2, 2008
  8. Johan HerlandSep 2, 2008
  9. Jeff KingSep 2, 2008
  10. Jeff KingSep 2, 2008
  11. Johan HerlandSep 3, 2008
  12. Junio C HamanoSep 3, 2008
  13. Johan HerlandSep 3, 2008
  14. Jeff KingSep 3, 2008
  15. Jeff KingSep 3, 2008
  16. Andreas EricssonSep 3, 2008
  17. Daniel BarkalowSep 3, 2008
  18. Jeff KingSep 3, 2008
  19. Junio C HamanoSep 3, 2008
  20. Jeff KingSep 3, 2008
  21. Wincent ColaiutaSep 3, 2008
  22. Jeff KingSep 3, 2008
  23. Nicolas PitreSep 3, 2008
  24. Junio C HamanoSep 2, 2008
  25. Nicolas PitreSep 2, 2008
  26. Avery PennarunSep 4, 2008
  27. Junio C HamanoSep 4, 2008
  28. Junio C HamanoSep 5, 2008
  29. Pieter de BieSep 2, 2008
  30. Jakub NarebskiSep 2, 2008
  31. Junio C HamanoSep 2, 2008
  32. Nicolas PitreSep 2, 2008
  33. Pieter de BieSep 3, 2008
  34. Builtin-commit: show on which branch a commit was addedPieter de Bie, Sep 5, 2008
  35. Junio C HamanoSep 7, 2008
  36. Junio C HamanoSep 7, 2008
  37. 1/2 pretty.c: add %% format specifierPieter de Bie, Sep 7, 2008
  38. 2/2 builtin-commit: show on which branch a commit was addedPieter de Bie, Sep 7, 2008
  39. Jeff KingSep 21, 2008
  40. Pieter de BieSep 29, 2008
  41. Jeff KingSep 29, 2008
  42. Andreas EricssonSep 30, 2008
  43. Jeff KingSep 30, 2008
  44. Andreas EricssonSep 30, 2008
  45. git commit: Reformat output somewhatAndreas Ericsson, Sep 30, 2008
  46. Wincent ColaiutaSep 30, 2008
  47. Jeff KingSep 30, 2008
  48. Andreas EricssonSep 30, 2008
  49. Jeff KingOct 1, 2008
  50. Andreas EricssonOct 1, 2008
  51. Shawn O. PearceOct 1, 2008
  52. Andreas EricssonOct 1, 2008
  53. Jeff KingOct 1, 2008
  54. Shawn O. PearceOct 1, 2008
  55. Jeff KingOct 1, 2008
  56. Shawn O. PearceOct 1, 2008
  57. git commit: Repaint the output format bikeshed (again)Andreas Ericsson, Oct 1, 2008
  58. Jeff KingOct 1, 2008
  59. Jeff KingOct 1, 2008
  60. Andreas EricssonOct 2, 2008
  61. Jeff KingOct 2, 2008
  62. Shawn O. PearceOct 3, 2008
  63. Jeff KingOct 3, 2008
  64. Shawn O. PearceOct 3, 2008
  65. Jeff KingOct 4, 2008
  66. Wincent ColaiutaOct 2, 2008
  67. Jeff KingOct 1, 2008

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.