Merge branch 'mh/blame-worktree'
[git] / builtin / count-objects.c
1 /*
2  * Builtin "git count-objects".
3  *
4  * Copyright (c) 2006 Junio C Hamano
5  */
6
7 #include "cache.h"
8 #include "dir.h"
9 #include "builtin.h"
10 #include "parse-options.h"
11
12 static unsigned long garbage;
13 static off_t size_garbage;
14 static int verbose;
15 static unsigned long loose, packed, packed_loose;
16 static off_t loose_size;
17
18 static const char *bits_to_msg(unsigned seen_bits)
19 {
20         switch (seen_bits) {
21         case 0:
22                 return "no corresponding .idx or .pack";
23         case PACKDIR_FILE_GARBAGE:
24                 return "garbage found";
25         case PACKDIR_FILE_PACK:
26                 return "no corresponding .idx";
27         case PACKDIR_FILE_IDX:
28                 return "no corresponding .pack";
29         case PACKDIR_FILE_PACK|PACKDIR_FILE_IDX:
30         default:
31                 return NULL;
32         }
33 }
34
35 static void real_report_garbage(unsigned seen_bits, const char *path)
36 {
37         struct stat st;
38         const char *desc = bits_to_msg(seen_bits);
39
40         if (!desc)
41                 return;
42
43         if (!stat(path, &st))
44                 size_garbage += st.st_size;
45         warning("%s: %s", desc, path);
46         garbage++;
47 }
48
49 static void loose_garbage(const char *path)
50 {
51         if (verbose)
52                 report_garbage(PACKDIR_FILE_GARBAGE, path);
53 }
54
55 static int count_loose(const unsigned char *sha1, const char *path, void *data)
56 {
57         struct stat st;
58
59         if (lstat(path, &st) || !S_ISREG(st.st_mode))
60                 loose_garbage(path);
61         else {
62                 loose_size += on_disk_bytes(st);
63                 loose++;
64                 if (verbose && has_sha1_pack(sha1))
65                         packed_loose++;
66         }
67         return 0;
68 }
69
70 static int count_cruft(const char *basename, const char *path, void *data)
71 {
72         loose_garbage(path);
73         return 0;
74 }
75
76 static char const * const count_objects_usage[] = {
77         N_("git count-objects [-v] [-H | --human-readable]"),
78         NULL
79 };
80
81 int cmd_count_objects(int argc, const char **argv, const char *prefix)
82 {
83         int human_readable = 0;
84         struct option opts[] = {
85                 OPT__VERBOSE(&verbose, N_("be verbose")),
86                 OPT_BOOL('H', "human-readable", &human_readable,
87                          N_("print sizes in human readable format")),
88                 OPT_END(),
89         };
90
91         argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0);
92         /* we do not take arguments other than flags for now */
93         if (argc)
94                 usage_with_options(count_objects_usage, opts);
95         if (verbose) {
96                 report_garbage = real_report_garbage;
97                 report_linked_checkout_garbage();
98         }
99
100         for_each_loose_file_in_objdir(get_object_directory(),
101                                       count_loose, count_cruft, NULL, NULL);
102
103         if (verbose) {
104                 struct packed_git *p;
105                 unsigned long num_pack = 0;
106                 off_t size_pack = 0;
107                 struct strbuf loose_buf = STRBUF_INIT;
108                 struct strbuf pack_buf = STRBUF_INIT;
109                 struct strbuf garbage_buf = STRBUF_INIT;
110                 if (!packed_git)
111                         prepare_packed_git();
112                 for (p = packed_git; p; p = p->next) {
113                         if (!p->pack_local)
114                                 continue;
115                         if (open_pack_index(p))
116                                 continue;
117                         packed += p->num_objects;
118                         size_pack += p->pack_size + p->index_size;
119                         num_pack++;
120                 }
121
122                 if (human_readable) {
123                         strbuf_humanise_bytes(&loose_buf, loose_size);
124                         strbuf_humanise_bytes(&pack_buf, size_pack);
125                         strbuf_humanise_bytes(&garbage_buf, size_garbage);
126                 } else {
127                         strbuf_addf(&loose_buf, "%lu",
128                                     (unsigned long)(loose_size / 1024));
129                         strbuf_addf(&pack_buf, "%lu",
130                                     (unsigned long)(size_pack / 1024));
131                         strbuf_addf(&garbage_buf, "%lu",
132                                     (unsigned long)(size_garbage / 1024));
133                 }
134
135                 printf("count: %lu\n", loose);
136                 printf("size: %s\n", loose_buf.buf);
137                 printf("in-pack: %lu\n", packed);
138                 printf("packs: %lu\n", num_pack);
139                 printf("size-pack: %s\n", pack_buf.buf);
140                 printf("prune-packable: %lu\n", packed_loose);
141                 printf("garbage: %lu\n", garbage);
142                 printf("size-garbage: %s\n", garbage_buf.buf);
143                 strbuf_release(&loose_buf);
144                 strbuf_release(&pack_buf);
145                 strbuf_release(&garbage_buf);
146         } else {
147                 struct strbuf buf = STRBUF_INIT;
148                 if (human_readable)
149                         strbuf_humanise_bytes(&buf, loose_size);
150                 else
151                         strbuf_addf(&buf, "%lu kilobytes",
152                                     (unsigned long)(loose_size / 1024));
153                 printf("%lu objects, %s\n", loose, buf.buf);
154                 strbuf_release(&buf);
155         }
156         return 0;
157 }