"Heather Lapointe via GitGitGadget" <gitgitgadget@xxxxxxxxx> writes: > @@ -47,40 +48,73 @@ int read_tree_at(struct repository *r, > return -1; > } > > - if (S_ISDIR(entry.mode)) > + if (S_ISDIR(entry.mode)) { > oidcpy(&oid, &entry.oid); > - else if (S_ISGITLINK(entry.mode)) { > - struct commit *commit; > > - commit = lookup_commit(r, &entry.oid); > + len = tree_entry_len(&entry); > + strbuf_add(base, entry.path, len); > + strbuf_addch(base, '/'); > + retval = read_tree_at(r, lookup_tree(r, &oid), > + base, pathspec, > + fn, context); > + strbuf_setlen(base, oldlen); > + if (retval) > + return -1; > + } else if (pathspec->recurse_submodules && S_ISGITLINK(entry.mode)) { > + struct commit *commit; > + struct repository subrepo; > + struct repository* subrepo_p = &subrepo; > + struct tree* submodule_tree; > + char *submodule_rel_path; > + int name_base_len = 0; > + > + len = tree_entry_len(&entry); > + strbuf_add(base, entry.path, len); > + submodule_rel_path = base->buf; > + // repo_submodule_init expects a path relative to submodule_prefix > + if (r->submodule_prefix) { > + name_base_len = strlen(r->submodule_prefix); > + // we should always expect to start with submodule_prefix > + assert(!strncmp(submodule_rel_path, r->submodule_prefix, name_base_len)); > + // strip the prefix > + submodule_rel_path += name_base_len; > + // if submodule_prefix doesn't end with a /, we want to get rid of that too > + if (is_dir_sep(submodule_rel_path[0])) { > + submodule_rel_path++; > + } > + } > + > + if (repo_submodule_init(subrepo_p, r, submodule_rel_path, null_oid())) > + die("couldn't init submodule %s", base->buf); > + > + if (repo_read_index(subrepo_p) < 0) > + die("index file corrupt"); > + > + commit = lookup_commit(subrepo_p, &entry.oid); > if (!commit) > - die("Commit %s in submodule path %s%s not found", > + die("Commit %s in submodule path %s not found", > oid_to_hex(&entry.oid), > - base->buf, entry.path); > - > - // FIXME: This is the wrong repo instance (it refers to the superproject) > - // it will always fail as is (will fix in later patch) > - // This current codepath isn't executed by any existing callbacks > - // so it wouldn't show up as an issue at this time. > - if (repo_parse_commit(r, commit)) > - die("Invalid commit %s in submodule path %s%s", > + base->buf); > + > + if (repo_parse_commit(subrepo_p, commit)) > + die("Invalid commit %s in submodule path %s", > oid_to_hex(&entry.oid), > - base->buf, entry.path); > + base->buf); > > - oidcpy(&oid, get_commit_tree_oid(commit)); > - } > - else > - continue; > + submodule_tree = repo_get_commit_tree(subrepo_p, commit); > + oidcpy(&oid, submodule_tree ? &submodule_tree->object.oid : NULL); > > - len = tree_entry_len(&entry); > - strbuf_add(base, entry.path, len); > - strbuf_addch(base, '/'); > - retval = read_tree_at(r, lookup_tree(r, &oid), > - base, pathspec, > - fn, context); > - strbuf_setlen(base, oldlen); > - if (retval) > - return -1; > + strbuf_addch(base, '/'); > + > + retval = read_tree_at(subrepo_p, lookup_tree(subrepo_p, &oid), > + base, pathspec, > + fn, context); > + if (retval) > + die("failed to read tree for %s", base->buf); > + strbuf_setlen(base, oldlen); > + repo_clear(subrepo_p); > + } > + // else, this is a file (or a submodule, but no pathspec->recurse_submodules) In this patch, we say that we can ignore a submodule when pathspec->recurse_submodules is 0, but unless I'm missing something, I don't think that's the case. The preimage is: else if (S_ISGITLINK(entry.mode)) { struct commit *commit; commit = lookup_commit(r, &entry.oid); if (!commit) die("Commit %s in submodule path %s%s not found", oid_to_hex(&entry.oid), base->buf, entry.path); /* ... */ if (repo_parse_commit(r, commit)) die("Invalid commit %s in submodule path %s%s", oid_to_hex(&entry.oid), base->buf, entry.path); oidcpy(&oid, get_commit_tree_oid(commit)); } else continue; len = tree_entry_len(&entry); strbuf_add(base, entry.path, len); strbuf_addch(base, '/'); retval = read_tree_at(r, lookup_tree(r, &oid), base, pathspec, fn, context); which isn't a no-op since we actually do recurse into the gitlink. I don't know whether the subsequent call actually succeeds though (e.g. maybe it always failed and it was just a de facto no-op?), but that's much harder to prove. Since this function has callers outside of "git archive", it would be better to be conservative and keep the original behavior in the S_ISGITLINK(entry.mode) && !pathspec->recurse_submodules case. > } > return 0; > } > -- > gitgitgadget