Skip to content

Commit 9db3979

Browse files
committed
Merge branch 'js/fsck-name-object'
When "git fsck" reports a broken link (e.g. a tree object contains a blob that does not exist), both containing object and the object that is referred to were reported with their 40-hex object names. The command learned the "--name-objects" option to show the path to the containing object from existing refs (e.g. "HEAD~24^2:file.txt"). * js/fsck-name-object: fsck: optionally show more helpful info for broken links fsck: give the error function a chance to see the fsck_options fsck_walk(): optionally name objects on the go fsck: refactor how to describe objects
2 parents 3cc75c1 + 90cf590 commit 9db3979

File tree

5 files changed

+200
-31
lines changed

5 files changed

+200
-31
lines changed

Documentation/git-fsck.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ SYNOPSIS
1111
[verse]
1212
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
1313
[--[no-]full] [--strict] [--verbose] [--lost-found]
14-
[--[no-]dangling] [--[no-]progress] [--connectivity-only] [<object>*]
14+
[--[no-]dangling] [--[no-]progress] [--connectivity-only]
15+
[--[no-]name-objects] [<object>*]
1516

1617
DESCRIPTION
1718
-----------
@@ -82,6 +83,12 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
8283
a blob, the contents are written into the file, rather than
8384
its object name.
8485

86+
--name-objects::
87+
When displaying names of reachable objects, in addition to the
88+
SHA-1 also display a name that describes *how* they are reachable,
89+
compatible with linkgit:git-rev-parse[1], e.g.
90+
`HEAD@{1234567890}~25^2:src/`.
91+
8592
--[no-]progress::
8693
Progress status is reported on the standard error stream by
8794
default when it is attached to a terminal, unless

builtin/fsck.c

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "dir.h"
1414
#include "progress.h"
1515
#include "streaming.h"
16+
#include "decorate.h"
1617

1718
#define REACHABLE 0x0001
1819
#define SEEN 0x0002
@@ -35,11 +36,26 @@ static int write_lost_and_found;
3536
static int verbose;
3637
static int show_progress = -1;
3738
static int show_dangling = 1;
39+
static int name_objects;
3840
#define ERROR_OBJECT 01
3941
#define ERROR_REACHABLE 02
4042
#define ERROR_PACK 04
4143
#define ERROR_REFS 010
4244

45+
static const char *describe_object(struct object *obj)
46+
{
47+
static struct strbuf buf = STRBUF_INIT;
48+
char *name = name_objects ?
49+
lookup_decoration(fsck_walk_options.object_names, obj) : NULL;
50+
51+
strbuf_reset(&buf);
52+
strbuf_addstr(&buf, oid_to_hex(&obj->oid));
53+
if (name)
54+
strbuf_addf(&buf, " (%s)", name);
55+
56+
return buf.buf;
57+
}
58+
4359
static int fsck_config(const char *var, const char *value, void *cb)
4460
{
4561
if (strcmp(var, "fsck.skiplist") == 0) {
@@ -67,7 +83,7 @@ static void objreport(struct object *obj, const char *msg_type,
6783
const char *err)
6884
{
6985
fprintf(stderr, "%s in %s %s: %s\n",
70-
msg_type, typename(obj->type), oid_to_hex(&obj->oid), err);
86+
msg_type, typename(obj->type), describe_object(obj), err);
7187
}
7288

7389
static int objerror(struct object *obj, const char *err)
@@ -77,7 +93,8 @@ static int objerror(struct object *obj, const char *err)
7793
return -1;
7894
}
7995

