Skip to content

Commit

Permalink
Add support for SHA-256 repositories
Browse files Browse the repository at this point in the history
Use variable extensions.objectformat, if available, to determine the
length of the hash id in the current repository.
  • Loading branch information
koutcher committed Nov 12, 2023
1 parent e543cfe commit 14a6b47
Show file tree
Hide file tree
Showing 25 changed files with 300 additions and 33 deletions.
2 changes: 2 additions & 0 deletions doc/manual.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion include/tig/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
6 changes: 3 additions & 3 deletions include/tig/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions include/tig/refdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
9 changes: 9 additions & 0 deletions include/tig/repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
4 changes: 2 additions & 2 deletions include/tig/tig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions src/argv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
6 changes: 3 additions & 3 deletions src/blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
};

Expand Down Expand Up @@ -187,15 +187,15 @@ 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;
}

{
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;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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)];
}
Expand Down
2 changes: 1 addition & 1 deletion src/graph-v1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/graph-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 23 additions & 5 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));

Expand Down
11 changes: 6 additions & 5 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/refdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 ||
Expand Down
4 changes: 3 additions & 1 deletion src/repo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
7 changes: 4 additions & 3 deletions src/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "tig/tig.h"
#include "tig/string.h"
#include "tig/repo.h"
#include "compat/utf8proc.h"

/*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ")
Expand Down
Loading

0 comments on commit 14a6b47

Please sign in to comment.