From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:00
The new function add_alt_odb() can be used to add alternate object
databases dynamically (i.e. after parsing of objects/info/alternates).
It will be used by git-archive to implement inclusion of submodules
by adding submodule object databases during tree traversal.
To make the function usable from call-sites which doesn't require the
add_alt_odb() to succeed, it takes a 'quiet' parameter which is passed
on to the underlying alt-odb-related functions.
Signed-off-by: Lars Hjemli <redacted>
---
cache.h | 1 +
sha1_file.c | 40 +++++++++++++++++++++++++++-------------
2 files changed, 28 insertions(+), 13 deletions(-)
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:00
The new --submodules option is used to trigger inclusion of checked
out submodules in the archive.
The implementation currently does not verify that the submodule has
been registered as 'interesting' in .git/config, neither does it resolve
the currently checked out submodule HEAD but instead uses the commit SHA1
recorded in the gitlink entry to identify the submodule root tree.
The plan is to fix these limitations by extending --submodules to allow
certain flags/options:
a|c|r include any|checked out|registered submodules
H resolve submodule HEAD to decide which tree to include
g:<name> only include submodules in group <name>
The syntax would then become '--submodules[=[a|c|r][H][g:<name>]]' and
group membership could be specified in .git/config and/or .gitmodules.
The current behavior would then match '--submodules=c' (which might be a
sensible default when only --submodules is specified).
Signed-off-by: Lars Hjemli <redacted>
---
Documentation/git-archive.txt | 3 +
archive.c | 53 ++++++++++++++++++-
archive.h | 1 +
t/t5001-archive-submodules.sh | 121 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 177 insertions(+), 1 deletions(-)
create mode 100755 t/t5001-archive-submodules.sh
@@ -51,6 +51,9 @@ OPTIONS This can be any options that the archiver backend understand. See next section.+--submodules::+ Include all checked out submodules in the archive.+ --remote=<repo>:: Instead of making a tar archive from local repository, retrieve a tar archive from a remote repository.
@@ -96,6 +96,52 @@ struct archiver_context {write_archive_entry_fn_twrite_entry;};+/* Given the root directory of a non-bare repository, return the path+*tothecorrespondingGITDIR,orNULLifnotfound.Thereturn-value+*ismalloc'dbythisfunctionandshouldbefree'dbythecaller.+*/+staticchar*get_gitdir(constchar*root)+{+constchar*path,*tmp;+structstatst;++if(!root)+returnNULL;++if(root[strlen(root)-1]=='/')+path=mkpath("%s.git",root);+else+path=mkpath("%s/.git",root);++tmp=read_gitfile_gently(path);+if(tmp)+path=tmp;++if(stat(path,&st)||!S_ISDIR(st.st_mode))+returnNULL;+returnxstrdup(path);+}++/* Return READ_TREE_RECURSIVE if we should recurse into the gitlinked+*repositoryor0ifitshouldbeskipped.+*/+staticintrecurse_gitlink(structarchiver_args*args,constchar*path)+{+char*gitdir;+char*objdir;++if(!args->submodules)+return0;+gitdir=get_gitdir(path);+if(!gitdir)+return0;+objdir=mkpath("%s/objects",gitdir);+free(gitdir);+if(add_alt_odb(objdir,0))+return-1;+returnREAD_TREE_RECURSIVE;+}+staticintwrite_archive_entry(constunsignedchar*sha1,constchar*base,intbaselen,constchar*filename,unsignedmode,intstage,void*context)
@@ -262,6 +310,8 @@ static int parse_archive_args(int argc, const char **argv,OPT_STRING(0,"format",&format,"fmt","archive format"),OPT_STRING(0,"prefix",&base,"prefix","prepend prefix to each pathname in the archive"),+OPT_BOOLEAN(0,"submodules",&submodules,+"include checked out submodules in the archive"),OPT__VERBOSE(&verbose),OPT__COMPR('0',&compression_level,"store only",0),OPT__COMPR('1',&compression_level,"compress faster",1),
@@ -0,0 +1,121 @@+#!/bin/sh++test_description='git archive can include submodule content'++../test-lib.sh++add_file()+{+gitadd$1&&+gitcommit-m"added $1"+}++add_submodule()+{+mkdir$1&&(+cd$1&&+gitinit&&+echo"File $2">$2&&+add_file$2+)&&+add_file$1+}++test_expect_success'by default, all submodules are ignored''+echo"File 1">1&&+add_file1&&+add_submodule23&&+add_submodule45&&+cat<<EOF>expected&&+1+2/+4/+EOF+gitarchiveHEAD>normal.tar&&+tar-tfnormal.tar>actual&&+test_cmpexpectedactual+'++test_debug'tar -tf normal.tar'++test_expect_success'with --submodules, checked-out submodules are included''+cat<<EOF>expected&&+1+2/+2/3+4/+4/5+EOF+gitarchive--submodulesHEAD>full.tar&&+tar-tffull.tar>actual&&+test_cmpexpectedactual+'++test_debug'tar -tf full.tar'++test_expect_success'submodules in submodules are supported''+(cd4&&add_submodule67)&&+add_file4&&+cat<<EOF>expected&&+1+2/+2/3+4/+4/5+4/6/+4/6/7+EOF+gitarchive--submodulesHEAD>recursive.tar&&+tar-tfrecursive.tar>actual&&+test_cmpexpectedactual+'++test_debug'tar -tf recursive.tar'++test_expect_success'packed submodules are supported''+cat<<EOF>expected&&+1+2/+2/3+4/+4/5+4/6/+4/6/7+EOF+msg=$(cd2&&gitrepack-ad&&gitcount-objects)&&+test"$msg"="0 objects, 0 kilobytes"&&+gitarchive--submodulesHEAD>packed.tar&&+tar-tfpacked.tar>actual&&+test_cmpexpectedactual+'++test_debug'tar -tf packed.tar'++test_expect_success'a missing submodule pack triggers an error''+find2/.git/objects/pack-typef|xargsrm&&+test_must_failgitarchive--submodulesHEAD+'++test_expect_success'non-checked out submodules are ignored''+cat<<EOF>expected&&+1+2/+4/+4/5+4/6/+4/6/7+EOF+rm-rf2/.git&&+gitarchive--submodulesHEAD>partial.tar&&+tar-tfpartial.tar>actual&&+test_cmpexpectedactual+'++test_debug'tar -tf partial.tar'++test_expect_success'missing objects in a submodule triggers an error''+find4/.git/objects-typef|xargsrm&&+test_must_failgitarchive--submodulesHEAD+'++test_done
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:00
When the callback function invoked from read_tree_recursive() returns
`READ_TREE_RECURSIVE` for a gitlink entry, the traversal will now
continue into the tree connected to the gitlinked commit. It is the
responsibility of the callback function to somehow make the gitlinked
commit (and corresponding tree/blob) objects available, possibly by
inserting the submodule object database as an alternate odb.
Also, all existing callback function has been updated to only return
READ_TREE_RECURSIVE for directory entries, so this patch should not
introduce any changes to current behavior.
Signed-off-by: Lars Hjemli <redacted>
---
archive.c | 2 +-
builtin-ls-tree.c | 9 ++-------
merge-recursive.c | 2 +-
tree.c | 28 ++++++++++++++++++++++++++++
4 files changed, 32 insertions(+), 9 deletions(-)
@@ -131,6 +131,34 @@ int read_tree_recursive(struct tree *tree,if(retval)return-1;continue;+}elseif(S_ISGITLINK(entry.mode)){+intretval;+structstrbufpath;+unsignedintentrylen;+structcommit*commit;++entrylen=tree_entry_len(entry.path,entry.sha1);+strbuf_init(&path,baselen+entrylen+1);+strbuf_add(&path,base,baselen);+strbuf_add(&path,entry.path,entrylen);+strbuf_addch(&path,'/');++commit=lookup_commit(entry.sha1);+if(!commit)+die("Commit %s in submodule path %s not found",+sha1_to_hex(entry.sha1),path.buf);++if(parse_commit(commit))+die("Invalid commit %s in submodule path %s",+sha1_to_hex(entry.sha1),path.buf);++retval=read_tree_recursive(commit->tree,+path.buf,path.len,+stage,match,fn,context);+strbuf_release(&path);+if(retval)+return-1;+continue;}}return0;
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:00
Hi,
On Thu, 22 Jan 2009, Lars Hjemli wrote:
quoted hunk
@@ -285,9 +286,10 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative /* Detect cases where alternate disappeared */ if (!is_directory(ent->base)) {- error("object directory %s does not exist; "- "check .git/objects/info/alternates.",- ent->base);+ if (!quiet)+ error("object directory %s does not exist; "+ "check .git/objects/info/alternates.",+ ent->base); free(ent); return -1; }
[...]
@@ -2573,3 +2579,11 @@ int read_pack_header(int fd, struct pack_header *header) return PH_ERROR_PROTOCOL; return 0; }++int add_alt_odb(char *path, int quiet)+{+ int err = link_alt_odb_entry(path, strlen(path), NULL, 0, quiet);+ if (!err)+ prepare_packed_git_one(path, 0);+ return err;+}
FWIW my concern is not at all addressed. A future user of add_alt_odb()
(and possibly your users in rare cases, too) can trigger the error that
suggests looking into the alternates. Leaving the human user puzzled.
Ciao,
Dscho
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:00
Hi,
On Thu, 22 Jan 2009, Lars Hjemli wrote:
The new --submodules option is used to trigger inclusion of checked out
submodules in the archive.
The implementation currently does not verify that the submodule has been
registered as 'interesting' in .git/config, neither does it resolve the
currently checked out submodule HEAD but instead uses the commit SHA1
recorded in the gitlink entry to identify the submodule root tree.
Please understand that I skipped the rest of the patch.
Ciao,
Dscho
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:01
On Fri, Jan 23, 2009 at 00:43, Johannes Schindelin
[off-list ref] wrote:
On Thu, 22 Jan 2009, Lars Hjemli wrote:
quoted
+ if (!quiet)
+ error("object directory %s does not exist; "
+ "check .git/objects/info/alternates.",
+ ent->base);
FWIW my concern is not at all addressed. A future user of add_alt_odb()
(and possibly your users in rare cases, too) can trigger the error that
suggests looking into the alternates. Leaving the human user puzzled.
Is it the phrasing of the error message that concerns you (when
invoked from add_alt_odb())?
If so, would something like this be ok/better?
quoted
+ if (!quiet)
+ error("Alternate object directory %s does not exist ",
+ ent->base);
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:01
On Fri, Jan 23, 2009 at 00:44, Johannes Schindelin
[off-list ref] wrote:
On Thu, 22 Jan 2009, Lars Hjemli wrote:
quoted
The new --submodules option is used to trigger inclusion of checked out
submodules in the archive.
The implementation currently does not verify that the submodule has been
registered as 'interesting' in .git/config, neither does it resolve the
currently checked out submodule HEAD but instead uses the commit SHA1
recorded in the gitlink entry to identify the submodule root tree.
Please understand that I skipped the rest of the patch.
That's too bad, I hoped on some feedback from you on the part of the
commit message which you didn't quote:
quoted
The plan is to fix these limitations by extending --submodules to allow
certain flags/options:
a|c|r include any|checked out|registered submodules
H resolve submodule HEAD to decide which tree to include
g:<name> only include submodules in group <name>
The syntax would then become '--submodules[=[a|c|r][H][g:<name>]]' and
group membership could be specified in .git/config and/or .gitmodules.
The current behavior would then match '--submodules=c' (which might be a
sensible default when only --submodules is specified).
Wouldn't such an option address your concern about the
consistency/semantics of the --submodules operation?
--
larsh
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:01
Hi,
On Fri, 23 Jan 2009, Lars Hjemli wrote:
On Fri, Jan 23, 2009 at 00:43, Johannes Schindelin
[off-list ref] wrote:
quoted
On Thu, 22 Jan 2009, Lars Hjemli wrote:
quoted
+ if (!quiet)
+ error("object directory %s does not exist; "
+ "check .git/objects/info/alternates.",
+ ent->base);
FWIW my concern is not at all addressed. A future user of add_alt_odb()
(and possibly your users in rare cases, too) can trigger the error that
suggests looking into the alternates. Leaving the human user puzzled.
Is it the phrasing of the error message that concerns you (when
invoked from add_alt_odb())?
If so, would something like this be ok/better?
quoted
quoted
+ if (!quiet)
+ error("Alternate object directory %s does not exist ",
+ ent->base);
That would almost certainly be better.
Ciao,
Dscho
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:01
Hi,
On Fri, 23 Jan 2009, Lars Hjemli wrote:
On Fri, Jan 23, 2009 at 00:44, Johannes Schindelin
[off-list ref] wrote:
quoted
On Thu, 22 Jan 2009, Lars Hjemli wrote:
quoted
The new --submodules option is used to trigger inclusion of checked out
submodules in the archive.
The implementation currently does not verify that the submodule has
been registered as 'interesting' in .git/config, neither does it
resolve the currently checked out submodule HEAD but instead uses the
commit SHA1 recorded in the gitlink entry to identify the submodule
root tree.
Please understand that I skipped the rest of the patch.
That's too bad, I hoped on some feedback from you on the part of the
commit message which you didn't quote:
Well, you ignored my comments, so what do you expect me to do? Be happy?
There are two issues there:
- presence of a specific commit object being present in the repository
does not necessarily mean that it is reachable by any ref, and therefore
can mean that the tree/blob objects are not reachable, because it could
be an interrupted fetch; in all of Git, we try to assume that only
reachable objects are valid objects.
- presence of a specific commit in the supermodule is a _lousy_ indicator
that the user wants to include that submodule in the archive.
Until both issues are addresse, I will not dance a little song and be
merry over this issue.
Ciao,
Dscho
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:01
On Fri, Jan 23, 2009 at 20:57, Johannes Schindelin
[off-list ref] wrote:
On Fri, 23 Jan 2009, Lars Hjemli wrote:
quoted
That's too bad, I hoped on some feedback from you on the part of the
commit message which you didn't quote:
Well, you ignored my comments,
I might have misunderstood your comments, but I certainly didn't
ignore them. I actually tried to come up with a solution that would
solve your concerns about which submodules to include in the archive
(which is why I hoped for some feedback on that proposal).
so what do you expect me to do? Be happy?
There are two issues there:
- presence of a specific commit object being present in the repository
does not necessarily mean that it is reachable by any ref, and therefore
can mean that the tree/blob objects are not reachable, because it could
be an interrupted fetch;
This part I agree with.
in all of Git, we try to assume that only
reachable objects are valid objects.
I don't think this is true (most git commands accepts their arguments
as valid objects without verifying if they are reachable from a ref).
Do you feel it is necessary to perform a reachability check of the
gitlink'd commit before traversing into a submodule tree?
- presence of a specific commit in the supermodule is a _lousy_ indicator
that the user wants to include that submodule in the archive.
This is the issue I tried to address with my
`--submodules=[a|c|r][g:<name>]` proposal in the commit message for
this patch. I hoped you would find it interesting, given your comments
in http://thread.gmane.org/gmane.comp.version-control.git/106167/focus=106235
(i.e. my 'a' flag would match your 'look-in-superprojects-odb', while
the 'c', 'r' and 'g' options would address your issues about how to
select the correct set of submodules).
--
larsh
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:01
Hi,
On Sat, 24 Jan 2009, Lars Hjemli wrote:
On Fri, Jan 23, 2009 at 20:57, Johannes Schindelin
[off-list ref] wrote:
quoted
in all of Git, we try to assume that only reachable objects are valid
objects.
I don't think this is true (most git commands accepts their arguments
as valid objects without verifying if they are reachable from a ref).
The fact that a user can ask for some object directly, and that we do not
try to validate it in that case has nothing to do with said assumption.
If something is pushed to a remote, and the connection fails, some commit
could be pushed already, but some of its reachable objects lacking.
The user on the remote side can still try to salvage parts by accessing
the objects directly, by their name.
But the only guarantee that the objects are reachable is to start from a
ref.
Concretely, if your patch is applied as-is, such a half-pushed state could
affect git-archive in a nasty way: even if the user started from a ref,
there could be missing objects!
Do you feel it is necessary to perform a reachability check of the
gitlink'd commit before traversing into a submodule tree?
No. Because HEAD is a ref, too.
Now, there is still a problem when your submodule is missing the objects
for the commit your superproject is referring to.
IMO that is a serious issue, as it just asks for confused users.
quoted
- presence of a specific commit in the supermodule is a _lousy_
indicator that the user wants to include that submodule in the
archive.
This is the issue I tried to address with my
`--submodules=[a|c|r][g:<name>]` proposal in the commit message for
this patch.
Nope, doing this "in the future" does not please me one bit.
Besides, I find the semantics, uhm, "interesting". (The other word would
be "unintuitive". Why do you have to be so cryptic that I have to read
the proposal to understand what the heck "c" is about?)
Ciao,
Dscho
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:01
On Sat, Jan 24, 2009 at 14:51, Johannes Schindelin
[off-list ref] wrote:
Now, there is still a problem when your submodule is missing the objects
for the commit your superproject is referring to.
IMO that is a serious issue, as it just asks for confused users.
This made me finally understand your concern (sorry for being slow):
you want the command to behave in a predictable/consistent way while
my implementation would end up making an archive with basically random
content.
quoted
quoted
- presence of a specific commit in the supermodule is a _lousy_
indicator that the user wants to include that submodule in the
archive.
This is the issue I tried to address with my
`--submodules=[a|c|r][g:<name>]` proposal in the commit message for
this patch.
Nope, doing this "in the future" does not please me one bit.
Besides, I find the semantics, uhm, "interesting". (The other word would
be "unintuitive". Why do you have to be so cryptic that I have to read
the proposal to understand what the heck "c" is about?)
I thought it would be nifty to be able to combine different flags
which would affect the behaviour/semantics of the command, but given
the comments from you and Junio, I think I'll end up with something
like this:
$ git archive --submodules <tree-ish>: Create an archive which
includes the trees of all gitlink entries in <tree-ish>, fail unless
all the required objects are available.
$ git archive --submodules=<group>: Same as above, but only traverse
submodules in the specified group (as defined in $GIT_CONFIG).
--
larsh
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:01
Hi,
On Sat, 24 Jan 2009, Lars Hjemli wrote:
$ git archive --submodules <tree-ish>: Create an archive which
includes the trees of all gitlink entries in <tree-ish>, fail unless
all the required objects are available.
$ git archive --submodules=<group>: Same as above, but only traverse
submodules in the specified group (as defined in $GIT_CONFIG).
How about having the former with --submodules='*' and let --submodules
without argument include those submodules that are checked out (none in a
bare repository)?
Thanks,
Dscho
From: Lars Hjemli <hidden> Date: 2016-06-15 22:46:01
On Sat, Jan 24, 2009 at 20:52, Johannes Schindelin
[off-list ref] wrote:
Hi,
On Sat, 24 Jan 2009, Lars Hjemli wrote:
quoted
$ git archive --submodules <tree-ish>: Create an archive which
includes the trees of all gitlink entries in <tree-ish>, fail unless
all the required objects are available.
$ git archive --submodules=<group>: Same as above, but only traverse
submodules in the specified group (as defined in $GIT_CONFIG).
How about having the former with --submodules='*' and let --submodules
without argument include those submodules that are checked out (none in a
bare repository)?
Yeah, that might make more sense (since you'd normally not have access
to the content of non-checked out submodules). I'm also considering
something like --submodules[=(all|checkedout|[group:]<name>)], i.e.
the 'group:'-part could be optional as long as <name> is unambiguous.
--
larsh