Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for SHA-256 repositories #1302

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be called %(repo:extensions.objectformat) to use the standard Git term.
Actually, is there even a need to expose this at all?
I don't think we expose any other config options. Users can already consult something like
git --git-dir=%(repo:git-dir) config extensions.objectformat

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @krobelus. %(repo:hash_len) is actually a by-product of storing hash_len in the repo struct, but it's the best compromise I have found. I'll make it more elegant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh it is exposed by the REPO_INFO macro. Maybe define it outside that

|=============================================================================

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. */
Copy link
Contributor

@krobelus krobelus Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks good apart from one comment about %(repo:hash_len).
I haven't used sha256, I'll try it if I get around to.
It's a shame we can't reuse existing unit tests without modification.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually git fast-export and git fast-import allow to port the tests without too much effort and also to get a nice sandbox from an existing repository.

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
10 changes: 10 additions & 0 deletions include/tig/repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
2 changes: 1 addition & 1 deletion include/tig/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 3 additions & 3 deletions include/tig/tig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)

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_copy_rev(commit->id, id);
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
13 changes: 7 additions & 6 deletions 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 All @@ -117,7 +117,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}};
Expand All @@ -127,10 +127,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;
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 @@ -242,7 +242,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 @@ -272,7 +272,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
2 changes: 1 addition & 1 deletion src/status.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
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
Loading