Skip to contentSkip to conversation

Should "git log --decorate" indicate whether the HEAD is detached?

PATCH In review Julien Cretel 3 participants 23 messages Jun 15, 2016

lore
Share & tools
lore
#0 lore raw

As of Git 2.3.0, the output of "git log --decorate" is ambiguous as to whether the HEAD is detached or not.
More specifically, consider the following output of "git log --decorate":

4d860e9 (HEAD, master, dev) Remove trailing whitespace

Whether the HEAD is attached to master or detached, the output is the same. Could/should "git log --decorate" be modified to provide this information? Perhaps something along the lines of

    4d860e9 (HEAD -> master, dev) Remove trailing whitespace

or

4d860e9 (HEAD = master, dev) Remove trailing whitespace

in case HEAD is attached to master, and the current output if it is detached? Any thoughts?
(For information, I asked a related question on Stack Overflow a few months ago: http://stackoverflow.com/q/25392580/2541573.)

Also, if such a feature is desirable, would its implementation be a suitable "microproject" for a prospective GSoC-2015 applicant?

Jubobs

#1 lore raw
Quoted 2 lines · Julien Cretel

As of Git 2.3.0, the output of "git log --decorate" is ambiguous as to whether the HEAD is detached or not.

It sounds as if you are reporting some regression, but has any version of Git ever done so, or is this just a new feature that does not exist yet?

Quoted 8 lines

More specifically, consider the following output of "git log --decorate":

4d860e9 (HEAD, master, dev) Remove trailing whitespace

Whether the HEAD is attached to master or detached, the output is the same. Could/should "git log --decorate" be modified to provide this information? Perhaps something along the lines of

Quoted 6 lines
    4d860e9 (HEAD -> master, dev) Remove trailing whitespace

or

4d860e9 (HEAD = master, dev) Remove trailing whitespace

I personally do not see a need for such a differenciation. Why does one even need to know, and is it worth the cost of computing at the runtime?

Most of the time when I am on detached HEAD it is either a few commits behind a tip, or a few commits ahead of a tip.

#2 lore raw
Quoted 8 lines · Junio C Hamano
Quoted 2 lines · Julien Cretel

As of Git 2.3.0, the output of "git log --decorate" is ambiguous as to whether the HEAD is detached or not.

It sounds as if you are reporting some regression, but has any version of Git ever done so, or is this just a new feature that does not exist yet?

Apologies; I should have explained myself better. I'm not reporting a regression;
as far as I can tell, "git log --decorate" has always been ambiguous in that way.

Quoted 11 lines
Quoted 11 lines

More specifically, consider the following output of "git log --decorate":

4d860e9 (HEAD, master, dev) Remove trailing whitespace

Whether the HEAD is attached to master or detached, the output is the same. Could/should "git log --decorate" be modified to provide this information? Perhaps something along the lines of

    4d860e9 (HEAD -> master, dev) Remove trailing whitespace
Quoted 8 lines
Quoted 4 lines

or

4d860e9 (HEAD = master, dev) Remove trailing whitespace

I personally do not see a need for such a differenciation. Why does one even need to know, and is it worth the cost of computing at the runtime?

I believe the "--decorate" flag to be quite popular. I personally like to run "git log --decorate --graph --oneline --all" to quickly get an idea of the state of a repo. In my experience, many users do the same, to the point that they feel the need to define an alias for this command; see the top answers to
http://stackoverflow.com/q/1057564/2541573.

My problem with the current output of "git log --decorate" is the asymmetry, so to speak. If the HEAD is detached but pointing at a commit that isn't any branch's tip, then the user can be sure the HEAD detached; however, if at least one branch points to the current commit, there is no way to tell.

I must admit I haven't given much thought about the cost involved, but I can't imagine performance would take a big hit. Would it?

Quoted 3 lines

Most of the time when I am on detached HEAD it is either a few commits behind a tip, or a few commits ahead of a tip.

#3 lore raw

Julien Cretel venit, vidit, dixit 17.02.2015 00:40:

Quoted 41 lines · Junio C Hamano
Quoted 8 lines
Quoted 2 lines · Julien Cretel

As of Git 2.3.0, the output of "git log --decorate" is ambiguous as to whether the HEAD is detached or not.

It sounds as if you are reporting some regression, but has any version of Git ever done so, or is this just a new feature that does not exist yet?

Apologies; I should have explained myself better. I'm not reporting a regression;
as far as I can tell, "git log --decorate" has always been ambiguous in that way.

Quoted 11 lines
Quoted 11 lines

More specifically, consider the following output of "git log --decorate":

4d860e9 (HEAD, master, dev) Remove trailing whitespace

Whether the HEAD is attached to master or detached, the output is the same. Could/should "git log --decorate" be modified to provide this information? Perhaps something along the lines of

    4d860e9 (HEAD -> master, dev) Remove trailing whitespace
Quoted 8 lines
Quoted 4 lines

or

4d860e9 (HEAD = master, dev) Remove trailing whitespace

I personally do not see a need for such a differenciation. Why does one even need to know, and is it worth the cost of computing at the runtime?

I believe the "--decorate" flag to be quite popular. I personally like to run "git log --decorate --graph --oneline --all" to quickly get an idea of the state of a repo. In my experience, many users do the same, to the point that they feel the need to define an alias for this command; see the top answers to
http://stackoverflow.com/q/1057564/2541573.

Quoted 11 lines

My problem with the current output of "git log --decorate" is the asymmetry, so to speak. If the HEAD is detached but pointing at a commit that isn't any branch's tip, then the user can be sure the HEAD detached; however, if at least one branch points to the current commit, there is no way to tell.

I must admit I haven't given much thought about the cost involved, but I can't imagine performance would take a big hit. Would it?

Quoted 3 lines

Most of the time when I am on detached HEAD it is either a few commits behind a tip, or a few commits ahead of a tip.

"git branch" will tell you your branches and which one is checked out (or HEAD); "git status" will tell you the latter.

"git log" is about the DAG which has absolutely nothing to do with what you have currently checked out.

Your expectation may come from the fact that the default argument to "git log" is HEAD; or from what "gitk" and other ui tools do.

On the other hand, our decorations can be considered "wrong" in the following sense: if HEAD is a symref it really points to a (branch) ref, not a commit. In this situation, "HEAD" should be the decoration of the branch ref, not of the commit which the branch ref resolves to.

But that would apply to annotated tags, as well: they point to tag objects (and should decorate them by the logic above) rather than commit objects.

So, what "log --decorate" really and consistently does is resolving ("peeling") any decorating reference until it points to a commit object, and decorate that.

A --decorate-detailed mode which does without the peeling could be elucidating - that would need markers for (branch) refs and tag objects in addition to commit objects, though (and an extension of the machinery).

Michael

#4 lore raw

[RFC/PATCH] log: decorate detached HEAD differently

"git status" and "git branch" let the user know when the HEAD is detached, while "git log --decorate" does not.

Change the decoration by a detached HEAD to "detached HEAD". This can be seen as giving more information about the decoration item itself in the same way as we prefix tags by "tag: ".

---
This turned out to be easy to do, though I am still undecided. Personally, I like to think of refs as objects (and have implemented refname objects in the past), but that view is not too popular.

So, maybe the analogy between ref peeling and symref resolving (for HEAD) is not that strong after all. They are both indirections, though different technically.

The RFC patch only checks HEAD for being a symref, the output is analogous to the summary of "git commit".

 log-tree.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
log-tree.c +7 -1
index 7f0890e..2eac4b6 100644
@@ -118,8 +118,14 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
 		type = DECORATION_REF_TAG;
 	else if (!strcmp(refname, "refs/stash"))
 		type = DECORATION_REF_STASH;
-	else if (!strcmp(refname, "HEAD"))
+	else if (!strcmp(refname, "HEAD")) {
+		char *junk_sha1[20];
+		char *head;
 		type = DECORATION_REF_HEAD;
+		head = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL);
+		if (!strcmp(head, "HEAD"))
+			refname = "detached HEAD";
+	}
 
 	if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
 		refname = prettify_refname(refname);
