All of lore.kernel.org
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: Joel Teichroeb <joel@teichroeb.net>
Cc: "Git Mailing List" <git@vger.kernel.org>,
	"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
	"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
	"Jeff King" <peff@peff.net>,
	"Christian Couder" <christian.couder@gmail.com>
Subject: Re: [PATCH v4 5/5] stash: implement builtin stash
Date: Fri, 16 Jun 2017 09:15:51 -0700	[thread overview]
Message-ID: <xmqqbmpnyklk.fsf@gitster.mtv.corp.google.com> (raw)
In-Reply-To: <20170608005535.13080-6-joel@teichroeb.net> (Joel Teichroeb's message of "Wed, 7 Jun 2017 17:55:35 -0700")

Joel Teichroeb <joel@teichroeb.net> writes:

> diff --git a/builtin/stash.c b/builtin/stash.c
> new file mode 100644
> index 0000000000..a9680f2909
> --- /dev/null
> +++ b/builtin/stash.c
> ...
> +static const char *ref_stash = "refs/stash";
> +static int quiet = 0;

Let BSS take care of zero-initialization, i.e. drop " = 0".

> +static int untracked_files(struct strbuf *out, int include_untracked,
> +		int include_ignored, const char **argv)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "ls-files", "-o", "-z", NULL);
> +	if (include_untracked && !include_ignored)
> +		argv_array_push(&cp.args, "--exclude-standard");
> +	argv_array_push(&cp.args, "--");
> +	if (argv)
> +		argv_array_pushv(&cp.args, argv);
> +	return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
> +}

Seeing that include_untracked and include_ignored always come in a
pair throughout the program, I wondered if it may be better to use
a single "unsigned include" with two bits

    #define INCLUDE_UNTRACKED 01
    #define INCLUDE_IGNORED 02

to pass around.  As long as we envision that we will not gain other
kind of "do we include X?" in the future, what your patch does is
fine, I would say.

> +static int check_no_changes(const char *prefix, int include_untracked,
> +		int include_ignored, const char **argv)
> +{
> +	struct argv_array args1 = ARGV_ARRAY_INIT;
> +	struct argv_array args2 = ARGV_ARRAY_INIT;
> +	struct strbuf out = STRBUF_INIT;
> +	int ret;
> +
> +	argv_array_pushl(&args1, "diff-index", "--quiet", "--cached", "HEAD",
> +		"--ignore-submodules", "--", NULL);
> +	if (argv)
> +		argv_array_pushv(&args1, argv);
> +
> +	argv_array_pushl(&args2, "diff-files", "--quiet", "--ignore-submodules",
> +		"--", NULL);
> +	if (argv)
> +		argv_array_pushv(&args2, argv);
> +
> +	if (include_untracked)
> +		untracked_files(&out, include_untracked, include_ignored, argv);
> +
> +	ret = cmd_diff_index(args1.argc, args1.argv, prefix) == 0 &&
> +			cmd_diff_files(args2.argc, args2.argv, prefix) == 0 &&
> +			(!include_untracked || out.len == 0);

When diff_index() finds there are modified paths, you do not have to
call diff_files() or untracked_files() at all (and you do not even
have to set-up args2).  Doesn't the above leak args.argv[] when &&
short circuits?

    This is a tangent, but it is somewhat unusual to call cmd_foo()
    as a subroutine.  I think cmd_diff_*() are written reasonably
    well to allow them to be called in this way safely, and there
    are a few existing commands that already do so, so it may be OK.

> +	strbuf_release(&out);
> +	return ret;
> +}
> +
> +static int get_stash_info(struct stash_info *info, const char *commit)
> +{
> +	struct strbuf w_commit_rev = STRBUF_INIT;
> +	struct strbuf b_commit_rev = STRBUF_INIT;
> +	struct strbuf w_tree_rev = STRBUF_INIT;
> +	struct strbuf b_tree_rev = STRBUF_INIT;
> +	struct strbuf i_tree_rev = STRBUF_INIT;
> +	struct strbuf u_tree_rev = STRBUF_INIT;
> +	struct strbuf commit_buf = STRBUF_INIT;
> +	struct strbuf symbolic = STRBUF_INIT;
> +	struct strbuf out = STRBUF_INIT;
> +	int ret;
> +	const char *revision = commit;
> +	char *end_of_rev;
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +	info->is_stash_ref = 0;
> +
> +	if (commit == NULL) {
> +		strbuf_addf(&commit_buf, "%s@{0}", ref_stash);
> +		revision = commit_buf.buf;
> +	} else if (strlen(commit) < 3) {

This is a bit sloppy (the original is even sloppier but it is in
shell, so it is more excusable ;-).  This code thinks that anything
with @{<num>} must be longer than 3 because it has to have @{},
and that is where the strlen() comes from, I think, but the magic
number 3 appears without explanation here.

What the code actually needs to do is to see if the stash entry
specification came in "commit" (which by the way is a bit misnamed
parameter) is a bare number and use refs/stash@{<that number>} only
in that case, I think.  strspn() might be useful.

> +		strbuf_addf(&commit_buf, "%s@{%s}", ref_stash, commit);
> +		revision = commit_buf.buf;
> +	}
> +	info->revision = revision;
> +
> +	strbuf_addf(&w_commit_rev, "%s", revision);
> +	strbuf_addf(&b_commit_rev, "%s^1", revision);
> +	strbuf_addf(&w_tree_rev, "%s:", revision);
> +	strbuf_addf(&b_tree_rev, "%s^1:", revision);
> +	strbuf_addf(&i_tree_rev, "%s^2:", revision);
> +	strbuf_addf(&u_tree_rev, "%s^3:", revision);
> +
> +	ret = (get_sha1(w_commit_rev.buf, info->w_commit.hash) == 0 &&
> +		get_sha1(b_commit_rev.buf, info->b_commit.hash) == 0 &&
> +		get_sha1(w_tree_rev.buf, info->w_tree.hash) == 0 &&
> +		get_sha1(b_tree_rev.buf, info->b_tree.hash) == 0 &&
> +		get_sha1(i_tree_rev.buf, info->i_tree.hash) == 0);

It's more conventional to check for errors with !get_sha1(params),
not a long-hand comparision with 0.

> +	strbuf_release(&w_commit_rev);
> +	strbuf_release(&b_commit_rev);
> +	strbuf_release(&w_tree_rev);
> +	strbuf_release(&b_tree_rev);
> +	strbuf_release(&i_tree_rev);
> +
> +	if (!ret)
> +		return error(_("%s is not a valid reference"), revision);

We are leaking u_tree_rev.buf upon early return.

> +	info->has_u = get_sha1(u_tree_rev.buf, info->u_tree.hash) == 0;
> +
> +	strbuf_release(&u_tree_rev);
> +
> +	end_of_rev = strchrnul(revision, '@');
> +	strbuf_add(&symbolic, revision, end_of_rev - revision);
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "rev-parse", "--symbolic-full-name", NULL);
> +	argv_array_pushf(&cp.args, "%s", symbolic.buf);
> +	strbuf_release(&symbolic);
> +	pipe_command(&cp, NULL, 0, &out, 0, NULL, 0);
> +
> +	if (out.len-1 == strlen(ref_stash))
> +		info->is_stash_ref = strncmp(out.buf, ref_stash, out.len-1) == 0;

