diff --git a/doc/manual.adoc b/doc/manual.adoc index cbdf702e6..5d1f56583 100644 --- a/doc/manual.adoc +++ b/doc/manual.adoc @@ -205,6 +205,8 @@ following variables. |%(repo:is-inside-work-tree) |Whether Tig is running inside a work tree, either `true` or `false`. +|%(repo:object-format) |The hash algorithm used for the repository, e.g. `sha1` + or `sha256`. |============================================================================= Example user-defined commands: diff --git a/include/tig/main.h b/include/tig/main.h index 7b248c2c9..659f2956c 100644 --- a/include/tig/main.h +++ b/include/tig/main.h @@ -19,7 +19,7 @@ #include "tig/util.h" struct commit { - char id[SIZEOF_REV]; /* SHA1 ID. */ + char id[SIZEOF_REV]; /* Hash ID. */ const struct ident *author; /* Author of the commit. */ struct time time; /* Date from the author ident. */ struct graph_canvas graph; /* Ancestry chain graphics. */ diff --git a/include/tig/parse.h b/include/tig/parse.h index b4817e7fe..8fbe97325 100644 --- a/include/tig/parse.h +++ b/include/tig/parse.h @@ -31,17 +31,17 @@ bool parse_chunk_header(struct chunk_header *header, const char *line); bool parse_chunk_lineno(unsigned long *lineno, const char *chunk, int marker); struct blame_commit { - char id[SIZEOF_REV]; /* SHA1 ID. */ + char id[SIZEOF_REV]; /* Hash ID. */ char title[128]; /* First line of the commit message. */ const struct ident *author; /* Author of the commit. */ struct time time; /* Date from the author ident. */ const char *filename; /* Name of file. */ - char parent_id[SIZEOF_REV]; /* Parent/previous SHA1 ID. */ + char parent_id[SIZEOF_REV]; /* Parent/previous hash ID. */ const char *parent_filename; /* Parent/previous name of file. */ }; struct blame_header { - char id[SIZEOF_REV]; /* SHA1 ID. */ + char id[SIZEOF_REV]; /* Hash ID. */ size_t orig_lineno; size_t lineno; size_t group; diff --git a/include/tig/refdb.h b/include/tig/refdb.h index b187bb5ff..71d137ed3 100644 --- a/include/tig/refdb.h +++ b/include/tig/refdb.h @@ -17,19 +17,20 @@ #include "tig/tig.h" #include "tig/types.h" #include "tig/util.h" +#include "tig/repo.h" struct argv_env; struct ref { struct ref *next; enum reference_type type; - char id[SIZEOF_REV]; /* Commit SHA1 ID */ + char id[SIZEOF_REV]; /* Commit hash ID */ unsigned int valid:1; /* Is the ref still valid? */ char name[1]; /* Ref name; tag or head names are shortened. */ }; #define is_initial_commit() (!get_ref_head()) -#define is_head_commit(rev) (!strcmp((rev), "HEAD") || (get_ref_head() && !strncmp(rev, get_ref_head()->id, SIZEOF_REV - 1))) +#define is_head_commit(rev) (!strcmp((rev), "HEAD") || (get_ref_head() && !strncmp(rev, get_ref_head()->id, REPO_INFO_SIZEOF_REV - 1))) #define ref_is_tag(ref) ((ref)->type == REFERENCE_TAG || (ref)->type == REFERENCE_LOCAL_TAG) #define ref_is_remote(ref) ((ref)->type == REFERENCE_REMOTE || (ref)->type == REFERENCE_TRACKED_REMOTE) diff --git a/include/tig/repo.h b/include/tig/repo.h index 136eb5a45..99dc20569 100644 --- a/include/tig/repo.h +++ b/include/tig/repo.h @@ -16,11 +16,21 @@ #include "tig/tig.h" +typedef enum { + REPO_INFO_SHA1 = 40, + REPO_INFO_SHA256 = 64 +} repo_object_format; + +/* Holds a hash ID and an ending NUL. */ +#define REPO_INFO_SIZEOF_REV (repo.object_format + 1) + typedef char repo_ref[SIZEOF_REF]; typedef char repo_rev[SIZEOF_REV]; typedef char repo_str[SIZEOF_STR]; +/* Leave object_format in first position. */ #define REPO_INFO(_) \ + _(repo_object_format, object_format) \ _(repo_ref, head) \ _(repo_rev, head_id) \ _(repo_ref, remote) \ diff --git a/include/tig/string.h b/include/tig/string.h index efe58876a..e4ed0b715 100644 --- a/include/tig/string.h +++ b/include/tig/string.h @@ -85,7 +85,7 @@ void string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen); void string_copy_rev(char *dst, const char *src); void string_copy_rev_from_commit_line(char *dst, const char *src); -#define string_rev_is_null(rev) !strncmp(rev, NULL_ID, STRING_SIZE(NULL_ID)) +#define string_rev_is_null(rev) !strncmp(rev, NULL_ID, REPO_INFO_SIZEOF_REV - 1) #define string_add(dst, from, src) \ string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src)) diff --git a/include/tig/tig.h b/include/tig/tig.h index 5bca4d518..b81aed22d 100644 --- a/include/tig/tig.h +++ b/include/tig/tig.h @@ -150,8 +150,8 @@ #define SIZEOF_STR 1024 /* Default string size. */ #define SIZEOF_MED_STR 8192 /* Medium string size. */ -#define SIZEOF_REF 256 /* Size of symbolic or SHA1 ID. */ -#define SIZEOF_REV 41 /* Holds a SHA-1 and an ending NUL. */ +#define SIZEOF_REF 256 /* Size of symbolic or hash ID. */ +#define SIZEOF_REV 65 /* Holds a SHA-1 or SHA-256 and an ending NUL. */ /* This color name can be used to refer to the default term colors. */ #define COLOR_DEFAULT (-1) @@ -166,7 +166,7 @@ #define MIN_VIEW_WIDTH 4 #define VSPLIT_SCALE 0.5 -#define NULL_ID "0000000000000000000000000000000000000000" +#define NULL_ID "0000000000000000000000000000000000000000000000000000000000000000" #define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000) diff --git a/src/argv.c b/src/argv.c index de05ad7c9..34aeae48b 100644 --- a/src/argv.c +++ b/src/argv.c @@ -415,6 +415,14 @@ bool_formatter(struct format_context *format, struct format_var *var) return string_format_from(format->buf, &format->bufpos, "%s", value ? "true" : "false"); } +static bool +repo_object_format_formatter(struct format_context *format, struct format_var *var) +{ + repo_object_format value = *(repo_object_format *)var->value_ref; + + return string_format_from(format->buf, &format->bufpos, "%s", value == REPO_INFO_SHA256 ? "sha256" : "sha1"); +} + static bool repo_str_formatter(struct format_context *format, struct format_var *var) { diff --git a/src/blame.c b/src/blame.c index dbcbf370a..edb6ed16c 100644 --- a/src/blame.c +++ b/src/blame.c @@ -28,7 +28,7 @@ */ struct blame_history_state { - char id[SIZEOF_REV]; /* SHA1 ID. */ + char id[SIZEOF_REV]; /* Hash ID. */ const char *filename; /* Name of file. */ }; @@ -187,7 +187,7 @@ get_blame_commit(struct view *view, const char *id) if (!blame->commit) continue; - if (!strncmp(blame->commit->id, id, SIZEOF_REV - 1)) + if (!strncmp(blame->commit->id, id, REPO_INFO_SIZEOF_REV - 1)) return blame->commit; } @@ -195,7 +195,7 @@ get_blame_commit(struct view *view, const char *id) struct blame_commit *commit = calloc(1, sizeof(*commit)); if (commit) - string_ncopy(commit->id, id, SIZEOF_REV); + string_copy_rev(commit->id, id); return commit; } } diff --git a/src/draw.c b/src/draw.c index 3b960f1bd..95ccbd01c 100644 --- a/src/draw.c +++ b/src/draw.c @@ -15,6 +15,7 @@ #include "tig/graph.h" #include "tig/draw.h" #include "tig/options.h" +#include "tig/repo.h" #include "compat/hashtab.h" static const enum line_type palette_colors[] = { @@ -267,7 +268,7 @@ draw_id(struct view *view, struct view_column *column, const char *id) return false; if (column->opt.id.color && id) { - hashval_t color = iterative_hash(id, SIZEOF_REV - 1, 0); + hashval_t color = iterative_hash(id, REPO_INFO_SIZEOF_REV - 1, 0); type = palette_colors[color % ARRAY_SIZE(palette_colors)]; } diff --git a/src/graph-v1.c b/src/graph-v1.c index 3dabed161..f60c36e25 100644 --- a/src/graph-v1.c +++ b/src/graph-v1.c @@ -32,7 +32,7 @@ struct graph_symbol { struct graph_column { struct graph_symbol symbol; - char id[SIZEOF_REV]; /* Parent SHA1 ID. */ + char id[SIZEOF_REV]; /* Parent hash ID. */ }; struct graph_row { diff --git a/src/graph-v2.c b/src/graph-v2.c index 0c8962738..27796feca 100644 --- a/src/graph-v2.c +++ b/src/graph-v2.c @@ -48,7 +48,7 @@ struct graph_symbol { struct graph_column { struct graph_symbol symbol; - const char *id; /* Parent SHA1 ID. */ + const char *id; /* Parent hash ID. */ }; struct graph_row { diff --git a/src/main.c b/src/main.c index edfbf6103..c34d756e2 100644 --- a/src/main.c +++ b/src/main.c @@ -100,7 +100,7 @@ main_add_commit(struct view *view, enum line_type type, struct commit *template, view_column_info_update(view, line); - if (view->env->goto_id[0] && !strncmp(view->env->goto_id, commit->id, SIZEOF_REV - 1)) { + if (view->env->goto_id[0] && !strncmp(view->env->goto_id, commit->id, REPO_INFO_SIZEOF_REV - 1)) { select_view_line(view, line->lineno + 1); view->env->goto_id[0] = 0; } else if (opt_start_on_head && is_head_commit(commit->id)) { @@ -121,7 +121,7 @@ main_flush_commit(struct view *view, struct commit *commit) static bool main_add_changes_commit(struct view *view, enum line_type type, const char *parent, const char *title) { - char ids[SIZEOF_STR] = NULL_ID " "; + char ids[SIZEOF_STR] = NULL_ID; struct main_state *state = view->private; struct graph *graph = state->graph; struct commit commit = {{0}}; @@ -131,10 +131,11 @@ main_add_changes_commit(struct view *view, enum line_type type, const char *pare if (!parent) return true; - if (*parent) - string_copy_rev(ids + STRING_SIZE(NULL_ID " "), parent); - else - ids[STRING_SIZE(NULL_ID)] = 0; + if (*parent) { + ids[REPO_INFO_SIZEOF_REV - 1] = ' '; + string_copy_rev(ids + REPO_INFO_SIZEOF_REV, parent); + } else + ids[REPO_INFO_SIZEOF_REV - 1] = 0; if (!time_now(&now, &tz)) { commit.time.tz = tz.tz_minuteswest * 60; diff --git a/src/options.c b/src/options.c index 7cdff0bbb..ec6bee06a 100644 --- a/src/options.c +++ b/src/options.c @@ -723,9 +723,16 @@ parse_option(struct option_info *option, const char *prefix, const char *arg) if (!strcmp(name, "line-number-interval") || !strcmp(name, "tab-size")) return parse_int(option->value, arg, 1, 1024); - else if (!strcmp(name, "id-width")) - return parse_int(option->value, arg, 0, SIZEOF_REV - 1); - else + else if (!strcmp(name, "id-width")) { + enum status_code code = parse_int(option->value, arg, 0, SIZEOF_REV - 1); + if (code == SUCCESS) { + int *value = option->value; + /* Limit id-width to the length of the hash used for the repository. */ + if (*value > REPO_INFO_SIZEOF_REV - 1) + *value = REPO_INFO_SIZEOF_REV - 1; + } + return code; + } else return parse_int(option->value, arg, 0, 1024); } @@ -1548,8 +1555,15 @@ read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen else if (!strcmp(name, "core.worktree")) string_ncopy(repo.worktree, value, valuelen); - else if (!strcmp(name, "core.abbrev")) - parse_int(&opt_id_width, value, 0, SIZEOF_REV - 1); + else if (!strcmp(name, "core.abbrev")) { + /* We cannot use REPO_INFO_SIZEOF_REV until we parse extensions.objectformat. */ + if (!strcmp(value, "no")) + opt_id_width = SIZEOF_REV - 1; + else if (strcmp(value, "auto")) + parse_int(&opt_id_width, value, 0, SIZEOF_REV - 1); + + } else if (!strcmp(name, "extensions.objectformat")) + repo.object_format = !strcmp(value, "sha256") ? REPO_INFO_SHA256 : REPO_INFO_SHA1; else if (!strcmp(name, "diff.noprefix")) { if (!find_option_info_by_value(&opt_diff_noprefix)->seen) @@ -1599,6 +1613,10 @@ load_git_config(void) code = io_run_load(&io, config_list_argv, "=", read_repo_config_option, NULL); + /* Limit id-width to the length of the hash used for the repository. */ + if (opt_id_width > REPO_INFO_SIZEOF_REV - 1) + opt_id_width = REPO_INFO_SIZEOF_REV - 1; + if (git_worktree && *git_worktree) string_ncopy(repo.worktree, git_worktree, strlen(git_worktree)); diff --git a/src/parse.c b/src/parse.c index ae8e45e73..51cc1518a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -14,6 +14,7 @@ #include "tig/tig.h" #include "tig/parse.h" #include "tig/map.h" +#include "tig/repo.h" size_t parse_size(const char *text) @@ -110,12 +111,12 @@ parse_number(const char **posref, size_t *number) bool parse_blame_header(struct blame_header *header, const char *text) { - const char *pos = text + SIZEOF_REV - 2; + const char *pos = text + REPO_INFO_SIZEOF_REV - 2; - if (strlen(text) <= SIZEOF_REV || pos[1] != ' ') + if (strlen(text) <= REPO_INFO_SIZEOF_REV || pos[1] != ' ') return false; - string_ncopy(header->id, text, SIZEOF_REV); + string_copy_rev(header->id, text); if (!parse_number(&pos, &header->orig_lineno) || !parse_number(&pos, &header->lineno)) @@ -164,10 +165,10 @@ parse_blame_info(struct blame_commit *commit, char author[SIZEOF_STR], char *lin string_ncopy(commit->title, line, strlen(line)); } else if (match_blame_header("previous ", &line)) { - if (strlen(line) <= SIZEOF_REV) + if (strlen(line) <= REPO_INFO_SIZEOF_REV) return false; string_copy_rev(commit->parent_id, line); - line += SIZEOF_REV; + line += REPO_INFO_SIZEOF_REV; commit->parent_filename = get_path(line); if (!commit->parent_filename) return true; diff --git a/src/refdb.c b/src/refdb.c index c7ac40417..99289a941 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -249,7 +249,7 @@ add_to_refs(const char *id, size_t idlen, char *name, size_t namelen, struct ref } /* If we are reloading or it's an annotated tag, replace the - * previous SHA1 with the resolved commit id; relies on the fact + * previous hash with the resolved commit id; relies on the fact * git-ls-remote lists the commit id of an annotated tag right * before the commit id it points to. */ if (type == REFERENCE_REPLACE) { @@ -279,7 +279,7 @@ add_to_refs(const char *id, size_t idlen, char *name, size_t namelen, struct ref ref->valid = true; ref->type = type; - string_ncopy_do(ref->id, SIZEOF_REV, id, idlen); + string_ncopy_do(ref->id, REPO_INFO_SIZEOF_REV, id, idlen); if (type == REFERENCE_HEAD) { if (!refs_head || diff --git a/src/repo.c b/src/repo.c index 479667bdb..9487a062c 100644 --- a/src/repo.c +++ b/src/repo.c @@ -57,7 +57,7 @@ read_repo_info(char *name, size_t namelen, char *value, size_t valuelen, void *d * this special case by looking at the emitted value. If it looks * like a commit ID and there's no cdup path assume that no value * was emitted. */ - if (!*repo.cdup && namelen == 40 && iscommit(name)) + if (!*repo.cdup && namelen == REPO_INFO_SIZEOF_REV - 1 && iscommit(name)) return read_repo_info(name, namelen, value, valuelen, data); string_ncopy(repo.prefix, name, namelen); @@ -105,6 +105,8 @@ load_repo_info(void) }; memset(&repo, 0, sizeof(repo)); + /* defaults to SHA-1 as older Git versions don't have extensions.objectFormat */ + repo.object_format = REPO_INFO_SHA1; return reload_repo_info(rev_parse_argv); } diff --git a/src/status.c b/src/status.c index bc709437b..3c453b8e3 100644 --- a/src/status.c +++ b/src/status.c @@ -111,7 +111,7 @@ status_run(struct view *view, const char *argv[], char status, enum line_type ty if (status) { file->status = status; if (status == 'A') - string_copy(file->old.rev, NULL_ID); + string_copy_rev(file->old.rev, NULL_ID); } else { if (!status_get_diff(&parsed, buf.data, buf.size)) diff --git a/src/string.c b/src/string.c index 68ed785e5..ea807ff9d 100644 --- a/src/string.c +++ b/src/string.c @@ -13,6 +13,7 @@ #include "tig/tig.h" #include "tig/string.h" +#include "tig/repo.h" #include "compat/utf8proc.h" /* @@ -42,7 +43,7 @@ iscommit(const char *str) return false; } - return 7 <= pos && pos < SIZEOF_REV; + return 7 <= pos && pos < REPO_INFO_SIZEOF_REV; } int @@ -72,11 +73,11 @@ string_copy_rev(char *dst, const char *src) if (!*src) return; - for (srclen = 0; srclen < SIZEOF_REV; srclen++) + for (srclen = 0; srclen < REPO_INFO_SIZEOF_REV; srclen++) if (!src[srclen] || isspace((unsigned char)src[srclen])) break; - string_ncopy_do(dst, SIZEOF_REV, src, srclen); + string_ncopy_do(dst, REPO_INFO_SIZEOF_REV, src, srclen); } void diff --git a/test/blame/sha256-initial-diff-test b/test/blame/sha256-initial-diff-test new file mode 100755 index 000000000..7d7b2ebe5 --- /dev/null +++ b/test/blame/sha256-initial-diff-test @@ -0,0 +1,69 @@ +#!/bin/sh + +. libtest.sh +. libgit.sh + +test_require sha256 + +steps ' + :save-display initial-diff.screen + :20 # Move to a deleted line. + :view-blame + :scroll-right + :save-display blame-deleted-line.screen +' + +in_work_dir create_repo_from_tgz "$base_dir/files/sha256-scala-js-benchmarks.tgz" + +LINES=23 test_tig show ed3277a + +assert_equals 'initial-diff.screen' < +AuthorDate: Sat Mar 1 15:59:02 2014 -0500 +Commit: Jonas Fonseca +CommitDate: Sat Mar 1 15:59:02 2014 -0500 + + Add type parameter for js.Dynamic +--- + common/src/main/scala/org/scalajs/benchmark/Benchmark.scala | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/common/src/main/scala/org/scalajs/benchmark/Benchmark.scala b/commo +index 4abd433..aa90cdf 100644 +--- a/common/src/main/scala/org/scalajs/benchmark/Benchmark.scala ++++ b/common/src/main/scala/org/scalajs/benchmark/Benchmark.scala +@@ -15,7 +15,7 @@ object Benchmark { + val benchmarks = js.Array[Benchmark]() + val benchmarkApps = js.Array[BenchmarkApp]() + +- val global = js.Dynamic.global.asInstanceOf[js.Dictionary] ++ val global = js.Dynamic.global.asInstanceOf[js.Dictionary[js.Any]] +[diff] ed3277a31a5a48def23854db7eaa7356871a29cbf26ba279cb8f1e4f93cf54fb - li 87% +EOF + +# Make sure that we find the commit that introduce the deleted line. +assert_equals 'blame-deleted-line.screen' < + :save-display main-with-diff.screen + + :save-display main-with-diff-next.screen +' + +git_clone 'sha256-repo-one' + +test_tig + +assert_equals 'main-default.screen' < Commit 8 B +[main] eac7f3b2335d4e51865229144ae34be34f8a2ae1b8a88ee82c86f22b4ad57688 - co 28% +EOF + +assert_equals 'main-ref-format.screen' < +AuthorDate: Thu Dec 17 12:49:30 2009 +0000 +Commit: Committer +CommitDate: Thu Dec 17 12:49:30 2009 +0000 + + Commit 8 B + +[diff] 4bf5f7eaa968deef5c5b67412ad79a3ba32de876a30ff7227751d72f7f39fb11 - l 100% +EOF diff --git a/test/tools/libtest.sh b/test/tools/libtest.sh index 3750d8ea5..45e0f7aed 100644 --- a/test/tools/libtest.sh +++ b/test/tools/libtest.sh @@ -553,7 +553,10 @@ test_require() test_skip "The test requires a tig compiled with readline" fi ;; - + sha256) + require_git_version 2.29 \ + "The test requires sha256 object format, available in git version 2.29 or newer" + ;; *) test_skip "Unknown feature requirement: $feature" esac diff --git a/test/tools/test-graph.c b/test/tools/test-graph.c index 5096b3b69..e9741cbf5 100644 --- a/test/tools/test-graph.c +++ b/test/tools/test-graph.c @@ -15,6 +15,7 @@ #include "tig/util.h" #include "tig/io.h" #include "tig/graph.h" +#include "tig/repo.h" #define USAGE \ "test-graph [--ascii]\n" \ @@ -23,6 +24,8 @@ " # git log --pretty=raw --parents | ./test-graph\n" \ " # git log --pretty=raw --parents | ./test-graph --ascii" +struct repo_info repo = {REPO_INFO_SHA1}; + struct commit { char id[SIZEOF_REV]; struct graph_canvas canvas; diff --git a/tools/doc-gen.c b/tools/doc-gen.c index f0bd5097a..1565a849c 100644 --- a/tools/doc-gen.c +++ b/tools/doc-gen.c @@ -14,6 +14,9 @@ #include "tig/tig.h" #include "tig/request.h" #include "tig/util.h" +#include "tig/repo.h" + +struct repo_info repo = {REPO_INFO_SHA1}; struct doc_action_iterator { bool end_group;