Signature · 1 line
2.3.0.136.g92a3b58
#5 lore raw
In reply to Michael J Gruber
Quoted 5 lines · Michael J Gruber

"git branch" will tell you your branches and which one is checked out (or HEAD); "git status" will tell you the latter.

"git log" is about the DAG which has absolutely nothing to do with what you have currently checked out.

Yeah, that summarizes my reaction, too. More importantly, "log" is about showing commits and "--decorate" is a way to enrich the presentation of commits---it talks about commits in terms of refs; the command and the option is not about describing refs and their relationships.

I do not terribly mind showing the fact that HEAD points at a branch when --decorate talks about HEAD, partly because we will be showing both HEAD and the branch name _anyway_ in the output. But I am not sure if the extra bit of information is more helpful to the readers or being distracting.

Julien's "HEAD=master, other" vs "HEAD, master, other" may be subdued enough to be undistracting, I would guess. I do not think the distinction between "HEAD = master" and "HEAD -> master" would be useful, on the other hand. We already know that the names listed all refer to the same commit, which means that we do not have to say "HEAD is detached" explicitly as long as we have a way to say "HEAD points at this branch". If HEAD is listed and is not marked to point at another branch that is shown, by definition it is detached, no?

#6 lore raw

Junio C Hamano venit, vidit, dixit 18.02.2015 18:07:

Quoted 20 lines
Quoted 5 lines · Michael J Gruber

"git branch" will tell you your branches and which one is checked out (or HEAD); "git status" will tell you the latter.

"git log" is about the DAG which has absolutely nothing to do with what you have currently checked out.

Yeah, that summarizes my reaction, too. More importantly, "log" is about showing commits and "--decorate" is a way to enrich the presentation of commits---it talks about commits in terms of refs; the command and the option is not about describing refs and their relationships.

