From 1024932f019905ff1a9e06e5acbee441919d4d05 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 18 May 2005 10:16:14 -0700 Subject: [PATCH] fsck-cache: walk the 'refs' directory if the user doesn't give any explicit references for reachability analysis. We already had that as separate logic in git-prune-script, so this is not a new special case - it's an old special case moved into fsck, making normal usage be much simpler. --- fsck-cache.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++------ git-prune-script | 13 --------- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/fsck-cache.c b/fsck-cache.c index a00702b7..d2aff8c6 100644 --- a/fsck-cache.c +++ b/fsck-cache.c @@ -296,6 +296,70 @@ static int fsck_dir(int i, char *path) return 0; } +static void read_sha1_reference(const char *path) +{ + char hexname[60]; + unsigned char sha1[20]; + int fd = open(path, O_RDONLY), len; + struct object *obj; + + if (fd < 0) + return; + + len = read(fd, hexname, sizeof(hexname)); + close(fd); + if (len < 40) + return; + + if (get_sha1_hex(hexname, sha1) < 0) + return; + + obj = lookup_object(sha1); + obj->used = 1; + mark_reachable(obj, REACHABLE); +} + +static void find_file_objects(const char *base, const char *name) +{ + int baselen = strlen(base); + int namelen = strlen(name); + char *path = xmalloc(baselen + namelen + 2); + struct stat st; + + memcpy(path, base, baselen); + path[baselen] = '/'; + memcpy(path + baselen + 1, name, namelen+1); + if (stat(path, &st) < 0) + return; + + /* + * Recurse into directories + */ + if (S_ISDIR(st.st_mode)) { + DIR *dir = opendir(path); + if (dir) { + struct dirent *de; + while ((de = readdir(dir)) != NULL) { + if (de->d_name[0] == '.') + continue; + find_file_objects(path, de->d_name); + } + closedir(dir); + } + return; + } + if (S_ISREG(st.st_mode)) { + read_sha1_reference(path); + return; + } +} + +static void get_default_heads(void) +{ + char *git_dir = gitenv(GIT_DIR_ENVIRONMENT) ? : DEFAULT_GIT_DIR_ENVIRONMENT; + find_file_objects(git_dir, "refs"); +} + int main(int argc, char **argv) { int i, heads; @@ -354,6 +418,16 @@ int main(int argc, char **argv) error("expected sha1, got %s", arg); } + /* + * If we've been asked to do reachability without any explicit + * head information, do the default ones from .git/refs. We also + * consider the index file in this case (ie this implies --cache). + */ + if (show_unreachable && !heads) { + get_default_heads(); + keep_cache_objects = 1; + } + if (keep_cache_objects) { int i; read_cache(); @@ -368,15 +442,6 @@ int main(int argc, char **argv) } } - if (!heads && !keep_cache_objects) { - if (show_unreachable) { - fprintf(stderr, "unable to do reachability without a head nor --cache\n"); - show_unreachable = 0; - } - if (!heads) - fprintf(stderr, "expect dangling commits - potential heads - due to lack of head information\n"); - } - check_connectivity(); return 0; } diff --git a/git-prune-script b/git-prune-script index 1a97ccc9..ec9f72de 100755 --- a/git-prune-script +++ b/git-prune-script @@ -14,19 +14,6 @@ done : ${GIT_DIR=.git} : ${GIT_OBJECT_DIRECTORY="${SHA1_FILE_DIRECTORY-"$GIT_DIR/objects"}"} -# Defaulting to include .git/refs/*/* may be debatable from the -# purist POV but power users can always give explicit parameters -# to the script anyway. - -case "$#" in -0) - x_40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' - x_40="$x_40$x_40$x_40$x_40$x_40$x_40$x_40$x_40" - set x $(sed -ne "/^$x_40\$/p" \ - "$GIT_DIR"/HEAD "$GIT_DIR"/refs/*/* /dev/null 2>/dev/null) - shift ;; -esac - git-fsck-cache --cache --unreachable "$@" | sed -ne '/unreachable /{ s/unreachable [^ ][^ ]* // -- 2.11.0