This command introduces a new concept, "change id". This is similar to
"n" in reflog sha-1 extended syntax @{n}. I'm trying to group changes of
the same second together, and this timestamp becomes "change id", so
you view roughly a snapshot of changes. Of course it's not 100%
accurate. But it works most of the time and it keeps log update low.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 builtin/backup-log.c  | 83 +++++++++++++++++++++++++++++++++++++++++++
 t/t2080-backup-log.sh | 17 +++++++++
 2 files changed, 100 insertions(+)

diff --git a/builtin/backup-log.c b/builtin/backup-log.c
index 75a02c8878..b370ff9d27 100644
--- a/builtin/backup-log.c
+++ b/builtin/backup-log.c
@@ -1,10 +1,13 @@
 #include "cache.h"
 #include "builtin.h"
 #include "backup-log.h"
+#include "dir.h"
+#include "object-store.h"
 #include "parse-options.h"
 
 static char const * const backup_log_usage[] = {
        N_("git backup-log [--path=<path> | --id=<id>] update <path> <old-hash> 
<new-hash>"),
+       N_("git backup-log [--path=<path> | --id=<id>] cat [<options>] 
<change-id> <path>"),
        NULL
 };
 
@@ -34,6 +37,84 @@ static int update(int argc, const char **argv,
        return ret;
 }
 
+struct cat_options {
+       timestamp_t id;
+       char *path;
+       int before;
+       int show_hash;
+};
+
+static int cat_parse(struct strbuf *line, void *data)
+{
+       struct cat_options *opts = data;
+       struct bkl_entry entry;
+       struct object_id *oid;
+       void *buf;
+       unsigned long size;
+       enum object_type type;
+
+       if (bkl_parse_entry(line, &entry))
+               return -1;
+
+       if (entry.timestamp < opts->id)
+               return 2;
+
+       if (entry.timestamp != opts->id ||
+           fspathcmp(entry.path, opts->path))
+               return 0;
+
+       if (opts->before)
+               oid = &entry.old_oid;
+       else
+               oid = &entry.new_oid;
+
+       if (opts->show_hash) {
+               puts(oid_to_hex(oid));
+               return 1;
+       }
+
+       if (is_null_oid(oid))
+               return 1;       /* treat null oid like empty blob */
+
+       buf = read_object_file(oid, &type, &size);
+       if (!buf)
+               die(_("object not found: %s"), oid_to_hex(oid));
+       if (type != OBJ_BLOB)
+               die(_("not a blob: %s"), oid_to_hex(oid));
+
+       write_in_full(1, buf, size);
+       free(buf);
+
+       return 1;
+}
+
+static int cat(int argc, const char **argv,
+               const char *prefix, const char *log_path)
+{
+       struct cat_options opts;
+       struct option options[] = {
+               OPT_BOOL(0, "before", &opts.before, N_("select the version 
before the update")),
+               OPT_BOOL(0, "hash", &opts.show_hash, N_("show the hash instead 
of the content")),
+               OPT_END()
+       };
+       char *end = NULL;
+       int ret;
+
+       memset(&opts, 0, sizeof(opts));
+       argc = parse_options(argc, argv, prefix, options, backup_log_usage, 0);
+       if (argc != 2)
+               usage_with_options(backup_log_usage, options);
+       opts.id = strtol(argv[0], &end, 10);
+       if (!end || *end)
+               die(_("not a valid change id: %s"), argv[0]);
+       opts.path = prefix_path(prefix, prefix ? strlen(prefix) : 0, argv[1]);
+       setup_pager();
+       ret = bkl_parse_file_reverse(log_path, cat_parse, &opts);
+       if (ret < 0)
+               die(_("failed to parse '%s'"), log_path);
+       return ret - 1;
+}
+
 static char *log_id_to_path(const char *id)
 {
        if (!strcmp(id, "index"))
@@ -73,6 +154,8 @@ int cmd_backup_log(int argc, const char **argv, const char 
*prefix)
 
        if (!strcmp(argv[0], "update"))
                return update(argc, argv, prefix, log_path);
+       else if (!strcmp(argv[0], "cat"))
+               return cat(argc, argv, prefix, log_path);
        else
                die(_("unknown subcommand: %s"), argv[0]);
 
diff --git a/t/t2080-backup-log.sh b/t/t2080-backup-log.sh
index 8d1c8c5935..9c004c9727 100755
--- a/t/t2080-backup-log.sh
+++ b/t/t2080-backup-log.sh
@@ -88,4 +88,21 @@ test_expect_success 'apply --cached writes backup log' '
        test_cmp expected .git/index.bkl
 '
 
+test_expect_success 'backup-log cat' '
+       OLD=$(git rev-parse :./initial.t) &&
+       echo update >>initial.t &&
+       test_tick &&
+       git -c core.backupLog=true add initial.t &&
+       NEW=$(git rev-parse :./initial.t) &&
+       git backup-log --id=index cat --before --hash $test_tick initial.t 
>actual &&
+       echo $OLD >expected &&
+       test_cmp expected actual &&
+       git backup-log --id=index cat --hash $test_tick initial.t >actual &&
+       echo $NEW >expected &&
+       test_cmp expected actual &&
+       git backup-log --id=index cat $test_tick initial.t >actual &&
+       git cat-file blob $NEW >expected &&
+       test_cmp expected actual
+'
+
 test_done
-- 
2.20.0.rc2.486.g9832c05c3d

Reply via email to