I do not terribly mind showing the fact that HEAD points at a branch when --decorate talks about HEAD, partly because we will be showing both HEAD and the branch name _anyway_ in the output. But I am not sure if the extra bit of information is more helpful to the readers or being distracting.

Quoted 10 lines

Julien's "HEAD=master, other" vs "HEAD, master, other" may be subdued enough to be undistracting, I would guess. I do not think the distinction between "HEAD = master" and "HEAD -> master" would be useful, on the other hand. We already know that the names listed all refer to the same commit, which means that we do not have to say "HEAD is detached" explicitly as long as we have a way to say "HEAD points at this branch". If HEAD is listed and is not marked to point at another branch that is shown, by definition it is detached, no?

Yep, it very well is. Also, that approach would tell you which branch is checked out, though I don't consider that git log's business.

OTOH, it's "backwards" in the sense that it marks the "ordinary" case (HEAD is symref, branch is checked out) specially compared to the "exceptional/dangerous" case (HEAD is ref, detached). And status, branch will point out that latter case more verbously, too.

Michael

#7 lore raw
Quoted 6 lines · Michael J Gruber

Yep, it very well is. Also, that approach would tell you which branch is checked out, though I don't consider that git log's business.

OTOH, it's "backwards" in the sense that it marks the "ordinary" case (HEAD is symref, branch is checked out) specially compared to the "exceptional/dangerous" case (HEAD is ref, detached).

Both are ordinary and there is nothing exceptional or dangerous about your HEAD temporarily being detached during a "rebase -i" session, for example.

Quoted 2 lines

And status, branch
will point out that latter case more verbously, too.

Yeah, but as you said, that is not "log"'s business.

#8 lore raw

Junio C Hamano venit, vidit, dixit 18.02.2015 20:49:

Quoted 5 lines
Quoted 3 lines · Michael J Gruber

Yep, it very well is. Also, that approach would tell you which branch is checked out, though I don't consider that git log's business.

Quoted 7 lines
Quoted 3 lines

OTOH, it's "backwards" in the sense that it marks the "ordinary" case (HEAD is symref, branch is checked out) specially compared to the "exceptional/dangerous" case (HEAD is ref, detached).

Both are ordinary and there is nothing exceptional or dangerous about your HEAD temporarily being detached during a "rebase -i" session, for example.

Sure, that's why I put it in quotes. That's only how it is perceived by some users, and I suppose it's that kind of users that we are trying to help here.

Quoted 4 lines
Quoted 2 lines

And status, branch
will point out that latter case more verbously, too.

Yeah, but as you said, that is not "log"'s business.

I still think decorations "detached HEAD" resp. "HEAD" for the two cases are more natural, if we want to include any additional information at all. Just think of:

deadbeef (HEAD=master, topicbranch, tag: v1)

log/rev-list is about commit objects. All the refs above resolve to the same commit, so why are only two of them equal?

In fact, they are very unequal, since HEAD would be "ref:
refs/heads/master" whereas master would "deadbeef". They are equal in the other (detached) case! I'm not telling you any news here, I just want to point out how badly misleading that notation is.

So, I would suggest to "decorate the decorations", by saying something like "detached HEAD", and maybe some version of "HEAD at master" (I'd prefer just "HEAD") and possibly more info on the tags ("s-tag" or "signed tag" etc).

Michael

#9 lore raw
In reply to Junio C Hamano
Quoted 4 lines · Junio C Hamano

Julien's "HEAD=master, other" vs "HEAD, master, other" may be subdued enough to be undistracting, I would guess. I do not think the distinction between "HEAD = master" and "HEAD -> master" would be useful, on the other hand.

Just to clarify, I suggested these two notations as alternatives for denoting the same state: "HEAD is attached to master". They were not meant to denote different states. Accordingly, a detached HEAD could be denoted by "HEAD, master, other" (i.e. the same as the current output of "git log --decorate").

#10 lore raw
Quoted 7 lines · Julien Cretel
Quoted 4 lines · Junio C Hamano

Julien's "HEAD=master, other" vs "HEAD, master, other" may be subdued enough to be undistracting, I would guess. I do not think the distinction between "HEAD = master" and "HEAD -> master" would be useful, on the other hand.

Quoted 5 lines

Just to clarify, I suggested these two notations as alternatives for denoting the same state: "HEAD is attached to master". They were not meant to denote different states. Accordingly, a detached HEAD could be denoted by "HEAD, master, other" (i.e. the same as the current output of "git log --decorate").

That makes it even better than my misunderstood version ;-) A list that is usually "A, B, C" that sometimes has "A, B=C" is inconspicuous enough not to be distracting too much, I would say.

Thanks.

#11 lore raw

PATCH 1/1 log: decorate detached HEAD differently

"git status" and "git branch" let the user know when the HEAD is detached, as well as the current branch, while "git log --decorate" does not.

Change the decoration by a non-detached HEAD pointing to branch foo to "HEAD->foo". This can be seen as giving more information about the decoration item itself in the same way as we prefix tags by "tag: ".

---