Favor !strncmp(params) over comparision with 0.

Style: Have SP around both sides of binary operator "-".

> +	strbuf_release(&out);
> +	return !ret;

Hmph, where did we last assign ret in this code?  Didn't we check
that value and returned error already, which means we know what !ret
is when the control reaches here?

> +}

I have to move to another building, so I'll stop here for now, but
will continue later.

Thanks.


  parent reply	other threads:[~2017-06-16 16:15 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-08  0:55 [PATCH v4 0/5] Implement git stash as a builtin command Joel Teichroeb
2017-06-08  0:55 ` [PATCH v4 1/5] stash: add test for stash create with no files Joel Teichroeb
2017-06-13 19:31   ` Junio C Hamano
2017-06-08  0:55 ` [PATCH v4 2/5] stash: Add a test for when apply fails during stash branch Joel Teichroeb
2017-06-13 19:40   ` Junio C Hamano
2017-06-13 19:54     ` Joel Teichroeb
2017-06-08  0:55 ` [PATCH v4 3/5] stash: add test for stashing in a detached state Joel Teichroeb
2017-06-13 19:45   ` Junio C Hamano
2017-06-13 19:48     ` Joel Teichroeb
2017-06-13 20:58       ` Junio C Hamano
2017-06-08  0:55 ` [PATCH v4 4/5] merge: close the index lock when not writing the new index Joel Teichroeb
2017-06-13 19:47   ` Junio C Hamano
2017-06-08  0:55 ` [PATCH v4 5/5] stash: implement builtin stash Joel Teichroeb
2017-06-11 21:27   ` Thomas Gummerer
2017-06-20  2:37     ` Joel Teichroeb
2017-06-25 21:09       ` Thomas Gummerer
2017-06-26  7:53         ` Matthieu Moy
2017-06-27 14:53           ` Thomas Gummerer
2017-06-16 16:15   ` Junio C Hamano [this message]
2017-06-16 22:47   ` Junio C Hamano
2017-06-19 13:16     ` Johannes Schindelin
2017-06-19 13:20       ` Jeff King
2017-06-20  2:12     ` Joel Teichroeb
2017-06-22 17:23       ` Junio C Hamano
2017-06-22 17:07   ` Junio C Hamano
2017-06-11 17:40 ` [PATCH v4 0/5] Implement git stash as a builtin command Joel Teichroeb

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=xmqqbmpnyklk.fsf@gitster.mtv.corp.google.com \
    --to=gitster@pobox.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=avarab@gmail.com \
    --cc=christian.couder@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=joel@teichroeb.net \
    --cc=peff@peff.net \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.