From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>, "Jeff King" <peff@peff.net>,
"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH] pack-refs: remove all empty dirs under .git/{refs,logs/refs}
Date: Sat, 11 Feb 2012 18:08:04 +0700 [thread overview]
Message-ID: <1328958484-4202-1-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1328946907-31650-1-git-send-email-pclouds@gmail.com>
"git pack-refs" tries to remove directory that becomes empty but it
does not try to do so hard enough. Only empty directories created
because a ref is packed are considered.
This patch introduces a global switch, which instructs ref machinery
to collect all empty directories (or ones containing only empty
directories) in removable order. "git pack-refs" uses this information
to clean $GIT_DIR/refs and $GIT_DIR/logs/refs.
Some directories are kept by this patch even if they are empty: refs,
refs/heads and refs/tags. The first one is one of git repository
signature. The rest is created by init-db, one may expect them to always
be there.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
v3, no second look at $GIT_DIR/refs and also clean
$GIT_DIR/logs/refs. Not really fond of the global switch, but it does
not look very intrusive to refs.c
builtin/pack-refs.c | 2 ++
pack-refs.c | 10 ++++++++++
refs.c | 35 +++++++++++++++++++++++++++++++----
refs.h | 4 ++++
t/t3210-pack-refs.sh | 10 ++++++++++
5 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index 39a9d89..044ae8f 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "parse-options.h"
#include "pack-refs.h"
+#include "refs.h"
static char const * const pack_refs_usage[] = {
"git pack-refs [options]",
@@ -15,6 +16,7 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "prune", &flags, "prune loose refs (default)", PACK_REFS_PRUNE),
OPT_END(),
};
+ save_empty_ref_directories = 1;
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
usage_with_options(pack_refs_usage, opts);
return pack_refs(flags);
diff --git a/pack-refs.c b/pack-refs.c
index f09a054..76d3408 100644
--- a/pack-refs.c
+++ b/pack-refs.c
@@ -2,6 +2,7 @@
#include "refs.h"
#include "tag.h"
#include "pack-refs.h"
+#include "string-list.h"
struct ref_to_prune {
struct ref_to_prune *next;
@@ -105,10 +106,19 @@ static void prune_ref(struct ref_to_prune *r)
static void prune_refs(struct ref_to_prune *r)
{
+ struct string_list *list = get_empty_ref_directories();;
+ int i;
+
while (r) {
prune_ref(r);
r = r->next;
}
+
+ for (i = 0; i < list->nr; i++) {
+ const char *s = list->items[i].string;
+ rmdir(git_path("%s", s));
+ rmdir(git_path("logs/%s", s));
+ }
}
static struct lock_file packed;
diff --git a/refs.c b/refs.c
index b8843bb..7e9a250 100644
--- a/refs.c
+++ b/refs.c
@@ -3,6 +3,7 @@
#include "object.h"
#include "tag.h"
#include "dir.h"
+#include "string-list.h"
/* ISSYMREF=0x01, ISPACKED=0x02 and ISBROKEN=0x04 are public interfaces */
#define REF_KNOWS_PEELED 0x10
@@ -29,6 +30,8 @@ struct ref_array {
struct ref_entry **refs;
};
+int save_empty_ref_directories;
+
/*
* Parse one line from a packed-refs file. Write the SHA1 to sha1.
* Return a pointer to the refname within the line (null-terminated),
@@ -177,6 +180,7 @@ static struct ref_cache {
char did_packed;
struct ref_array loose;
struct ref_array packed;
+ struct string_list empty_dirs;
/* The submodule name, or "" for the main repo. */
char name[FLEX_ARRAY];
} *ref_cache;
@@ -326,7 +330,7 @@ void add_packed_ref(const char *refname, const unsigned char *sha1)
}
static void get_ref_dir(struct ref_cache *refs, const char *base,
- struct ref_array *array)
+ struct ref_array *array, int *would_be_empty)
{
DIR *dir;
const char *path;
@@ -343,6 +347,7 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
struct dirent *de;
int baselen = strlen(base);
char *refname = xmalloc(baselen + 257);
+ int nr = 0;
memcpy(refname, base, baselen);
if (baselen && base[baselen-1] != '/')
@@ -355,8 +360,13 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
int namelen;
const char *refdir;
- if (de->d_name[0] == '.')
+ if (de->d_name[0] == '.') {
+ if (strcmp(de->d_name, "..") &&
+ strcmp(de->d_name, "."))
+ nr++;
continue;
+ }
+ nr++;
namelen = strlen(de->d_name);
if (namelen > 255)
continue;
@@ -369,7 +379,10 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
if (stat(refdir, &st) < 0)
continue;
if (S_ISDIR(st.st_mode)) {
- get_ref_dir(refs, refname, array);
+ int empty = 0;
+ get_ref_dir(refs, refname, array, &empty);
+ if (empty)
+ nr--;
continue;
}
if (*refs->name) {
@@ -387,6 +400,15 @@ static void get_ref_dir(struct ref_cache *refs, const char *base,
}
free(refname);
closedir(dir);
+ if (save_empty_ref_directories &&
+ nr == 0 &&
+ strcmp(base, "refs") &&
+ strcmp(base, "refs/heads") &&
+ strcmp(base, "refs/tags")) {
+ string_list_append(&refs->empty_dirs, xstrdup(base));
+ if (would_be_empty)
+ *would_be_empty = 1;
+ }
}
}
@@ -427,12 +449,17 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
static struct ref_array *get_loose_refs(struct ref_cache *refs)
{
if (!refs->did_loose) {
- get_ref_dir(refs, "refs", &refs->loose);
+ get_ref_dir(refs, "refs", &refs->loose, NULL);
refs->did_loose = 1;
}
return &refs->loose;
}
+struct string_list *get_empty_ref_directories()
+{
+ return &get_ref_cache(NULL)->empty_dirs;
+}
+
/* We allow "recursive" symbolic refs. Only within reason, though */
#define MAXDEPTH 5
#define MAXREFLEN (1024)
diff --git a/refs.h b/refs.h
index 00ba1e2..21a2a00 100644
--- a/refs.h
+++ b/refs.h
@@ -14,6 +14,10 @@ struct ref_lock {
#define REF_ISPACKED 0x02
#define REF_ISBROKEN 0x04
+struct string_list;
+extern int save_empty_ref_directories;
+extern struct string_list *get_empty_ref_directories();
+
/*
* Calls the specified function for each ref file until it returns nonzero,
* and returns the value
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index cd04361..40fcd54 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -66,6 +66,16 @@ test_expect_success 'see if git pack-refs --prune removes empty dirs' '
! test -e .git/refs/heads/r
'
+test_expect_success 'pack-refs --prune removes all empty dirs in refs and logs' '
+ mkdir -p .git/refs/empty/outside/heads &&
+ mkdir -p .git/refs/heads/empty/dir/ectory &&
+ mkdir -p .git/logs/refs/heads/empty/dir/ectory &&
+ git pack-refs --all --prune &&
+ ! test -e .git/refs/empty &&
+ ! test -e .git/refs/heads/empty &&
+ ! test -e .git/logs/refs/heads/empty
+'
+
test_expect_success \
'git branch g should work when git branch g/h has been deleted' \
'git branch g/h &&
--
1.7.8.36.g69ee2
next prev parent reply other threads:[~2012-02-11 11:02 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-10 16:25 [PATCH] Remove empty ref directories while reading loose refs Nguyễn Thái Ngọc Duy
2012-02-10 19:09 ` Junio C Hamano
2012-02-10 20:53 ` Jeff King
2012-02-11 7:55 ` [PATCH 1/2] pack-refs: remove all empty directories under $GIT_DIR/refs Nguyễn Thái Ngọc Duy
2012-02-11 7:55 ` [PATCH 2/2] Revert be7c6d4 (pack-refs: remove newly empty directories) Nguyễn Thái Ngọc Duy
2012-02-11 8:26 ` [PATCH 1/2] pack-refs: remove all empty directories under $GIT_DIR/refs Junio C Hamano
2012-02-11 8:55 ` Nguyen Thai Ngoc Duy
2012-02-11 17:59 ` Junio C Hamano
2012-02-11 11:08 ` Nguyễn Thái Ngọc Duy [this message]
2012-02-11 11:27 ` [PATCH] pack-refs: remove all empty dirs under .git/{refs,logs/refs} Thomas Adam
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1328958484-4202-1-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).