80-
static int fsck_error_func(struct object *obj, int type, const char *message)
96+
static int fsck_error_func(struct fsck_options *o,
97+
struct object *obj, int type, const char *message)
8198
{
8299
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", message);
83100
return (type == FSCK_WARN) ? 0 : 1;
@@ -97,7 +114,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
97114
if (!obj) {
98115
/* ... these references to parent->fld are safe here */
99116
printf("broken link from %7s %s\n",
100-
typename(parent->type), oid_to_hex(&parent->oid));
117+
typename(parent->type), describe_object(parent));
101118
printf("broken link from %7s %s\n",
102119
(type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
103120
errors_found |= ERROR_REACHABLE;
@@ -114,9 +131,9 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
114131
if (!(obj->flags & HAS_OBJ)) {
115132
if (parent && !has_object_file(&obj->oid)) {
116133
printf("broken link from %7s %s\n",
117-
typename(parent->type), oid_to_hex(&parent->oid));
134+
typename(parent->type), describe_object(parent));
118135
printf(" to %7s %s\n",
119-
typename(obj->type), oid_to_hex(&obj->oid));
136+
typename(obj->type), describe_object(obj));
120137
errors_found |= ERROR_REACHABLE;
121138
}
122139
return 1;
@@ -190,7 +207,8 @@ static void check_reachable_object(struct object *obj)
190207
return; /* it is in pack - forget about it */
191208
if (connectivity_only && has_object_file(&obj->oid))
192209
return;
193-
printf("missing %s %s\n", typename(obj->type), oid_to_hex(&obj->oid));
210+
printf("missing %s %s\n", typename(obj->type),
211+
describe_object(obj));
194212
errors_found |= ERROR_REACHABLE;
195213
return;
196214
}
@@ -215,7 +233,8 @@ static void check_unreachable_object(struct object *obj)
215233
* since this is something that is prunable.
216234
*/
217235
if (show_unreachable) {
218-
printf("unreachable %s %s\n", typename(obj->type), oid_to_hex(&obj->oid));
236+
printf("unreachable %s %s\n", typename(obj->type),
237+
describe_object(obj));
219238
return;
220239
}
221240

@@ -234,11 +253,11 @@ static void check_unreachable_object(struct object *obj)
234253
if (!obj->used) {
235254
if (show_dangling)
236255
printf("dangling %s %s\n", typename(obj->type),
237-
oid_to_hex(&obj->oid));
256+
describe_object(obj));
238257
if (write_lost_and_found) {
239258
char *filename = git_pathdup("lost-found/%s/%s",
240259
obj->type == OBJ_COMMIT ? "commit" : "other",
241-
oid_to_hex(&obj->oid));
260+
describe_object(obj));
242261
FILE *f;
243262

244263
if (safe_create_leading_directories_const(filename)) {
@@ -252,7 +271,7 @@ static void check_unreachable_object(struct object *obj)
252271
if (stream_blob_to_fd(fileno(f), obj->oid.hash, NULL, 1))
253272
die_errno("Could not write '%s'", filename);
254273
} else
255-
fprintf(f, "%s\n", oid_to_hex(&obj->oid));
274+
fprintf(f, "%s\n", describe_object(obj));
256275
if (fclose(f))
257276
die_errno("Could not finish '%s'",
258277
filename);
@@ -271,7 +290,7 @@ static void check_unreachable_object(struct object *obj)
271290
static void check_object(struct object *obj)
272291
{
273292
if (verbose)
274-
fprintf(stderr, "Checking %s\n", oid_to_hex(&obj->oid));
293+
fprintf(stderr, "Checking %s\n", describe_object(obj));
275294

276295
if (obj->flags & REACHABLE)
277296
check_reachable_object(obj);
@@ -307,7 +326,7 @@ static int fsck_obj(struct object *obj)
307326

308327
if (verbose)
309328
fprintf(stderr, "Checking %s %s\n",
310-
typename(obj->type), oid_to_hex(&obj->oid));
329+
typename(obj->type), describe_object(obj));
311330

312331
if (fsck_walk(obj, NULL, &fsck_obj_options))
313332
objerror(obj, "broken links");
@@ -326,15 +345,17 @@ static int fsck_obj(struct object *obj)
326345
free_commit_buffer(commit);
327346

328347
if (!commit->parents && show_root)
329-
printf("root %s\n", oid_to_hex(&commit->object.oid));
348+
printf("root %s\n", describe_object(&commit->object));
330349
}
331350

