If you have a project which is setup like: project website and you decide you wish to generate a tar archive of _just_ the 'project' portion, git-tar-tree is not able to help. This patch adds two parameters which can assist. The first is '--pathlimit', which forces git-tar-tree to only generate the tar archive for project; as in: 'git tar-tree --pathlimit=project project-1.0 tag-1.0' The above command will mean that paths in the tar archive look like: project-1.0/project/src/main.c etc. The second parameter allows you two strip the extraneous project, as in: 'git tar-tree --strippath=project --pathlimit=project project-1.0 tag-1.0 Which will result in tar archives looking like: project-1.0/src/main.c This patch also updates the documentation to match the new parameters and rewrites the argument processing so that arguments can be passed in any order by the user Signed-off-by: Anand Kumria <wildfire@xxxxxxxxxxx> --- Documentation/git-tar-tree.txt | 11 ++++++ tar-tree.c | 70 ++++++++++++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 18 deletions(-) diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt index 2139b6f..d123329 100644 --- a/Documentation/git-tar-tree.txt +++ b/Documentation/git-tar-tree.txt @@ -8,7 +8,7 @@ git-tar-tree - Creates a tar archive of SYNOPSIS -------- -'git-tar-tree' <tree-ish> [ <base> ] +'git-tar-tree' [--strippath=<path>] [--pathlimit=<path>] <tree-ish> [ <base> ] DESCRIPTION ----------- @@ -23,6 +23,15 @@ commit time as recorded in the reference Additionally the commit ID is stored in a global extended pax header. It can be extracted using git-get-tar-commit-id. +OPTIONS +------- +--strippath:: + Remove from the created tar archive the specified string from + any of the generated paths + +--pathlimit:: + Create the tar archive but limit the included files to be those + specified by the pathlimit Author ------ diff --git a/tar-tree.c b/tar-tree.c index fc60a90..78ae7ff 100644 --- a/tar-tree.c +++ b/tar-tree.c @@ -11,7 +11,7 @@ #include "tar.h" #define RECORDSIZE (512) #define BLOCKSIZE (RECORDSIZE * 20) -static const char tar_tree_usage[] = "git-tar-tree <key> [basedir]"; +static const char tar_tree_usage[] = "git-tar-tree [--strippath=<path>] [--pathlimit=<path>] <key> [basedir]"; static char block[BLOCKSIZE]; static unsigned long offset; @@ -265,7 +265,7 @@ static void write_global_extended_header free(ext_header.buf); } -static void traverse_tree(struct tree_desc *tree, struct strbuf *path) +static void traverse_tree(struct tree_desc *tree, struct strbuf *path, const char *namelimit, const char *strippath) { int pathlen = path->len; @@ -280,14 +280,25 @@ static void traverse_tree(struct tree_de sha1 = tree_entry_extract(tree, &name, &mode); update_tree_entry(tree); + /* if we have a namelimit and we don't match it, escape */ + if (namelimit) + if (!(strcmp(name,namelimit) == 0)) + continue; + eltbuf = read_sha1_file(sha1, elttype, &eltsize); if (!eltbuf) die("cannot read %s", sha1_to_hex(sha1)); path->len = pathlen; - strbuf_append_string(path, name); - if (S_ISDIR(mode)) - strbuf_append_string(path, "/"); + + /* if we match the path to strip out, + * don't append it to the path + */ + if ((strippath) && (!(strcmp(name,strippath) == 0))) { + strbuf_append_string(path, name); + if (S_ISDIR(mode)) + strbuf_append_string(path, "/"); + } write_entry(sha1, path, mode, eltbuf, eltsize); @@ -295,7 +306,7 @@ static void traverse_tree(struct tree_de struct tree_desc subtree; subtree.buf = eltbuf; subtree.size = eltsize; - traverse_tree(&subtree, path); + traverse_tree(&subtree, path, NULL, strippath); } free(eltbuf); } @@ -307,6 +318,9 @@ int main(int argc, char **argv) struct commit *commit; struct tree_desc tree; struct strbuf current_path; + int i, gotsha1 = 0, gotpath = 0; + const char *strippath; + const char *pathlimit; current_path.buf = xmalloc(PATH_MAX); current_path.alloc = PATH_MAX; @@ -315,19 +329,41 @@ int main(int argc, char **argv) setup_git_directory(); git_config(git_default_config); - switch (argc) { - case 3: - strbuf_append_string(¤t_path, argv[2]); - strbuf_append_string(¤t_path, "/"); - /* FALLTHROUGH */ - case 2: - if (get_sha1(argv[1], sha1) < 0) + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + + if (*arg != '-') { + /* first assume it is an SHA1 ref */ + if (!gotsha1) { + if (get_sha1(arg, sha1) >= 0) { + gotsha1 = 1; + continue; + } + } + + /* now assume it is the path prefix */ + if (!gotpath) { + strbuf_append_string(¤t_path, arg); + strbuf_append_string(¤t_path, "/"); + gotpath = 1; + continue; + } + + /* we're still here? */ + usage(tar_tree_usage); + + } else if (!strncmp(arg, "--strippath=", 12)) { + strippath = strdup(arg+12); + } else if (!strncmp(arg, "--pathlimit=", 12)) { + pathlimit = strdup(arg+12); + } else usage(tar_tree_usage); - break; - default: - usage(tar_tree_usage); } + /* be sure we have an SHA1 ref */ + if (!gotsha1) + usage(tar_tree_usage); + commit = lookup_commit_reference_gently(sha1, 1); if (commit) { write_global_extended_header(commit->object.sha1); @@ -343,7 +379,7 @@ int main(int argc, char **argv) if (current_path.len > 0) write_entry(tree_sha1, ¤t_path, 040777, NULL, 0); - traverse_tree(&tree, ¤t_path); + traverse_tree(&tree, ¤t_path, pathlimit, strippath); write_trailer(); free(current_path.buf); return 0; -- 1.4.1 - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html