Notes:
v2 decorates the HEAD pointing to master as "HEAD->master", a detached HEAD just as "HEAD". The "->" hopefully conveys the symlink nature - a "=" would be confusing.

Somehow I still prefer "detached HEAD", dunno. Maybe in addition?

Note that now a checked branch is listed twice, once as target of the HEAD, once as branch: They are two different refs and colored differently.

 log-tree.c                             | 8 +++++++-
 t/t4013/diff.log_--decorate=full_--all | 2 +-
 t/t4013/diff.log_--decorate_--all      | 2 +-
 t/t4207-log-decoration-colors.sh       | 2 +-
 4 files changed, 10 insertions(+), 4 deletions(-)
log-tree.c +7 -1
index 7f0890e..38862bb 100644
@@ -118,8 +118,11 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
 		type = DECORATION_REF_TAG;
 	else if (!strcmp(refname, "refs/stash"))
 		type = DECORATION_REF_STASH;
-	else if (!strcmp(refname, "HEAD"))
+	else if (!strcmp(refname, "HEAD")) {
+		unsigned char junk_sha1[20];
 		type = DECORATION_REF_HEAD;
+		refname = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL);
+	}
 
 	if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
 		refname = prettify_refname(refname);
@@ -198,6 +201,9 @@ void format_decorations_extended(struct strbuf *sb,
 		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 		if (decoration->type == DECORATION_REF_TAG)
 			strbuf_addstr(sb, "tag: ");
+		else if (decoration->type == DECORATION_REF_HEAD &&
+			 strcmp(decoration->name, "HEAD"))
+			strbuf_addstr(sb, "HEAD->");
 		strbuf_addstr(sb, decoration->name);
 		strbuf_addstr(sb, color_reset);
 		prefix = separator;
t/t4013/diff.log_--decorate=full_--all +1 -1
index 44d4525..3758ae9 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD->refs/heads/master, refs/heads/master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4013/diff.log_--decorate_--all +1 -1
index 27d3eab..df702ae 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD->master, master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4207-log-decoration-colors.sh +1 -1
index 925f577..0437ff2 100755
@@ -44,7 +44,7 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD->master${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
Signature · 1 line
2.3.1.303.g5174db1
#12 lore raw

Re: [PATCH] log: decorate detached HEAD differently

Michael J Gruber venit, vidit, dixit 06.03.2015 17:15:
... and maybe the patch title should be different for v2, too:

log: decorate non-detached HEAD differently

Not my day today it seems, but this is my last patch for today.

Michael

#13 lore raw

Re: [PATCH] log: decorate detached HEAD differently

In reply to Michael J Gruber
Quoted 15 lines · Michael J Gruber

"git status" and "git branch" let the user know when the HEAD is detached, as well as the current branch, while "git log --decorate" does not.

Change the decoration by a non-detached HEAD pointing to branch foo to "HEAD->foo". This can be seen as giving more information about the decoration item itself in the same way as we prefix tags by "tag: ".

---

Notes:
v2 decorates the HEAD pointing to master as "HEAD->master", a detached HEAD just as "HEAD". The "->" hopefully conveys the symlink nature - a "=" would be confusing.

Quoted 4 lines

Somehow I still prefer "detached HEAD", dunno. Maybe in addition?

Note that now a checked branch is listed twice, once as target of the HEAD, once as branch: They are two different refs and colored differently.

The pointee of HEAD would always be branch and will always appear on the output when you show HEAD->$name_of_that_branch; is it feasible to drop the duplicate, I wonder?

Quoted 73 lines
 log-tree.c                             | 8 +++++++-
 t/t4013/diff.log_--decorate=full_--all | 2 +-
 t/t4013/diff.log_--decorate_--all      | 2 +-
 t/t4207-log-decoration-colors.sh       | 2 +-
 4 files changed, 10 insertions(+), 4 deletions(-)
log-tree.c +7 -1
index 7f0890e..38862bb 100644
@@ -118,8 +118,11 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
 		type = DECORATION_REF_TAG;
 	else if (!strcmp(refname, "refs/stash"))
 		type = DECORATION_REF_STASH;
-	else if (!strcmp(refname, "HEAD"))
+	else if (!strcmp(refname, "HEAD")) {
+		unsigned char junk_sha1[20];
 		type = DECORATION_REF_HEAD;
+		refname = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL);
+	}
 
 	if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
 		refname = prettify_refname(refname);
@@ -198,6 +201,9 @@ void format_decorations_extended(struct strbuf *sb,
 		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 		if (decoration->type == DECORATION_REF_TAG)
 			strbuf_addstr(sb, "tag: ");
+		else if (decoration->type == DECORATION_REF_HEAD &&
+			 strcmp(decoration->name, "HEAD"))
+			strbuf_addstr(sb, "HEAD->");
 		strbuf_addstr(sb, decoration->name);
 		strbuf_addstr(sb, color_reset);
 		prefix = separator;
t/t4013/diff.log_--decorate=full_--all +1 -1
index 44d4525..3758ae9 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD->refs/heads/master, refs/heads/master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4013/diff.log_--decorate_--all +1 -1
index 27d3eab..df702ae 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD->master, master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4207-log-decoration-colors.sh +1 -1
index 925f577..0437ff2 100755
@@ -44,7 +44,7 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD->master${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
#14 lore raw

Re: [PATCH] log: decorate detached HEAD differently

Junio C Hamano venit, vidit, dixit 06.03.2015 20:03:

Quoted 17 lines
Quoted 15 lines · Michael J Gruber

"git status" and "git branch" let the user know when the HEAD is detached, as well as the current branch, while "git log --decorate" does not.

Change the decoration by a non-detached HEAD pointing to branch foo to "HEAD->foo". This can be seen as giving more information about the decoration item itself in the same way as we prefix tags by "tag: ".

---

Notes:

    v2 decorates the HEAD pointing to master as "HEAD->master", a detached
    HEAD just as "HEAD". The "->" hopefully conveys the symlink nature - a
    "=" would be confusing.
Quoted 8 lines
Quoted 4 lines

Somehow I still prefer "detached HEAD", dunno. Maybe in addition?

Note that now a checked branch is listed twice, once as target of the HEAD, once as branch: They are two different refs and colored differently.

The pointee of HEAD would always be branch and will always appear on the output when you show HEAD->$name_of_that_branch; is it feasible to drop the duplicate, I wonder?

It's doable but not nice, because we cannot take the order in which refs are processed for granted.

I also think that we shouldn't simply check whether branch foo is checked out (when decorating with foo) - we need to know whether HEAD is among the refs which are eligible for decoration. That caveat is also true for the "always" above. (I don't think we allow decorating by a subset of all refs right now, but it would be useful, and easy given the for-each-ref machinery.)

Also, HEAD and foo are two different refs, so even if HEAD has the value "foo", I think we should really show them both anyways.

Alternatively, we could decorate by (HEAD, *foo, master, tag: release) if foo is checked out, just like branch does.

Quoted 72 lines
Quoted 72 lines
 log-tree.c                             | 8 +++++++-
 t/t4013/diff.log_--decorate=full_--all | 2 +-
 t/t4013/diff.log_--decorate_--all      | 2 +-
 t/t4207-log-decoration-colors.sh       | 2 +-
 4 files changed, 10 insertions(+), 4 deletions(-)
log-tree.c +7 -1
index 7f0890e..38862bb 100644
@@ -118,8 +118,11 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
 		type = DECORATION_REF_TAG;
 	else if (!strcmp(refname, "refs/stash"))
 		type = DECORATION_REF_STASH;
-	else if (!strcmp(refname, "HEAD"))
+	else if (!strcmp(refname, "HEAD")) {
+		unsigned char junk_sha1[20];
 		type = DECORATION_REF_HEAD;
+		refname = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL);
+	}
 
 	if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
 		refname = prettify_refname(refname);
@@ -198,6 +201,9 @@ void format_decorations_extended(struct strbuf *sb,
 		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 		if (decoration->type == DECORATION_REF_TAG)
 			strbuf_addstr(sb, "tag: ");
+		else if (decoration->type == DECORATION_REF_HEAD &&
+			 strcmp(decoration->name, "HEAD"))
+			strbuf_addstr(sb, "HEAD->");
 		strbuf_addstr(sb, decoration->name);
 		strbuf_addstr(sb, color_reset);
 		prefix = separator;
t/t4013/diff.log_--decorate=full_--all +1 -1
index 44d4525..3758ae9 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD->refs/heads/master, refs/heads/master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4013/diff.log_--decorate_--all +1 -1
index 27d3eab..df702ae 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD->master, master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4207-log-decoration-colors.sh +1 -1
index 925f577..0437ff2 100755
@@ -44,7 +44,7 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD->master${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
#15 lore raw

Re: [PATCH] log: decorate detached HEAD differently

Quoted 6 lines · Michael J Gruber

Junio C Hamano venit, vidit, dixit 06.03.2015 20:03:

Quoted 5 lines
Quoted 3 lines · Michael J Gruber

Note that now a checked branch is listed twice, once as target of the HEAD, once as branch: They are two different refs and colored differently.

Quoted 6 lines
Quoted 3 lines

The pointee of HEAD would always be branch and will always appear on the output when you show HEAD->$name_of_that_branch; is it feasible to drop the duplicate, I wonder?

It's doable but not nice, because we cannot take the order in which refs are processed for granted.

That is true, but when we format them into a single line in the header in response to --decorate (or %d), don't we have all of them already at hand---does the order still matter?

Here is an illustration of what I had in mind, made on a random commit I happened to have checked out that does not have your patches on this topic. Half of the change is a new helper function, and the other half is mostly reindenting.

 log-tree.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 63 insertions(+), 8 deletions(-)
log-tree.c +63 -8
index 7f0890e..e0c5865 100644
@@ -173,6 +173,43 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 }
 
 /*
+ * Do we have HEAD in the output, and also the branch it points at?
+ * If so, find that decoration entry for that current branch.
+ */
+static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
+{
+	const struct name_decoration *list, *head = NULL;
+	const char *branch_name = NULL;
+	unsigned char unused[20];
+	int rru_flags;
+
+	/* First find HEAD */
+	for (list = decoration; list; list = list->next)
+		if (list->type == DECORATION_REF_HEAD) {
+			head = list;
+			break;
+		}
+	if (!head)
+		return NULL;
+
+	/* Now resolve and find the matching current branch */
+	branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
+	if (!(rru_flags & REF_ISSYMREF))
+		return NULL;
+	if (!skip_prefix(branch_name, "refs/heads/", &branch_name))
+		return NULL;
+
+	/* OK, do we have that ref in the list? */
+	for (list = decoration; list; list = list->next)
+		if ((list->type == DECORATION_REF_LOCAL) &&
+		    !strcmp(branch_name, list->name)) {
+			return list;
+		}
+
+	return NULL;
+}
+
+/*
  * The caller makes sure there is no funny color before calling.
  * format_decorations_extended makes sure the same after return.
  */
@@ -184,6 +221,7 @@ void format_decorations_extended(struct strbuf *sb,
 			const char *suffix)
 {
 	const struct name_decoration *decoration;
+	const struct name_decoration *current_and_HEAD;
 	const char *color_commit =
 		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
@@ -192,15 +230,32 @@ void format_decorations_extended(struct strbuf *sb,
 	decoration = get_name_decoration(&commit->object);
 	if (!decoration)
 		return;
+
+	current_and_HEAD = current_pointed_by_HEAD(decoration);
 	while (decoration) {
-		strbuf_addstr(sb, color_commit);
-		strbuf_addstr(sb, prefix);
-		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
-		if (decoration->type == DECORATION_REF_TAG)
-			strbuf_addstr(sb, "tag: ");
-		strbuf_addstr(sb, decoration->name);
-		strbuf_addstr(sb, color_reset);
-		prefix = separator;
+		/*
+		 * When both current and HEAD are there, only
+		 * show HEAD->current where HEAD would have
+		 * appeaed, skipping the entry for current.
+		 */
+		if (current_and_HEAD && decoration == current_and_HEAD)
+			;
+		else {
+			strbuf_addstr(sb, color_commit);
+			strbuf_addstr(sb, prefix);
+			strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
+			if (decoration->type == DECORATION_REF_TAG)
+				strbuf_addstr(sb, "tag: ");
+
+			if (current_and_HEAD &&
+			    decoration->type == DECORATION_REF_HEAD)
+				strbuf_addf(sb, "HEAD->%s", current_and_HEAD->name);
+			else
+				strbuf_addstr(sb, decoration->name);
+			strbuf_addstr(sb, color_reset);
+
+			prefix = separator;
+		}
 		decoration = decoration->next;
 	}
 	strbuf_addstr(sb, color_commit);
#16 lore raw

Re: [PATCH] log: decorate detached HEAD differently

Junio C Hamano venit, vidit, dixit 10.03.2015 03:03:

Quoted 15 lines
Quoted 6 lines · Michael J Gruber

Junio C Hamano venit, vidit, dixit 06.03.2015 20:03:

Quoted 5 lines
Quoted 3 lines · Michael J Gruber

Note that now a checked branch is listed twice, once as target of the HEAD, once as branch: They are two different refs and colored differently.

Quoted 6 lines
Quoted 3 lines

The pointee of HEAD would always be branch and will always appear on the output when you show HEAD->$name_of_that_branch; is it feasible to drop the duplicate, I wonder?

It's doable but not nice, because we cannot take the order in which refs are processed for granted.

Quoted 8 lines

That is true, but when we format them into a single line in the header in response to --decorate (or %d), don't we have all of them already at hand---does the order still matter?

Here is an illustration of what I had in mind, made on a random commit I happened to have checked out that does not have your patches on this topic. Half of the change is a new helper function, and the other half is mostly reindenting.

Yes, the patch illustrates pretty well what I meant by "doable but not nice" :)

Quoted 5 lines · But I also

Also, HEAD and foo are two different refs, so even if HEAD has the value "foo", I think we should really show them both anyways.

Alternatively, we could decorate by (HEAD, *foo, master, tag: release) if foo is checked out, just like branch does.

I guess I will have to apply your patch and feel what it's like in practical use in order to change my mind...

Michael

#17 lore raw

PATCH v2 1/2 log-tree: properly reset colors

Except for the separator, all output items reset the color immediately. Do the same for the separator.

This affects only cases where setting color A does not override color B, such as when one is forground and one background.

---
 log-tree.c                       |  1 +
 t/t4207-log-decoration-colors.sh | 16 ++++++++--------
 2 files changed, 9 insertions(+), 8 deletions(-)
log-tree.c +1 -0
index 7f0890e..53bb526 100644
@@ -195,6 +195,7 @@ void format_decorations_extended(struct strbuf *sb,
 	while (decoration) {
 		strbuf_addstr(sb, color_commit);
 		strbuf_addstr(sb, prefix);
+		strbuf_addstr(sb, color_reset);
 		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 		if (decoration->type == DECORATION_REF_TAG)
 			strbuf_addstr(sb, "tag: ");
t/t4207-log-decoration-colors.sh +8 -8
index 925f577..6b8ad4f 100755
@@ -44,15 +44,15 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
- ${c_tag}tag: v1.0${c_reset}${c_commit},\
- ${c_tag}tag: B${c_reset}${c_commit},\
- ${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
- ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit},\
+ ${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit},\
+ ${c_reset}${c_tag}tag: B${c_reset}${c_commit},\
+ ${c_reset}${c_branch}master${c_reset}${c_commit})${c_reset} B
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit},\
+ ${c_reset}${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
  On master: Changes to A.t
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
 EOF
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
Signature · 1 line
2.3.2.346.gb6960c9
#18 lore raw

PATCH v2 2/2 log: decorate HEAD with branch name

In reply to Michael J Gruber

From: Junio C Hamano <[email protected]>

Currently, log decorations do not indicate which branch is checked out and whether HEAD is detached.

When branch foo is checked out, change the "HEAD, foo" part of the decorations to "HEAD -> foo". This serves to indicate both ref decorations (helped by the spacing) as well as their relationshsip. As a consequence, "HEAD" without any " -> " denotes a detached HEAD now.

---

Notes:
The patch is really Junio's now.
I just simplified the if's and added colors and tests. The spaces around "->" should help to make the branch stick out even without colors.

 log-tree.c                        | 77 ++++++++++++++++++++++++++++++++++-----
 t/t4013/diff.log_--decorate_--all |  2 +-
 t/t4207-log-decoration-colors.sh  |  6 +--
 3 files changed, 72 insertions(+), 13 deletions(-)
log-tree.c +68 -9
index 53bb526..2c1ed0f 100644
@@ -173,6 +173,43 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 }
 
 /*
+ * Do we have HEAD in the output, and also the branch it points at?
+ * If so, find that decoration entry for that current branch.
+ */
+static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
+{
+	const struct name_decoration *list, *head = NULL;
+	const char *branch_name = NULL;
+	unsigned char unused[20];
+	int rru_flags;
+
+	/* First find HEAD */
+	for (list = decoration; list; list = list->next)
+		if (list->type == DECORATION_REF_HEAD) {
+			head = list;
+			break;
+		}
+	if (!head)
+		return NULL;
+
+	/* Now resolve and find the matching current branch */
+	branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
+	if (!(rru_flags & REF_ISSYMREF))
+		return NULL;
+	if (!skip_prefix(branch_name, "refs/heads/", &branch_name))
+		return NULL;
+
+	/* OK, do we have that ref in the list? */
+	for (list = decoration; list; list = list->next)
+		if ((list->type == DECORATION_REF_LOCAL) &&
+		    !strcmp(branch_name, list->name)) {
+			return list;
+		}
+
+	return NULL;
+}
+
+/*
  * The caller makes sure there is no funny color before calling.
  * format_decorations_extended makes sure the same after return.
  */
@@ -184,6 +221,7 @@ void format_decorations_extended(struct strbuf *sb,
 			const char *suffix)
 {
 	const struct name_decoration *decoration;
+	const struct name_decoration *current_and_HEAD;
 	const char *color_commit =
 		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
@@ -192,16 +230,37 @@ void format_decorations_extended(struct strbuf *sb,
 	decoration = get_name_decoration(&commit->object);
 	if (!decoration)
 		return;
+
+	current_and_HEAD = current_pointed_by_HEAD(decoration);
 	while (decoration) {
-		strbuf_addstr(sb, color_commit);
-		strbuf_addstr(sb, prefix);
-		strbuf_addstr(sb, color_reset);
-		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
-		if (decoration->type == DECORATION_REF_TAG)
-			strbuf_addstr(sb, "tag: ");
-		strbuf_addstr(sb, decoration->name);
-		strbuf_addstr(sb, color_reset);
-		prefix = separator;
+		/*
+		 * When both current and HEAD are there, only
+		 * show HEAD->current where HEAD would have
+		 * appeared, skipping the entry for current.
+		 */
+		if (decoration != current_and_HEAD) {
+			strbuf_addstr(sb, color_commit);
+			strbuf_addstr(sb, prefix);
+			strbuf_addstr(sb, color_reset);
+			strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
+			if (decoration->type == DECORATION_REF_TAG)
+				strbuf_addstr(sb, "tag: ");
+
+			strbuf_addstr(sb, decoration->name);
+
+			if (current_and_HEAD &&
+			    decoration->type == DECORATION_REF_HEAD) {
+				strbuf_addstr(sb, color_reset);
+				strbuf_addstr(sb, color_commit);
+				strbuf_addstr(sb, " -> ");
+				strbuf_addstr(sb, color_reset);
+				strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
+				strbuf_addstr(sb, current_and_HEAD->name);
+			}
+			strbuf_addstr(sb, color_reset);
+
+			prefix = separator;
+		}
 		decoration = decoration->next;
 	}
 	strbuf_addstr(sb, color_commit);
t/t4013/diff.log_--decorate_--all +1 -1
index 27d3eab..3aa16a9 100644
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <[email protected]>
 Date:   Mon Jun 26 00:04:00 2006 +0000
t/t4207-log-decoration-colors.sh +3 -3
index 6b8ad4f..f8008b6 100755
@@ -44,10 +44,10 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit} ->\
+ ${c_reset}${c_branch}master${c_reset}${c_commit},\
  ${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit},\
- ${c_reset}${c_tag}tag: B${c_reset}${c_commit},\
- ${c_reset}${c_branch}master${c_reset}${c_commit})${c_reset} B
+ ${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
 ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit},\
  ${c_reset}${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
 ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
Signature · 1 line
2.3.2.346.gb6960c9
#19 lore raw

v2 cover log decorations for HEAD

In reply to Michael J Gruber

So it didn't take too long to convince me after all :)

Here comes Junio's version, preceded by a cleanup of the color setting and resetting for decorations.

Junio C Hamano (1):
log: decorate HEAD with branch name

Michael J Gruber (1):
log-tree: properly reset colors

 log-tree.c                        | 76 ++++++++++++++++++++++++++++++++++-----
 t/t4013/diff.log_--decorate_--all |  2 +-
 t/t4207-log-decoration-colors.sh  | 16 ++++-----
 3 files changed, 77 insertions(+), 17 deletions(-)
Signature · 1 line
2.3.2.346.gb6960c9
#20 lore raw

Re: [PATCHv2 0/2] log decorations for HEAD

Quoted 8 lines · Michael J Gruber

So it didn't take too long to convince me after all :)

Here comes Junio's version, preceded by a cleanup of the color setting and resetting for decorations.

Junio C Hamano (1):
log: decorate HEAD with branch name

Quoted 7 lines

Michael J Gruber (1):
log-tree: properly reset colors

 log-tree.c                        | 76 ++++++++++++++++++++++++++++++++++-----
 t/t4013/diff.log_--decorate_--all |  2 +-
 t/t4207-log-decoration-colors.sh  | 16 ++++-----
 3 files changed, 77 insertions(+), 17 deletions(-)

Hmph, is the "do not leak commit color" one the same as 5ee87585 (log --decorate: do not leak "commit" color into the next item, 2015-03-04) aka $gmane/264788 [*1*] or is there something I missed?

[References]

*1* http://thread.gmane.org/gmane.comp.version-control.git/264063/focus=264788

#21 lore raw

Re: [PATCHv2 0/2] log decorations for HEAD

Junio C Hamano venit, vidit, dixit 10.03.2015 18:06:

Quoted 13 lines
Quoted 11 lines · Michael J Gruber

So it didn't take too long to convince me after all :)

Here comes Junio's version, preceded by a cleanup of the color setting and resetting for decorations.

Junio C Hamano (1):
log: decorate HEAD with branch name

Michael J Gruber (1):
log-tree: properly reset colors

Quoted 9 lines
Quoted 4 lines
 log-tree.c                        | 76 ++++++++++++++++++++++++++++++++++-----
 t/t4013/diff.log_--decorate_--all |  2 +-
 t/t4207-log-decoration-colors.sh  | 16 ++++-----
 3 files changed, 77 insertions(+), 17 deletions(-)

Hmph, is the "do not leak commit color" one the same as 5ee87585 (log --decorate: do not leak "commit" color into the next item, 2015-03-04) aka $gmane/264788 [*1*] or is there something I missed?

Uh, I missed that one. The commit msg confuses me somewhat (color.diff vs color.decorate), but the patch to log-tree.c is the same, and so I assume the patch to t4207 is the same, too. 2/2 from here should go on top of 7/7 from there, accordingly.

Quoted 7 lines

[References]

*1* http://thread.gmane.org/gmane.comp.version-control.git/264063/focus=264788

#22 lore raw

Re: [PATCHv2 0/2] log decorations for HEAD

In reply to Michael J Gruber
Quoted 12 lines · Michael J Gruber

So it didn't take too long to convince me after all :)

Here comes Junio's version, preceded by a cleanup of the color setting and resetting for decorations.

Junio C Hamano (1):
log: decorate HEAD with branch name

Michael J Gruber (1):
log-tree: properly reset colors

Quoted 8 lines
 log-tree.c                        | 76 ++++++++++++++++++++++++++++++++++-----
 t/t4013/diff.log_--decorate_--all |  2 +-
 t/t4207-log-decoration-colors.sh  | 16 ++++-----
 3 files changed, 77 insertions(+), 17 deletions(-)

--
2.3.2.346.gb6960c9

I'm so glad you've implemented this. Thanks again.

I hope I'll get familiar enough with the Git codebase to start posting patches of my own, in the future.

Jubobs