diff --git a/doc/manual.adoc b/doc/manual.adoc index 126dec13f..ade73a846 100644 --- a/doc/manual.adoc +++ b/doc/manual.adoc @@ -203,6 +203,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 e4001cce8..279f91257 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 fcd698da3..2f5a4a3e3 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 09395f554..230978d02 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 af30443b2..94e90569e 100644 --- a/include/tig/repo.h +++ b/include/tig/repo.h @@ -16,11 +16,20 @@ #include "tig/tig.h" +typedef enum { + REPO_INFO_SHA1 = 40, + REPO_INFO_SHA256 = 64 +} repo_object_format; + +#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/tig.h b/include/tig/tig.h index 278726ef7..32d1504f3 100644 --- a/include/tig/tig.h +++ b/include/tig/tig.h @@ -148,8 +148,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) diff --git a/src/argv.c b/src/argv.c index 80f4d6f4b..a8e26b722 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 43af804fd..9e20dfbdf 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_ncopy(commit->id, id, REPO_INFO_SIZEOF_REV); return commit; } } diff --git a/src/draw.c b/src/draw.c index b764294b6..2613be891 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 dfaa5ed29..047587a18 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 b36e2863e..154b63046 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 3ac88c6fc..a0a345681 100644 --- a/src/main.c +++ b/src/main.c @@ -101,7 +101,7 @@ main_add_commit(struct view *view, enum line_type type, struct commit *template, view_column_info_update(view, line); if ((opt_start_on_head && is_head_commit(commit->id)) || - (view->env->goto_id[0] && !strncmp(view->env->goto_id, commit->id, SIZEOF_REV - 1))) + (view->env->goto_id[0] && !strncmp(view->env->goto_id, commit->id, REPO_INFO_SIZEOF_REV - 1))) select_view_line(view, line->lineno + 1); return commit; diff --git a/src/options.c b/src/options.c index 56cbe5025..2fe7d1eb7 100644 --- a/src/options.c +++ b/src/options.c @@ -701,9 +701,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); } @@ -1528,8 +1535,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")) parse_bool(&opt_diff_noprefix, value); @@ -1578,6 +1592,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 983afdb82..7dc1be26d 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) @@ -109,12 +110,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)) @@ -163,10 +164,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 fddb0f8a3..814dfae37 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -239,7 +239,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) { @@ -269,7 +269,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 45cb531c3..b593a717c 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); @@ -102,6 +102,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/string.c b/src/string.c index a90fc1bb0..337453eb5 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/src/tree.c b/src/tree.c index 8a96b6a41..ebebafb09 100644 --- a/src/tree.c +++ b/src/tree.c @@ -58,7 +58,7 @@ push_tree_stack_entry(struct view *view, const char *name, struct position *posi */ #define SIZEOF_TREE_ATTR \ - STRING_SIZE("100644 blob f931e1d229c3e185caad4449bf5b66ed72462657\t") + STRING_SIZE("100644 blob ") + REPO_INFO_SIZEOF_REV - 1 + STRING_SIZE("\t") #define SIZEOF_TREE_MODE \ STRING_SIZE("100644 ") diff --git a/test/blame/sha256-initial-diff-test b/test/blame/sha256-initial-diff-test new file mode 100755 index 000000000..a95c68a95 --- /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 ceb85a337..3b6b48d9e 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 0617f4707..bafc91537 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 5c82671d3..82002fab3 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;