git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff King <peff@peff.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, Eric Sunshine <sunshine@sunshineco.com>
Subject: Re: [PATCH v3 08/14] remote.c: report specific errors from branch_get_upstream
Date: Thu, 21 May 2015 14:49:10 -0400	[thread overview]
Message-ID: <20150521184910.GA3490@peff.net> (raw)
In-Reply-To: <xmqq7fs1kcfd.fsf@gitster.dls.corp.google.com>

On Thu, May 21, 2015 at 11:33:58AM -0700, Junio C Hamano wrote:

> > +static const char *error_buf(struct strbuf *err, const char *fmt, ...)
> >  {
> > -	if (!branch || !branch->merge || !branch->merge[0])
> > -		return NULL;
> > +	if (err) {
> > +		va_list ap;
> > +		va_start(ap, fmt);
> > +		strbuf_vaddf(err, fmt, ap);
> > +		va_end(ap);
> > +	}
> > +	return NULL;
> > +}
> 
> Many of our functions return -1 to signal an error, and that is why
> it makes sense for our error() helper to return -1 to save code in
> the caller, but only because the callers of this private helper use
> a NULL to signal an error, this also returns NULL.  If we were to
> use the "callers can opt into detailed message by passing strbuf"
> pattern more widely, we would want a variant of the above that
> returns -1, too.  And such a helper would do the same thing as
> above, with only difference from the above is to return -1.

Yeah, this is not really a good general-purpose purpose function in that
sense. I have often wanted an error() that returns NULL, but avoided
adding just because it seemed like needless proliferation.

The real reason to include the return value at all in error() is to let
you turn two-liners into one-liners. We could drop the return value from
this helper entirely (or make it -1, but of course no callers would use
it) and write it out long-hand in the callers:

  if (!branch->merge) {
	error_buf(err, ...);
	return NULL;
  }

That is really not so bad, as there are only a handful of callers.

> > +const char *branch_get_upstream(struct branch *branch, struct strbuf *err)
> > +{
> > +	if (!branch)
> > +		return error_buf(err, _("HEAD does not point to a branch"));
> > +	if (!branch->merge || !branch->merge[0] || !branch->merge[0]->dst) {
> > +		if (!ref_exists(branch->refname))
> > +			return error_buf(err, _("no such branch: '%s'"),
> > +					 branch->name);
> > +		if (!branch->merge)
> > +			return error_buf(err,
> > +					 _("no upstream configured for branch '%s'"),
> > +					 branch->name);
> > +		return error_buf(err,
> > +				 _("upstream branch '%s' not stored as a remote-tracking branch"),
> > +				 branch->merge[0]->src);
> > +	}
> > +
> >  	return branch->merge[0]->dst;
> >  }
> 
> This is a faithful conversion of what the get_upstream_branch() used
> to do, but that ref_exists() check and the error checking there look
> somewhat out of place.
> 
> It makes the reader wonder what should happen when "branch->refname"
> does not exist as a ref, but "branch->merge[0]->dst" can be fully
> dereferenced.  Should it be an error, or if it is OK, the reason why
> it is OK is...?

Yeah, my goal here was to faithfully keep the same logic, but I had a
similar head-scratching moment. What would make more sense to me is:

  if (!branch)
	return error("HEAD does not point to a branch");

  if (!branch->merge || !branch->merge[0]) {
	/*
	 * no merge config; is it because the user didn't define any, or
	 * because it is not a real branch, and get_branch auto-vivified
	 * it?
	 */
	if (!ref_exists(branch->refname))
		return error("no such branch");
	return error("no upstream configured for branch");
  }

  if (!branch->merge[0]->dst)
	return error("upstream branch not stored as a remote-tracking branch");

  return branch->merge[0]->dst;


Hopefully the comment there answers your question; it is not that we
truly care whether the ref exists, but only that we are trying to tell
the difference between a "real" branch and a struct that is an artifact
of our internal code.

Note also that the original may dereference branch->merge[0] even if it
is NULL. I think that can't actually happen in practice (we only
allocate branch->merge if we have at least one item to put in it, and
all of the checks of branch->merge[0] are actually being over-careful).
But the code I just wrote above does not have that problem.

-Peff

  reply	other threads:[~2015-05-21 18:49 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-21  4:44 [PATCH v3 0/14] implement @{push} shorthand Jeff King
2015-05-21  4:45 ` [PATCH v3 01/14] remote.c: drop default_remote_name variable Jeff King
2015-05-21  4:45 ` [PATCH v3 02/14] remote.c: refactor setup of branch->merge list Jeff King
2015-05-21 17:47   ` Junio C Hamano
2015-05-21  4:45 ` [PATCH v3 03/14] remote.c: drop "remote" pointer from "struct branch" Jeff King
2015-05-21  4:45 ` [PATCH v3 04/14] remote.c: hoist branch.*.remote lookup out of remote_get_1 Jeff King
2015-05-21  4:45 ` [PATCH v3 05/14] remote.c: provide per-branch pushremote name Jeff King
2015-05-21  4:45 ` [PATCH v3 06/14] remote.c: hoist read_config into remote_get_1 Jeff King
2015-05-21  4:45 ` [PATCH v3 07/14] remote.c: introduce branch_get_upstream helper Jeff King
2015-05-21 18:07   ` Junio C Hamano
2015-05-21 18:14     ` Jeff King
2015-05-21 18:35       ` Jeff King
2015-05-21 19:16         ` Junio C Hamano
2015-05-21  4:45 ` [PATCH v3 08/14] remote.c: report specific errors from branch_get_upstream Jeff King
2015-05-21 18:33   ` Junio C Hamano
2015-05-21 18:49     ` Jeff King [this message]
2015-05-21 19:25       ` Junio C Hamano
2015-05-22  0:46         ` Jeff King
2015-05-22  0:49           ` Jeff King
2015-05-21  4:45 ` [PATCH v3 09/14] remote.c: add branch_get_push Jeff King
2015-05-21  4:45 ` [PATCH v3 10/14] sha1_name: refactor upstream_mark Jeff King
2015-05-21  4:45 ` [PATCH v3 11/14] sha1_name: refactor interpret_upstream_mark Jeff King
2015-05-21  4:45 ` [PATCH v3 12/14] sha1_name: implement @{push} shorthand Jeff King
2015-05-21  4:45 ` [PATCH v3 13/14] for-each-ref: use skip_prefix instead of starts_with Jeff King
2015-05-21  4:45 ` [PATCH v3 14/14] for-each-ref: accept "%(push)" format Jeff King
2015-05-21  4:52 ` [PATCH v3 0/14] implement @{push} shorthand Jeff King
2015-05-21 18:37   ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150521184910.GA3490@peff.net \
    --to=peff@peff.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=sunshine@sunshineco.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).