diff options
-rw-r--r-- | Documentation/git-archive.txt | 5 | ||||
-rw-r--r-- | archive.c | 23 | ||||
-rw-r--r-- | archive.h | 1 | ||||
-rw-r--r-- | attr.c | 12 | ||||
-rw-r--r-- | attr.h | 3 | ||||
-rw-r--r-- | builtin-tar-tree.c | 9 | ||||
-rwxr-xr-x | t/t5000-tar-tree.sh | 9 | ||||
-rwxr-xr-x | t/t5001-archive-attr.sh | 91 | ||||
-rw-r--r-- | unpack-trees.c | 6 |
9 files changed, 147 insertions, 12 deletions
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index c1adf59497..bc132c87e1 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>] - [--output=<file>] + [--output=<file>] [--worktree-attributes] [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish> [path...] @@ -51,6 +51,9 @@ OPTIONS --output=<file>:: Write the archive to <file> instead of stdout. +--worktree-attributes:: + Look for attributes in .gitattributes in working directory too. + <extra>:: This can be any options that the archiver backend understands. See next section. @@ -4,6 +4,7 @@ #include "attr.h" #include "archive.h" #include "parse-options.h" +#include "unpack-trees.h" static char const * const archive_usage[] = { "git archive [options] <tree-ish> [path...]", @@ -150,6 +151,8 @@ int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry) { struct archiver_context context; + struct unpack_trees_options opts; + struct tree_desc t; int err; if (args->baselen > 0 && args->base[args->baselen - 1] == '/') { @@ -168,6 +171,22 @@ int write_archive_entries(struct archiver_args *args, context.args = args; context.write_entry = write_entry; + /* + * Setup index and instruct attr to read index only + */ + if (!args->worktree_attributes) { + memset(&opts, 0, sizeof(opts)); + opts.index_only = 1; + opts.head_idx = -1; + opts.src_index = &the_index; + opts.dst_index = &the_index; + opts.fn = oneway_merge; + init_tree_desc(&t, args->tree->buffer, args->tree->size); + if (unpack_trees(1, &t, &opts)) + return -1; + git_attr_set_direction(GIT_ATTR_INDEX, &the_index); + } + err = read_tree_recursive(args->tree, args->base, args->baselen, 0, args->pathspec, write_archive_entry, &context); if (err == READ_TREE_RECURSIVE) @@ -258,6 +277,7 @@ static int parse_archive_args(int argc, const char **argv, int verbose = 0; int i; int list = 0; + int worktree_attributes = 0; struct option opts[] = { OPT_GROUP(""), OPT_STRING(0, "format", &format, "fmt", "archive format"), @@ -265,6 +285,8 @@ static int parse_archive_args(int argc, const char **argv, "prepend prefix to each pathname in the archive"), OPT_STRING(0, "output", &output, "file", "write the archive to this file"), + OPT_BOOLEAN(0, "worktree-attributes", &worktree_attributes, + "read .gitattributes in working directory"), OPT__VERBOSE(&verbose), OPT__COMPR('0', &compression_level, "store only", 0), OPT__COMPR('1', &compression_level, "compress faster", 1), @@ -324,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv, args->verbose = verbose; args->base = base; args->baselen = strlen(base); + args->worktree_attributes = worktree_attributes; return argc; } @@ -10,6 +10,7 @@ struct archiver_args { time_t time; const char **pathspec; unsigned int verbose : 1; + unsigned int worktree_attributes : 1; int compression_level; }; @@ -405,7 +405,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) if (!res) res = read_attr_from_file(path, macro_ok); } - else { + else if (direction == GIT_ATTR_CHECKIN) { res = read_attr_from_file(path, macro_ok); if (!res) /* @@ -415,6 +415,8 @@ static struct attr_stack *read_attr(const char *path, int macro_ok) */ res = read_attr_from_index(path, macro_ok); } + else + res = read_attr_from_index(path, macro_ok); if (!res) res = xcalloc(1, sizeof(*res)); return res; @@ -466,7 +468,7 @@ static void bootstrap_attr_stack(void) elem->prev = attr_stack; attr_stack = elem; - if (!is_bare_repository()) { + if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { elem = read_attr(GITATTRIBUTES_FILE, 1); elem->origin = strdup(""); elem->prev = attr_stack; @@ -533,7 +535,7 @@ static void prepare_attr_stack(const char *path, int dirlen) /* * Read from parent directories and push them down */ - if (!is_bare_repository()) { + if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { while (1) { char *cp; @@ -674,6 +676,10 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check) void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate) { enum git_attr_direction old = direction; + + if (is_bare_repository() && new != GIT_ATTR_INDEX) + die("BUG: non-INDEX attr direction in a bare repo"); + direction = new; if (new != old) drop_attr_stack(); @@ -33,7 +33,8 @@ int git_checkattr(const char *path, int, struct git_attr_check *); enum git_attr_direction { GIT_ATTR_CHECKIN, - GIT_ATTR_CHECKOUT + GIT_ATTR_CHECKOUT, + GIT_ATTR_INDEX, }; void git_attr_set_direction(enum git_attr_direction, struct index_state *); diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index 0713bca778..f88e721936 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -24,7 +24,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) * git archive --format-tar --prefix=basedir tree-ish */ int i; - const char **nargv = xcalloc(sizeof(*nargv), argc + 2); + const char **nargv = xcalloc(sizeof(*nargv), argc + 3); char *basedir_arg; int nargc = 0; @@ -36,6 +36,13 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix) argv++; argc--; } + + /* + * Because it's just a compatibility wrapper, tar-tree supports only + * the old behaviour of reading attributes from the work tree. + */ + nargv[nargc++] = "--worktree-attributes"; + switch (argc) { default: usage(tar_tree_usage); diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 7641e0dd46..abb41b07ef 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -50,7 +50,7 @@ test_expect_success \ test_expect_success \ 'add ignored file' \ 'echo ignore me >a/ignored && - echo ignored export-ignore >.gitattributes' + echo ignored export-ignore >.git/info/attributes' test_expect_success \ 'add files to repository' \ @@ -64,7 +64,7 @@ test_expect_success \ test_expect_success \ 'create bare clone' \ 'git clone --bare . bare.git && - cp .gitattributes bare.git/info/attributes' + cp .git/info/attributes bare.git/info/attributes' test_expect_success \ 'remove ignored file' \ @@ -139,10 +139,11 @@ test_expect_success \ test_expect_success \ 'create archives with substfiles' \ - 'echo "substfile?" export-subst >a/.gitattributes && + 'cp .git/info/attributes .git/info/attributes.before && + echo "substfile?" export-subst >>.git/info/attributes && git archive HEAD >f.tar && git archive --prefix=prefix/ HEAD >g.tar && - rm a/.gitattributes' + mv .git/info/attributes.before .git/info/attributes' test_expect_success \ 'extract substfiles' \ diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh new file mode 100755 index 0000000000..426b319bd3 --- /dev/null +++ b/t/t5001-archive-attr.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +test_description='git archive attribute tests' + +. ./test-lib.sh + +SUBSTFORMAT=%H%n + +test_expect_exists() { + test_expect_success " $1 exists" "test -e $1" +} + +test_expect_missing() { + test_expect_success " $1 does not exist" "test ! -e $1" +} + +test_expect_success 'setup' ' + echo ignored >ignored && + echo ignored export-ignore >>.git/info/attributes && + git add ignored && + + echo ignored by tree >ignored-by-tree && + echo ignored-by-tree export-ignore >.gitattributes && + git add ignored-by-tree .gitattributes && + + echo ignored by worktree >ignored-by-worktree && + echo ignored-by-worktree export-ignore >.gitattributes && + git add ignored-by-worktree && + + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >nosubstfile && + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >substfile1 && + printf "A not substituted O" >substfile2 && + echo "substfile?" export-subst >>.git/info/attributes && + git add nosubstfile substfile1 substfile2 && + + git commit -m. && + + git clone --bare . bare && + cp .git/info/attributes bare/info/attributes +' + +test_expect_success 'git archive' ' + git archive HEAD >archive.tar && + (mkdir archive && cd archive && "$TAR" xf -) <archive.tar +' + +test_expect_missing archive/ignored +test_expect_missing archive/ignored-by-tree +test_expect_exists archive/ignored-by-worktree + +test_expect_success 'git archive with worktree attributes' ' + git archive --worktree-attributes HEAD >worktree.tar && + (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar +' + +test_expect_missing worktree/ignored +test_expect_exists worktree/ignored-by-tree +test_expect_missing worktree/ignored-by-worktree + +test_expect_success 'git archive vs. bare' ' + (cd bare && git archive HEAD) >bare-archive.tar && + test_cmp archive.tar bare-archive.tar +' + +test_expect_success 'git archive with worktree attributes, bare' ' + (cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar && + (mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar +' + +test_expect_missing bare-worktree/ignored +test_expect_exists bare-worktree/ignored-by-tree +test_expect_exists bare-worktree/ignored-by-worktree + +test_expect_success 'export-subst' ' + git log "--pretty=format:A${SUBSTFORMAT}O" HEAD >substfile1.expected && + test_cmp nosubstfile archive/nosubstfile && + test_cmp substfile1.expected archive/substfile1 && + test_cmp substfile2 archive/substfile2 +' + +test_expect_success 'git tar-tree vs. git archive with worktree attributes' ' + git tar-tree HEAD >tar-tree.tar && + test_cmp worktree.tar tar-tree.tar +' + +test_expect_success 'git tar-tree vs. git archive with worktree attrs, bare' ' + (cd bare && git tar-tree HEAD) >bare-tar-tree.tar && + test_cmp bare-worktree.tar bare-tar-tree.tar +' + +test_done diff --git a/unpack-trees.c b/unpack-trees.c index 6847c2d966..e4eb8fa3af 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -87,7 +87,8 @@ static int check_updates(struct unpack_trees_options *o) cnt = 0; } - git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result); for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; @@ -112,7 +113,8 @@ static int check_updates(struct unpack_trees_options *o) } } stop_progress(&progress); - git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); + if (o->update) + git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); return errs != 0; } |