332351
if (obj->type == OBJ_TAG) {
333352
struct tag *tag = (struct tag *) obj;
334353

335354
if (show_tags && tag->tagged) {
336-
printf("tagged %s %s", typename(tag->tagged->type), oid_to_hex(&tag->tagged->oid));
337-
printf(" (%s) in %s\n", tag->tag, oid_to_hex(&tag->object.oid));
355+
printf("tagged %s %s", typename(tag->tagged->type),
356+
describe_object(tag->tagged));
357+
printf(" (%s) in %s\n", tag->tag,
358+
describe_object(&tag->object));
338359
}
339360
}
340361

@@ -368,13 +389,18 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
368389

369390
static int default_refs;
370391

371-
static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1)
392+
static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,
393+
unsigned long timestamp)
372394
{
373395
struct object *obj;
374396

375397
if (!is_null_sha1(sha1)) {
376398
obj = lookup_object(sha1);
377399
if (obj) {
400+
if (timestamp && name_objects)
401+
add_decoration(fsck_walk_options.object_names,
402+
obj,
403+
xstrfmt("%s@{%ld}", refname, timestamp));
378404
obj->used = 1;
379405
mark_object_reachable(obj);
380406
} else {
@@ -394,8 +420,8 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
394420
fprintf(stderr, "Checking reflog %s->%s\n",
395421
sha1_to_hex(osha1), sha1_to_hex(nsha1));
396422

397-
fsck_handle_reflog_sha1(refname, osha1);
398-
fsck_handle_reflog_sha1(refname, nsha1);
423+
fsck_handle_reflog_sha1(refname, osha1, 0);
424+
fsck_handle_reflog_sha1(refname, nsha1, timestamp);
399425
return 0;
400426
}
401427

@@ -424,6 +450,9 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
424450
}
425451
default_refs++;
426452
obj->used = 1;
453+
if (name_objects)
454+
add_decoration(fsck_walk_options.object_names,
455+
obj, xstrdup(refname));
427456
mark_object_reachable(obj);
428457

429458
return 0;
@@ -539,6 +568,9 @@ static int fsck_cache_tree(struct cache_tree *it)
539568
return 1;
540569
}
541570
obj->used = 1;
571+
if (name_objects)
572+
add_decoration(fsck_walk_options.object_names,
573+
obj, xstrdup(":"));
542574
mark_object_reachable(obj);
543575
if (obj->type != OBJ_TREE)
544576
err |= objerror(obj, "non-tree in cache-tree");
@@ -567,6 +599,7 @@ static struct option fsck_opts[] = {
567599
OPT_BOOL(0, "lost-found", &write_lost_and_found,
568600
N_("write dangling objects in .git/lost-found")),
569601
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
602+
OPT_BOOL(0, "name-objects", &name_objects, N_("show verbose names for reachable objects")),
570603
OPT_END(),
571604
};
572605

@@ -596,6 +629,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
596629
include_reflogs = 0;
597630
}
598631

632+
if (name_objects)
633+
fsck_walk_options.object_names =
634+
xcalloc(1, sizeof(struct decoration));
635+
599636
git_config(fsck_config, NULL);
600637

601638
fsck_head_link();
@@ -651,6 +688,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
651688
continue;
652689

653690
obj->used = 1;
691+
if (name_objects)
692+
add_decoration(fsck_walk_options.object_names,
693+
obj, xstrdup(arg));
654694
mark_object_reachable(obj);
655695
heads++;
656696
continue;
@@ -683,6 +723,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
683723
continue;
684724
obj = &blob->object;
685725
obj->used = 1;
726+
if (name_objects)
727+
add_decoration(fsck_walk_options.object_names,
728+
obj,
729+
xstrfmt(":%s", active_cache[i]->name));
686730
mark_object_reachable(obj);
687731
}
688732
if (active_cache_tree)

0 commit comments

Comments
 (0)