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

Re: [PATCH v3] Accept tags in HEAD or MERGE_HEAD

From
Junio C Hamano <gitster@pobox.com>
Date
Aug 18, 2011, 18:54 UTC
Message-ID
<7vd3g2a431.fsf@alter.siamese.dyndns.org>
In-Reply-To
<1313674994-22902-1-git-send-email-pclouds@gmail.com>
Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
Show 9 quoted lines
> HEAD and MERGE_HEAD (among other branch tips) should never hold a
> tag. That can only be caused by broken tools and is cumbersome to fix
> by an end user with:
>
>   $ git update-ref HEAD $(git rev-parse HEAD^{commit})
>
> which may look like a magic to a new person.
>
> Be easy, warn users (so broken tools can be fixed) and move on.
We do not really fix broken tools; we just fix breakages caused by them.
> Be robust, if the given SHA-1 cannot be resolved to a commit object,
> die (therefore return value is always valid).
Makes sense.
Show 9 quoted lines
> diff --git a/builtin/commit.c b/builtin/commit.c
> index cb73857..f78b449 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -63,6 +63,7 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
>  "Otherwise, please use 'git reset'\n");
>  
>  static unsigned char head_sha1[20];
> +static struct commit *head_commit;

I was not happy with the file-scope global head_sha1[] already, and this makes me even less happy. Was it too much trouble to keep them local to cmd_commit() and pass them around as arguments where necessary? If you pass around head_commit, is_null_sha1(head_sha1) can be replaced with a check !head_commit so we may even be able to lose the head_sha1[] global.

And actually removing head_sha1[] is a necessary step from the correctness point of view. The repository may have given an object name for a tag in head_sha1[] and lookup_expect_commit() may have peeled it to a commit. The code may want to add the "HEAD" as one of the parents of a new commit, and head_sha1[] is no longer the place to pick that information up after your fix. The code needs to look at head_commit->object.sha1[] instead. Losing the use of head_sha1[] variable and forcing the code to go to head_commit->object.sha1[] reduces the risk of such confusion.

Show 6 quoted lines
> @@ -1028,6 +1026,9 @@ static int parse_and_validate_options(int argc, const char *argv[],
>  
>  	if (get_sha1("HEAD", head_sha1))
>  		initial_commit = 1;
> +	else
> +		head_commit = lookup_expect_commit(head_sha1, "HEAD");

It may be just me, but the name feels a bit funny. The original name was "look up" (verb) + "commit" (direct object of the verb), and what you are doing is lookup_and_expect_commit(), but it is too long.

Perhaps lookup_commit_or_die()?
To a naïve reader of the caller, the function looks as if it would do
	struct commit *lookup_expect_commit(unsigned char *head_sha1, char *name)
        {
        	struct commit *c;
		if (get_sha1("HEAD", head_sha1) ||
	            !(c = lookup_commit(head_sha1))) die(...);
		return c;
	}

but in fact it does not use "HEAD" for anything other than error reporting and it is the caller's responsibility to supply head_sha1[].

It is documented in the function declaration by making the memory head_sha1 points at as a "const" (i.e. the function can't be calling get_sha() on the refname), but it may also need a comment or two there.

Show 9 quoted lines
> diff --git a/builtin/merge.c b/builtin/merge.c
> index 325891e..22e98e8 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -51,6 +51,7 @@ static int allow_trivial = 1, have_message;
>  static struct strbuf merge_msg;
>  static struct commit_list *remoteheads;
>  static unsigned char head[20], stash[20];
> +static struct commit* head_commit;
This is C, not C++; asterisk sticks to the variable, not type.
Show 9 quoted lines
> @@ -1030,6 +1031,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
>  		branch += 11;
>  	if (is_null_sha1(head))
>  		head_invalid = 1;
> +	else
> +		head_commit = lookup_expect_commit(head, "HEAD");
>  
>  	git_config(git_merge_config, NULL);
>  

The same comment as head[] vs head_commit->object.sha1[] redundancy applies from builtin/commit.c here.

Overall, the changes to buitlin/merge.c look very nice, getting rid of the repeated lookup_commit(head). In a separate patch after this fix gets ready, we may want to further clean it up so that head_commit being NULL means head_invalid, losing a redundant variable.

Previous: Nguyễn Thái Ngọc DuyNext: Nguyen Thai Ngoc Duy
Message 10 of 21 in “commit: check return value of lookup_commit()”
  1. commit: check return value of lookup_commit()Nguyễn Thái Ngọc Duy, Aug 15, 2011
  2. Junio C HamanoAug 15, 2011
  3. Nguyen Thai Ngoc DuyAug 16, 2011
  4. Junio C HamanoAug 16, 2011
  5. Nguyen Thai Ngoc DuyAug 17, 2011
  6. commit: accept tag objects in HEAD/MERGE_HEADNguyễn Thái Ngọc Duy, Aug 17, 2011
  7. Junio C HamanoAug 17, 2011
  8. Nguyen Thai Ngoc DuyAug 18, 2011
  9. Accept tags in HEAD or MERGE_HEADNguyễn Thái Ngọc Duy, Aug 18, 2011
  10. Junio C HamanoAug 18, 2011
  11. Nguyen Thai Ngoc DuyAug 19, 2011
  12. 1/4 commit: remove global variable head_sha1[]Nguyễn Thái Ngọc Duy, Aug 19, 2011
  13. 2/4 merge: keep stash[] a local variableNguyễn Thái Ngọc Duy, Aug 19, 2011
  14. Junio C HamanoAug 19, 2011
  15. 3/4 merge: remove global variable head[]Nguyễn Thái Ngọc Duy, Aug 19, 2011
  16. Junio C HamanoAug 23, 2011
  17. 4/4 Accept tags in HEAD or MERGE_HEADNguyễn Thái Ngọc Duy, Aug 19, 2011
  18. Junio C HamanoAug 19, 2011
  19. Nguyen Thai Ngoc DuyAug 20, 2011
  20. Junio C HamanoAug 19, 2011
  21. Nguyen Thai Ngoc DuyAug 20, 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.