1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-11-06 01:03:02 +01:00
git/ls-tree.c

127 lines
2.7 KiB
C
Raw Normal View History

/*
* GIT - The information manager from hell
*
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
#include "blob.h"
#include "tree.h"
#include "quote.h"
static int line_termination = '\n';
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
#define LS_RECURSIVE 1
#define LS_TREE_ONLY 2
#define LS_SHOW_TREES 4
#define LS_NAME_ONLY 8
ls-tree: further tweaks of the rewrite It modifies the selection a bit, so that a pathspec that is a superset of a particular tree path will always cause it to recurse into that tree. As an example, let's say that we do git-ls-tree HEAD drivers/char _without_ the "-r". What will happen is that it will start out doing all the base tree, and for "drivers" it will notice that it's a proper subset of "drivers/char", so it will always recurse into _that_ tree (but not into other trees). Then, it will not match anything else than "char" in that subdirectory, and because that's not a proper superset (it's an exact match), it will _not_ recurse into it, so you get: [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char 040000 tree 9568cda453aae205bb58983747fa73b9696d9d51 drivers/char which is what you got with the old git-ls-tree too. But interestingly, if you add the slash, it will become a proper superset and it will recurse into _that_ subdirectory (but no deeper: so if you want all subdirectories _below_ drivers/char/, you still need to give "-r"): [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char/ 100644 blob 2b6b1d772ed776fff87927fc34adc2e40500218e drivers/char/.gitignore 100644 blob 56b8a2e76ab10a5c21787cb7068a846075cbaffd drivers/char/ChangeLog 100644 blob 970f70d498f4c814e1cf3362e33d7e23ac53c299 drivers/char/Kconfig ... See? This is on top of the previous two diffs, holler if you want a whole new "everything combined" version.. It hasn't gotten lots of testing, but it should work. Linus
2005-11-28 07:48:08 +01:00
static int ls_options = 0;
const char **pathspec;
static const char ls_tree_usage[] =
"git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] <tree-ish> [path...]";
static int show_recursive(const char *base, int baselen, const char *pathname)
{
const char **s;
if (ls_options & LS_RECURSIVE)
return 1;
s = pathspec;
if (!s)
return 0;
for (;;) {
const char *spec = *s++;
int len, speclen;
if (!spec)
return 0;
if (strncmp(base, spec, baselen))
continue;
len = strlen(pathname);
spec += baselen;
speclen = strlen(spec);
if (speclen <= len)
continue;
if (memcmp(pathname, spec, len))
continue;
return 1;
}
}
static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
{
int retval = 0;
const char *type = "blob";
if (S_ISDIR(mode)) {
if (show_recursive(base, baselen, pathname)) {
retval = READ_TREE_RECURSIVE;
if (!(ls_options & LS_SHOW_TREES))
return retval;
ls-tree: further tweaks of the rewrite It modifies the selection a bit, so that a pathspec that is a superset of a particular tree path will always cause it to recurse into that tree. As an example, let's say that we do git-ls-tree HEAD drivers/char _without_ the "-r". What will happen is that it will start out doing all the base tree, and for "drivers" it will notice that it's a proper subset of "drivers/char", so it will always recurse into _that_ tree (but not into other trees). Then, it will not match anything else than "char" in that subdirectory, and because that's not a proper superset (it's an exact match), it will _not_ recurse into it, so you get: [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char 040000 tree 9568cda453aae205bb58983747fa73b9696d9d51 drivers/char which is what you got with the old git-ls-tree too. But interestingly, if you add the slash, it will become a proper superset and it will recurse into _that_ subdirectory (but no deeper: so if you want all subdirectories _below_ drivers/char/, you still need to give "-r"): [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char/ 100644 blob 2b6b1d772ed776fff87927fc34adc2e40500218e drivers/char/.gitignore 100644 blob 56b8a2e76ab10a5c21787cb7068a846075cbaffd drivers/char/ChangeLog 100644 blob 970f70d498f4c814e1cf3362e33d7e23ac53c299 drivers/char/Kconfig ... See? This is on top of the previous two diffs, holler if you want a whole new "everything combined" version.. It hasn't gotten lots of testing, but it should work. Linus
2005-11-28 07:48:08 +01:00
}
type = "tree";
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
}
else if (ls_options & LS_TREE_ONLY)
return 0;
if (!(ls_options & LS_NAME_ONLY))
printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
write_name_quoted(base, baselen, pathname, line_termination, stdout);
putchar(line_termination);
return retval;
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
}
int main(int argc, const char **argv)
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
{
ls-tree: further tweaks of the rewrite It modifies the selection a bit, so that a pathspec that is a superset of a particular tree path will always cause it to recurse into that tree. As an example, let's say that we do git-ls-tree HEAD drivers/char _without_ the "-r". What will happen is that it will start out doing all the base tree, and for "drivers" it will notice that it's a proper subset of "drivers/char", so it will always recurse into _that_ tree (but not into other trees). Then, it will not match anything else than "char" in that subdirectory, and because that's not a proper superset (it's an exact match), it will _not_ recurse into it, so you get: [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char 040000 tree 9568cda453aae205bb58983747fa73b9696d9d51 drivers/char which is what you got with the old git-ls-tree too. But interestingly, if you add the slash, it will become a proper superset and it will recurse into _that_ subdirectory (but no deeper: so if you want all subdirectories _below_ drivers/char/, you still need to give "-r"): [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char/ 100644 blob 2b6b1d772ed776fff87927fc34adc2e40500218e drivers/char/.gitignore 100644 blob 56b8a2e76ab10a5c21787cb7068a846075cbaffd drivers/char/ChangeLog 100644 blob 970f70d498f4c814e1cf3362e33d7e23ac53c299 drivers/char/Kconfig ... See? This is on top of the previous two diffs, holler if you want a whole new "everything combined" version.. It hasn't gotten lots of testing, but it should work. Linus
2005-11-28 07:48:08 +01:00
const char *prefix;
unsigned char sha1[20];
char *buf;
unsigned long size;
prefix = setup_git_directory();
while (1 < argc && argv[1][0] == '-') {
switch (argv[1][1]) {
case 'z':
line_termination = 0;
break;
case 'r':
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
ls_options |= LS_RECURSIVE;
break;
case 'd':
ls_options |= LS_TREE_ONLY;
break;
case 't':
ls_options |= LS_SHOW_TREES;
break;
case '-':
if (!strcmp(argv[1]+2, "name-only") ||
!strcmp(argv[1]+2, "name-status")) {
ls_options |= LS_NAME_ONLY;
break;
}
/* otherwise fallthru */
default:
usage(ls_tree_usage);
}
argc--; argv++;
}
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
ls_options |= LS_SHOW_TREES;
if (argc < 2)
usage(ls_tree_usage);
if (get_sha1(argv[1], sha1) < 0)
usage(ls_tree_usage);
[PATCH] Rewrite ls-tree to behave more like "/bin/ls -a" This is a complete rewrite of ls-tree to make it behave more like what "/bin/ls -a" does in the current working directory. Namely, the changes are: - Unlike the old ls-tree behaviour that used paths arguments to restrict output (not that it worked as intended---as pointed out in the mailing list discussion, it was quite incoherent), this rewrite uses paths arguments to specify what to show. - Without arguments, it implicitly uses the root level as its sole argument ("/bin/ls -a" behaves as if "." is given without argument). - Without -r (recursive) flag, it shows the named blob (either file or symlink), or the named tree and its immediate children. - With -r flag, it shows the named path, and recursively descends into it if it is a tree. - With -d flag, it shows the named path and does not show its children even if the path is a tree, nor descends into it recursively. This is still request-for-comments patch. There is no mailing list consensus that this proposed new behaviour is a good one. The patch to t/t3100-ls-tree-restrict.sh illustrates user-visible behaviour changes. Namely: * "git-ls-tree $tree path1 path0" lists path1 first and then path0. It used to use paths as an output restrictor and showed output in cache entry order (i.e. path0 first and then path1) regardless of the order of paths arguments. * "git-ls-tree $tree path2" lists path2 and its immediate children but having explicit paths argument does not imply recursive behaviour anymore, hence paths/baz is shown but not paths/baz/b. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-05-28 09:05:38 +02:00
ls-tree: further tweaks of the rewrite It modifies the selection a bit, so that a pathspec that is a superset of a particular tree path will always cause it to recurse into that tree. As an example, let's say that we do git-ls-tree HEAD drivers/char _without_ the "-r". What will happen is that it will start out doing all the base tree, and for "drivers" it will notice that it's a proper subset of "drivers/char", so it will always recurse into _that_ tree (but not into other trees). Then, it will not match anything else than "char" in that subdirectory, and because that's not a proper superset (it's an exact match), it will _not_ recurse into it, so you get: [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char 040000 tree 9568cda453aae205bb58983747fa73b9696d9d51 drivers/char which is what you got with the old git-ls-tree too. But interestingly, if you add the slash, it will become a proper superset and it will recurse into _that_ subdirectory (but no deeper: so if you want all subdirectories _below_ drivers/char/, you still need to give "-r"): [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char/ 100644 blob 2b6b1d772ed776fff87927fc34adc2e40500218e drivers/char/.gitignore 100644 blob 56b8a2e76ab10a5c21787cb7068a846075cbaffd drivers/char/ChangeLog 100644 blob 970f70d498f4c814e1cf3362e33d7e23ac53c299 drivers/char/Kconfig ... See? This is on top of the previous two diffs, holler if you want a whole new "everything combined" version.. It hasn't gotten lots of testing, but it should work. Linus
2005-11-28 07:48:08 +01:00
pathspec = get_pathspec(prefix, argv + 2);
buf = read_object_with_reference(sha1, "tree", &size, NULL);
if (!buf)
die("not a tree object");
ls-tree: further tweaks of the rewrite It modifies the selection a bit, so that a pathspec that is a superset of a particular tree path will always cause it to recurse into that tree. As an example, let's say that we do git-ls-tree HEAD drivers/char _without_ the "-r". What will happen is that it will start out doing all the base tree, and for "drivers" it will notice that it's a proper subset of "drivers/char", so it will always recurse into _that_ tree (but not into other trees). Then, it will not match anything else than "char" in that subdirectory, and because that's not a proper superset (it's an exact match), it will _not_ recurse into it, so you get: [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char 040000 tree 9568cda453aae205bb58983747fa73b9696d9d51 drivers/char which is what you got with the old git-ls-tree too. But interestingly, if you add the slash, it will become a proper superset and it will recurse into _that_ subdirectory (but no deeper: so if you want all subdirectories _below_ drivers/char/, you still need to give "-r"): [torvalds@g5 linux]$ ~/git/git-ls-tree HEAD drivers/char/ 100644 blob 2b6b1d772ed776fff87927fc34adc2e40500218e drivers/char/.gitignore 100644 blob 56b8a2e76ab10a5c21787cb7068a846075cbaffd drivers/char/ChangeLog 100644 blob 970f70d498f4c814e1cf3362e33d7e23ac53c299 drivers/char/Kconfig ... See? This is on top of the previous two diffs, holler if you want a whole new "everything combined" version.. It hasn't gotten lots of testing, but it should work. Linus
2005-11-28 07:48:08 +01:00
read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
return 0;
}