Skip to content

Commit 90cf590

Browse files
dschogitster
authored andcommitted
fsck: optionally show more helpful info for broken links
When reporting broken links between commits/trees/blobs, it would be quite helpful at times if the user would be told how the object is supposed to be reachable. With the new --name-objects option, git-fsck will try to do exactly that: name the objects in a way that shows how they are reachable. For example, when some reflog got corrupted and a blob is missing that should not be, the user might want to remove the corresponding reflog entry. This option helps them find that entry: `git fsck` will now report something like this: broken link from tree b5eb6ff... (refs/stash@{<date>}~37:) to blob ec5cf80... Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1cd772c commit 90cf590

File tree

4 files changed

+85
-9
lines changed

4 files changed

+85
-9
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: 38 additions & 4 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,14 +36,24 @@ 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

4345
static const char *describe_object(struct object *obj)
4446
{
45-
return oid_to_hex(&obj->oid);
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;
4657
}
4758

4859
static int fsck_config(const char *var, const char *value, void *cb)
@@ -378,13 +389,18 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
378389

379390
static int default_refs;
380391

381-
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)
382394
{
383395
struct object *obj;
384396

385397
if (!is_null_sha1(sha1)) {
386398
obj = lookup_object(sha1);
387399
if (obj) {
400+
if (timestamp && name_objects)
401+
add_decoration(fsck_walk_options.object_names,
402+
obj,
403+
xstrfmt("%s@{%ld}", refname, timestamp));
388404
obj->used = 1;
389405
mark_object_reachable(obj);
390406
} else {
@@ -404,8 +420,8 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
404420
fprintf(stderr, "Checking reflog %s->%s\n",
405421
sha1_to_hex(osha1), sha1_to_hex(nsha1));
406422

407-
fsck_handle_reflog_sha1(refname, osha1);
408-
fsck_handle_reflog_sha1(refname, nsha1);
423+
fsck_handle_reflog_sha1(refname, osha1, 0);
424+
fsck_handle_reflog_sha1(refname, nsha1, timestamp);
409425
return 0;
410426
}
411427

@@ -434,6 +450,9 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
434450
}
435451
default_refs++;
436452
obj->used = 1;
453+
if (name_objects)
454+
add_decoration(fsck_walk_options.object_names,
455+
obj, xstrdup(refname));
437456
mark_object_reachable(obj);
438457

439458
return 0;
@@ -549,6 +568,9 @@ static int fsck_cache_tree(struct cache_tree *it)
549568
return 1;
550569
}
551570
obj->used = 1;
571+
if (name_objects)
572+
add_decoration(fsck_walk_options.object_names,
573+
obj, xstrdup(":"));
552574
mark_object_reachable(obj);
553575
if (obj->type != OBJ_TREE)
554576
err |= objerror(obj, "non-tree in cache-tree");
@@ -577,6 +599,7 @@ static struct option fsck_opts[] = {
577599
OPT_BOOL(0, "lost-found", &write_lost_and_found,
578600
N_("write dangling objects in .git/lost-found")),
579601
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
602+
OPT_BOOL(0, "name-objects", &name_objects, N_("show verbose names for reachable objects")),
580603
OPT_END(),
581604
};
582605

@@ -606,6 +629,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
606629
include_reflogs = 0;
607630
}
608631

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

611638
fsck_head_link();
@@ -661,6 +688,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
661688
continue;
662689

663690
obj->used = 1;
691+
if (name_objects)
692+
add_decoration(fsck_walk_options.object_names,
693+
obj, xstrdup(arg));
664694
mark_object_reachable(obj);
665695
heads++;
666696
continue;
@@ -693,6 +723,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
693723
continue;
694724
obj = &blob->object;
695725
obj->used = 1;
726+
if (name_objects)
727+
add_decoration(fsck_walk_options.object_names,
728+
obj,
729+
xstrfmt(":%s", active_cache[i]->name));
696730
mark_object_reachable(obj);
697731
}
698732
if (active_cache_tree)

fsck.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,19 @@ static void put_object_name(struct fsck_options *options, struct object *obj,
323323
va_end(ap);
324324
}
325325

326+
static const char *describe_object(struct fsck_options *o, struct object *obj)
327+
{
328+
static struct strbuf buf = STRBUF_INIT;
329+
char *name;
330+
331+
strbuf_reset(&buf);
332+
strbuf_addstr(&buf, oid_to_hex(&obj->oid));
333+
if (o->object_names && (name = lookup_decoration(o->object_names, obj)))
334+
strbuf_addf(&buf, " (%s)", name);
335+
336+
return buf.buf;
337+
}
338+
326339
static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
327340
{
328341
struct tree_desc desc;
@@ -358,7 +371,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
358371
}
359372
else {
360373
result = error("in tree %s: entry %s has bad mode %.6o",
361-
oid_to_hex(&tree->object.oid), entry.path, entry.mode);
374+
describe_object(options, &tree->object), entry.path, entry.mode);
362375
}
363376
if (result < 0)
364377
return result;
@@ -454,7 +467,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
454467
case OBJ_TAG:
455468
return fsck_walk_tag((struct tag *)obj, data, options);
456469
default:
457-
error("Unknown object type for %s", oid_to_hex(&obj->oid));
470+
error("Unknown object type for %s", describe_object(options, obj));
458471
return -1;
459472
}
460473
}
@@ -901,9 +914,9 @@ int fsck_error_function(struct fsck_options *o,
901914
struct object *obj, int msg_type, const char *message)
902915
{
903916
if (msg_type == FSCK_WARN) {
904-
warning("object %s: %s", oid_to_hex(&obj->oid), message);
917+
warning("object %s: %s", describe_object(o, obj), message);
905918
return 0;
906919
}
907-
error("object %s: %s", oid_to_hex(&obj->oid), message);
920+
error("object %s: %s", describe_object(o, obj), message);
908921
return 1;
909922
}

t/t1450-fsck.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,4 +523,26 @@ test_expect_success 'fsck --connectivity-only' '
523523
)
524524
'
525525

526+
remove_loose_object () {
527+
sha1="$(git rev-parse "$1")" &&
528+
remainder=${sha1#??} &&
529+
firsttwo=${sha1%$remainder} &&
530+
rm .git/objects/$firsttwo/$remainder
531+
}
532+
533+
test_expect_success 'fsck --name-objects' '
534+
rm -rf name-objects &&
535+
git init name-objects &&
536+
(
537+
cd name-objects &&
538+
test_commit julius caesar.t &&
539+
test_commit augustus &&
540+
test_commit caesar &&
541+
remove_loose_object $(git rev-parse julius:caesar.t) &&
542+
test_must_fail git fsck --name-objects >out &&
543+
tree=$(git rev-parse --verify julius:) &&
544+
grep "$tree (\(refs/heads/master\|HEAD\)@{[0-9]*}:" out
545+
)
546+
'
547+
526548
test_done

0 commit comments

Comments
 (0)