Thread (27 messages) 27 messages, 2 authors, 2017-05-02

Re: [PATCH 5/6] submodule: improve submodule_has_commits

From: Stefan Beller <hidden>
Date: 2017-04-29 00:28:23

On Fri, Apr 28, 2017 at 4:54 PM, Brandon Williams [off-list ref] wrote:
Teach 'submodule_has_commits()' to ensure that if a commit exists in a
submodule, that it is also reachable from a ref.

This is a prepritory step prior to merging the logic which checkes for
s/prepritory/preparatory/
s/checkes/checks/

This is the first commit in the series that changes user observable behavior,
I guess there will be tests in a later patch? Can you elaborate in this commit
message more about why it is useful (or at least harmless for performing
this check in the case of fetch/push)?
quoted hunk ↗ jump to hunk
diff --git a/submodule.c b/submodule.c
index 3bcf44521..100d31d39 100644
--- a/submodule.c
+++ b/submodule.c
@@ -648,6 +648,30 @@ static int submodule_has_commits(const char *path, struct oid_array *commits)
                return 0;

        oid_array_for_each_unique(commits, check_has_commit, &has_commit);
+
+       if (has_commit) {
+               /*
+                * Even if the submodule is checked out and the commit is
+                * present, make sure it is reachable from a ref.
+                */
+               struct child_process cp = CHILD_PROCESS_INIT;
+               struct strbuf out = STRBUF_INIT;
+
+               argv_array_pushl(&cp.args, "rev-list", "-n", "1", NULL);
+               oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args);
+               argv_array_pushl(&cp.args, "--not", "--all", NULL);
+
+               prepare_submodule_repo_env(&cp.env_array);
+               cp.git_cmd = 1;
+               cp.no_stdin = 1;
+               cp.dir = path;
+
+               if (capture_command(&cp, &out, 1024) || out.len)
+                       has_commit = 0;
So if we fail to launch capture_command, we assume we do not
have the commits?

capture_command can fail for reasons that are hard to track down
or even spurious (OOM due to excessive output, disk failure,
corrupt repo, error in executing the process, getting a signal and
so on), some of them are ok to ignore, others should never be ignored.

So I'd rather die on capture_command, and inspect out.len only
in case of successful capturing.

In addition to that we're only interested if there is any output,
such that we can optimize further:
c.f. http://public-inbox.org/git/20170324223848.GH31294@aiede.mtv.corp.google.com/

    if (start_command(&cp))
        die("cannot start git-rev-list in submodule'%s', sub->path);

    /* read only one character, if any */
    if (xread(cp.out, &tmp, 1);
        has_commit = 0;

    /*
     * close cp.out, such that the child may get SIGPIPE, upon which
     * it dies (silently, maybe we need to suppress cp.err ?)
     */
    close(cp.out);

    /*
     * Though we need to be nitpicky about finish_command IIUC by now:
     * TODO(sbeller): if this turns out to be true, fixup is_submodule_modified
    */
    int code = finish_command(&cp);
    if (!code && code != 128 + SIGPIPE)
        die("git rev-list failed in submodule'%s'", sub->path);

Upon rereading the patch, I notice the '-n 1', which would make the
optimized code above useless, so just consider it food for thought.

Thanks,
Stefan
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help