Merge branch 'bc/sha-256-part-2'
SHA-256 migration work continues. * bc/sha-256-part-2: (44 commits) remote-testgit: adapt for object-format bundle: detect hash algorithm when reading refs t5300: pass --object-format to git index-pack t5704: send object-format capability with SHA-256 t5703: use object-format serve option t5702: offer an object-format capability in the test t/helper: initialize the repository for test-sha1-array remote-curl: avoid truncating refs with ls-remote t1050: pass algorithm to index-pack when outside repo builtin/index-pack: add option to specify hash algorithm remote-curl: detect algorithm for dumb HTTP by size builtin/ls-remote: initialize repository based on fetch t5500: make hash independent serve: advertise object-format capability for protocol v2 connect: parse v2 refs with correct hash algorithm connect: pass full packet reader when parsing v2 refs Documentation/technical: document object-format for protocol v2 t1302: expect repo format version 1 for SHA-256 builtin/show-index: provide options to determine hash algo t5302: modernize test formatting ...
This commit is contained in:
commit
12210859da
@ -93,6 +93,14 @@ OPTIONS
|
|||||||
--max-input-size=<size>::
|
--max-input-size=<size>::
|
||||||
Die, if the pack is larger than <size>.
|
Die, if the pack is larger than <size>.
|
||||||
|
|
||||||
|
--object-format=<hash-algorithm>::
|
||||||
|
Specify the given object format (hash algorithm) for the pack. The valid
|
||||||
|
values are 'sha1' and (if enabled) 'sha256'. The default is the algorithm for
|
||||||
|
the current repository (set by `extensions.objectFormat`), or 'sha1' if no
|
||||||
|
value is set or outside a repository.
|
||||||
|
+
|
||||||
|
This option cannot be used with --stdin.
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ git-show-index - Show packed archive index
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git show-index'
|
'git show-index' [--object-format=<hash-algorithm>]
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -36,6 +36,15 @@ Note that you can get more information on a packfile by calling
|
|||||||
linkgit:git-verify-pack[1]. However, as this command considers only the
|
linkgit:git-verify-pack[1]. However, as this command considers only the
|
||||||
index file itself, it's both faster and more flexible.
|
index file itself, it's both faster and more flexible.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
|
||||||
|
--object-format=<hash-algorithm>::
|
||||||
|
Specify the given object format (hash algorithm) for the index file. The
|
||||||
|
valid values are 'sha1' and (if enabled) 'sha256'. The default is the
|
||||||
|
algorithm for the current repository (set by `extensions.objectFormat`), or
|
||||||
|
'sha1' if no value is set or outside a repository..
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
Part of the linkgit:git[1] suite
|
Part of the linkgit:git[1] suite
|
||||||
|
@ -238,6 +238,9 @@ the remote repository.
|
|||||||
`--signed-tags=verbatim` to linkgit:git-fast-export[1]. In the
|
`--signed-tags=verbatim` to linkgit:git-fast-export[1]. In the
|
||||||
absence of this capability, Git will use `--signed-tags=warn-strip`.
|
absence of this capability, Git will use `--signed-tags=warn-strip`.
|
||||||
|
|
||||||
|
'object-format'::
|
||||||
|
This indicates that the helper is able to interact with the remote
|
||||||
|
side using an explicit hash algorithm extension.
|
||||||
|
|
||||||
|
|
||||||
COMMANDS
|
COMMANDS
|
||||||
@ -257,12 +260,14 @@ Support for this command is mandatory.
|
|||||||
'list'::
|
'list'::
|
||||||
Lists the refs, one per line, in the format "<value> <name>
|
Lists the refs, one per line, in the format "<value> <name>
|
||||||
[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
|
[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
|
||||||
a symref, or "?" to indicate that the helper could not get the
|
a symref, ":<keyword> <value>" for a key-value pair, or
|
||||||
value of the ref. A space-separated list of attributes follows
|
"?" to indicate that the helper could not get the value of the
|
||||||
the name; unrecognized attributes are ignored. The list ends
|
ref. A space-separated list of attributes follows the name;
|
||||||
with a blank line.
|
unrecognized attributes are ignored. The list ends with a
|
||||||
|
blank line.
|
||||||
+
|
+
|
||||||
See REF LIST ATTRIBUTES for a list of currently defined attributes.
|
See REF LIST ATTRIBUTES for a list of currently defined attributes.
|
||||||
|
See REF LIST KEYWORDS for a list of currently defined keywords.
|
||||||
+
|
+
|
||||||
Supported if the helper has the "fetch" or "import" capability.
|
Supported if the helper has the "fetch" or "import" capability.
|
||||||
|
|
||||||
@ -432,6 +437,18 @@ attributes are defined.
|
|||||||
This ref is unchanged since the last import or fetch, although
|
This ref is unchanged since the last import or fetch, although
|
||||||
the helper cannot necessarily determine what value that produced.
|
the helper cannot necessarily determine what value that produced.
|
||||||
|
|
||||||
|
REF LIST KEYWORDS
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The 'list' command may produce a list of key-value pairs.
|
||||||
|
The following keys are defined.
|
||||||
|
|
||||||
|
'object-format'::
|
||||||
|
The refs are using the given hash algorithm. This keyword is only
|
||||||
|
used if the server and client both support the object-format
|
||||||
|
extension.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
@ -516,6 +533,14 @@ set by Git if the remote helper has the 'option' capability.
|
|||||||
transaction. If successful, all refs will be updated, or none will. If the
|
transaction. If successful, all refs will be updated, or none will. If the
|
||||||
remote side does not support this capability, the push will fail.
|
remote side does not support this capability, the push will fail.
|
||||||
|
|
||||||
|
'option object-format' {'true'|algorithm}::
|
||||||
|
If 'true', indicate that the caller wants hash algorithm information
|
||||||
|
to be passed back from the remote. This mode is used when fetching
|
||||||
|
refs.
|
||||||
|
+
|
||||||
|
If set to an algorithm, indicate that the caller wants to interact with
|
||||||
|
the remote side using that algorithm.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
linkgit:git-remote[1]
|
linkgit:git-remote[1]
|
||||||
|
@ -176,6 +176,21 @@ agent strings are purely informative for statistics and debugging
|
|||||||
purposes, and MUST NOT be used to programmatically assume the presence
|
purposes, and MUST NOT be used to programmatically assume the presence
|
||||||
or absence of particular features.
|
or absence of particular features.
|
||||||
|
|
||||||
|
object-format
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This capability, which takes a hash algorithm as an argument, indicates
|
||||||
|
that the server supports the given hash algorithms. It may be sent
|
||||||
|
multiple times; if so, the first one given is the one used in the ref
|
||||||
|
advertisement.
|
||||||
|
|
||||||
|
When provided by the client, this indicates that it intends to use the
|
||||||
|
given hash algorithm to communicate. The algorithm provided must be one
|
||||||
|
that the server supports.
|
||||||
|
|
||||||
|
If this capability is not provided, it is assumed that the only
|
||||||
|
supported algorithm is SHA-1.
|
||||||
|
|
||||||
symref
|
symref
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -483,3 +483,12 @@ included in a request. This is done by sending each option as a
|
|||||||
a request.
|
a request.
|
||||||
|
|
||||||
The provided options must not contain a NUL or LF character.
|
The provided options must not contain a NUL or LF character.
|
||||||
|
|
||||||
|
object-format
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The server can advertise the `object-format` capability with a value `X` (in the
|
||||||
|
form `object-format=X`) to notify the client that the server is able to deal
|
||||||
|
with objects using hash algorithm X. If not specified, the server is assumed to
|
||||||
|
only handle SHA-1. If the client would like to use a hash algorithm other than
|
||||||
|
SHA-1, it should specify its object-format string.
|
||||||
|
@ -1220,6 +1220,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||||||
refs = transport_get_remote_refs(transport, &ref_prefixes);
|
refs = transport_get_remote_refs(transport, &ref_prefixes);
|
||||||
|
|
||||||
if (refs) {
|
if (refs) {
|
||||||
|
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we know what algorithm the remote side is using,
|
||||||
|
* let's set ours to the same thing.
|
||||||
|
*/
|
||||||
|
initialize_repository_version(hash_algo);
|
||||||
|
repo_set_hash_algo(the_repository, hash_algo);
|
||||||
|
|
||||||
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
|
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
|
||||||
/*
|
/*
|
||||||
* transport_get_remote_refs() may return refs with null sha-1
|
* transport_get_remote_refs() may return refs with null sha-1
|
||||||
|
@ -1555,13 +1555,9 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
|
|||||||
{
|
{
|
||||||
const uint32_t *idx1, *idx2;
|
const uint32_t *idx1, *idx2;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
const uint32_t hashwords = the_hash_algo->rawsz / sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* The address of the 4-byte offset table */
|
/* The address of the 4-byte offset table */
|
||||||
idx1 = (((const uint32_t *)p->index_data)
|
idx1 = (((const uint32_t *)((const uint8_t *)p->index_data + p->crc_offset))
|
||||||
+ 2 /* 8-byte header */
|
|
||||||
+ 256 /* fan out */
|
|
||||||
+ hashwords * p->num_objects /* object ID table */
|
|
||||||
+ p->num_objects /* CRC32 table */
|
+ p->num_objects /* CRC32 table */
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1671,6 +1667,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
|||||||
unsigned char pack_hash[GIT_MAX_RAWSZ];
|
unsigned char pack_hash[GIT_MAX_RAWSZ];
|
||||||
unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
|
unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
|
||||||
int report_end_of_input = 0;
|
int report_end_of_input = 0;
|
||||||
|
int hash_algo = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* index-pack never needs to fetch missing objects except when
|
* index-pack never needs to fetch missing objects except when
|
||||||
@ -1764,6 +1761,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
|||||||
die(_("bad %s"), arg);
|
die(_("bad %s"), arg);
|
||||||
} else if (skip_prefix(arg, "--max-input-size=", &arg)) {
|
} else if (skip_prefix(arg, "--max-input-size=", &arg)) {
|
||||||
max_input_size = strtoumax(arg, NULL, 10);
|
max_input_size = strtoumax(arg, NULL, 10);
|
||||||
|
} else if (skip_prefix(arg, "--object-format=", &arg)) {
|
||||||
|
hash_algo = hash_algo_by_name(arg);
|
||||||
|
if (hash_algo == GIT_HASH_UNKNOWN)
|
||||||
|
die(_("unknown hash algorithm '%s'"), arg);
|
||||||
|
repo_set_hash_algo(the_repository, hash_algo);
|
||||||
} else
|
} else
|
||||||
usage(index_pack_usage);
|
usage(index_pack_usage);
|
||||||
continue;
|
continue;
|
||||||
@ -1780,6 +1782,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
|
|||||||
die(_("--fix-thin cannot be used without --stdin"));
|
die(_("--fix-thin cannot be used without --stdin"));
|
||||||
if (from_stdin && !startup_info->have_repository)
|
if (from_stdin && !startup_info->have_repository)
|
||||||
die(_("--stdin requires a git repository"));
|
die(_("--stdin requires a git repository"));
|
||||||
|
if (from_stdin && hash_algo)
|
||||||
|
die(_("--object-format cannot be used with --stdin"));
|
||||||
if (!index_name && pack_name)
|
if (!index_name && pack_name)
|
||||||
index_name = derive_filename(pack_name, "idx", &index_name_buf);
|
index_name = derive_filename(pack_name, "idx", &index_name_buf);
|
||||||
|
|
||||||
|
@ -118,6 +118,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
|||||||
transport->server_options = &server_options;
|
transport->server_options = &server_options;
|
||||||
|
|
||||||
ref = transport_get_remote_refs(transport, &ref_prefixes);
|
ref = transport_get_remote_refs(transport, &ref_prefixes);
|
||||||
|
if (ref) {
|
||||||
|
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
|
||||||
|
repo_set_hash_algo(the_repository, hash_algo);
|
||||||
|
}
|
||||||
if (transport_disconnect(transport)) {
|
if (transport_disconnect(transport)) {
|
||||||
UNLEAK(sorting);
|
UNLEAK(sorting);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -249,6 +249,7 @@ static void show_ref(const char *path, const struct object_id *oid)
|
|||||||
strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
|
strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
|
||||||
if (advertise_push_options)
|
if (advertise_push_options)
|
||||||
strbuf_addstr(&cap, " push-options");
|
strbuf_addstr(&cap, " push-options");
|
||||||
|
strbuf_addf(&cap, " object-format=%s", the_hash_algo->name);
|
||||||
strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
|
strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
|
||||||
packet_write_fmt(1, "%s %s%c%s\n",
|
packet_write_fmt(1, "%s %s%c%s\n",
|
||||||
oid_to_hex(oid), path, 0, cap.buf);
|
oid_to_hex(oid), path, 0, cap.buf);
|
||||||
@ -1624,6 +1625,8 @@ static struct command *read_head_info(struct packet_reader *reader,
|
|||||||
linelen = strlen(reader->line);
|
linelen = strlen(reader->line);
|
||||||
if (linelen < reader->pktlen) {
|
if (linelen < reader->pktlen) {
|
||||||
const char *feature_list = reader->line + linelen + 1;
|
const char *feature_list = reader->line + linelen + 1;
|
||||||
|
const char *hash = NULL;
|
||||||
|
int len = 0;
|
||||||
if (parse_feature_request(feature_list, "report-status"))
|
if (parse_feature_request(feature_list, "report-status"))
|
||||||
report_status = 1;
|
report_status = 1;
|
||||||
if (parse_feature_request(feature_list, "side-band-64k"))
|
if (parse_feature_request(feature_list, "side-band-64k"))
|
||||||
@ -1636,6 +1639,13 @@ static struct command *read_head_info(struct packet_reader *reader,
|
|||||||
if (advertise_push_options
|
if (advertise_push_options
|
||||||
&& parse_feature_request(feature_list, "push-options"))
|
&& parse_feature_request(feature_list, "push-options"))
|
||||||
use_push_options = 1;
|
use_push_options = 1;
|
||||||
|
hash = parse_feature_value(feature_list, "object-format", &len, NULL);
|
||||||
|
if (!hash) {
|
||||||
|
hash = hash_algos[GIT_HASH_SHA1].name;
|
||||||
|
len = strlen(hash);
|
||||||
|
}
|
||||||
|
if (xstrncmpz(the_hash_algo->name, hash, len))
|
||||||
|
die("error: unsupported object format '%s'", hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(reader->line, "push-cert")) {
|
if (!strcmp(reader->line, "push-cert")) {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
|
#include "parse-options.h"
|
||||||
|
|
||||||
static const char show_index_usage[] =
|
static const char *const show_index_usage[] = {
|
||||||
"git show-index";
|
"git show-index [--object-format=<hash-algorithm>]",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
int cmd_show_index(int argc, const char **argv, const char *prefix)
|
int cmd_show_index(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
@ -11,10 +14,26 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
|
|||||||
unsigned nr;
|
unsigned nr;
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
static unsigned int top_index[256];
|
static unsigned int top_index[256];
|
||||||
const unsigned hashsz = the_hash_algo->rawsz;
|
unsigned hashsz;
|
||||||
|
const char *hash_name = NULL;
|
||||||
|
int hash_algo;
|
||||||
|
const struct option show_index_options[] = {
|
||||||
|
OPT_STRING(0, "object-format", &hash_name, N_("hash-algorithm"),
|
||||||
|
N_("specify the hash algorithm to use")),
|
||||||
|
OPT_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
argc = parse_options(argc, argv, prefix, show_index_options, show_index_usage, 0);
|
||||||
|
|
||||||
|
if (hash_name) {
|
||||||
|
hash_algo = hash_algo_by_name(hash_name);
|
||||||
|
if (hash_algo == GIT_HASH_UNKNOWN)
|
||||||
|
die(_("Unknown hash algorithm"));
|
||||||
|
repo_set_hash_algo(the_repository, hash_algo);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashsz = the_hash_algo->rawsz;
|
||||||
|
|
||||||
if (argc != 1)
|
|
||||||
usage(show_index_usage);
|
|
||||||
if (fread(top_index, 2 * 4, 1, stdin) != 1)
|
if (fread(top_index, 2 * 4, 1, stdin) != 1)
|
||||||
die("unable to read header");
|
die("unable to read header");
|
||||||
if (top_index[0] == htonl(PACK_IDX_SIGNATURE)) {
|
if (top_index[0] == htonl(PACK_IDX_SIGNATURE)) {
|
||||||
|
22
bundle.c
22
bundle.c
@ -23,6 +23,17 @@ static void add_to_ref_list(const struct object_id *oid, const char *name,
|
|||||||
list->nr++;
|
list->nr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct git_hash_algo *detect_hash_algo(struct strbuf *buf)
|
||||||
|
{
|
||||||
|
size_t len = strcspn(buf->buf, " \n");
|
||||||
|
int algo;
|
||||||
|
|
||||||
|
algo = hash_algo_by_length(len / 2);
|
||||||
|
if (algo == GIT_HASH_UNKNOWN)
|
||||||
|
return NULL;
|
||||||
|
return &hash_algos[algo];
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_bundle_header(int fd, struct bundle_header *header,
|
static int parse_bundle_header(int fd, struct bundle_header *header,
|
||||||
const char *report_path)
|
const char *report_path)
|
||||||
{
|
{
|
||||||
@ -52,12 +63,21 @@ static int parse_bundle_header(int fd, struct bundle_header *header,
|
|||||||
}
|
}
|
||||||
strbuf_rtrim(&buf);
|
strbuf_rtrim(&buf);
|
||||||
|
|
||||||
|
if (!header->hash_algo) {
|
||||||
|
header->hash_algo = detect_hash_algo(&buf);
|
||||||
|
if (!header->hash_algo) {
|
||||||
|
error(_("unknown hash algorithm length"));
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tip lines have object name, SP, and refname.
|
* Tip lines have object name, SP, and refname.
|
||||||
* Prerequisites have object name that is optionally
|
* Prerequisites have object name that is optionally
|
||||||
* followed by SP and subject line.
|
* followed by SP and subject line.
|
||||||
*/
|
*/
|
||||||
if (parse_oid_hex(buf.buf, &oid, &p) ||
|
if (parse_oid_hex_algop(buf.buf, &oid, &p, header->hash_algo) ||
|
||||||
(*p && !isspace(*p)) ||
|
(*p && !isspace(*p)) ||
|
||||||
(!is_prereq && !*p)) {
|
(!is_prereq && !*p)) {
|
||||||
if (report_path)
|
if (report_path)
|
||||||
|
1
bundle.h
1
bundle.h
@ -15,6 +15,7 @@ struct ref_list {
|
|||||||
struct bundle_header {
|
struct bundle_header {
|
||||||
struct ref_list prerequisites;
|
struct ref_list prerequisites;
|
||||||
struct ref_list references;
|
struct ref_list references;
|
||||||
|
const struct git_hash_algo *hash_algo;
|
||||||
};
|
};
|
||||||
|
|
||||||
int is_bundle(const char *path, int quiet);
|
int is_bundle(const char *path, int quiet);
|
||||||
|
138
connect.c
138
connect.c
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
static char *server_capabilities_v1;
|
static char *server_capabilities_v1;
|
||||||
static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
|
static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
|
||||||
static const char *parse_feature_value(const char *, const char *, int *);
|
static const char *next_server_feature_value(const char *feature, int *len, int *offset);
|
||||||
|
|
||||||
static int check_ref(const char *name, unsigned int flags)
|
static int check_ref(const char *name, unsigned int flags)
|
||||||
{
|
{
|
||||||
@ -83,6 +83,21 @@ int server_supports_v2(const char *c, int die_on_error)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int server_feature_v2(const char *c, const char **v)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < server_capabilities_v2.argc; i++) {
|
||||||
|
const char *out;
|
||||||
|
if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
|
||||||
|
(*out == '=')) {
|
||||||
|
*v = out + 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int server_supports_feature(const char *c, const char *feature,
|
int server_supports_feature(const char *c, const char *feature,
|
||||||
int die_on_error)
|
int die_on_error)
|
||||||
{
|
{
|
||||||
@ -181,17 +196,16 @@ reject:
|
|||||||
static void annotate_refs_with_symref_info(struct ref *ref)
|
static void annotate_refs_with_symref_info(struct ref *ref)
|
||||||
{
|
{
|
||||||
struct string_list symref = STRING_LIST_INIT_DUP;
|
struct string_list symref = STRING_LIST_INIT_DUP;
|
||||||
const char *feature_list = server_capabilities_v1;
|
int offset = 0;
|
||||||
|
|
||||||
while (feature_list) {
|
while (1) {
|
||||||
int len;
|
int len;
|
||||||
const char *val;
|
const char *val;
|
||||||
|
|
||||||
val = parse_feature_value(feature_list, "symref", &len);
|
val = next_server_feature_value("symref", &len, &offset);
|
||||||
if (!val)
|
if (!val)
|
||||||
break;
|
break;
|
||||||
parse_one_symref_info(&symref, val, len);
|
parse_one_symref_info(&symref, val, len);
|
||||||
feature_list = val + 1;
|
|
||||||
}
|
}
|
||||||
string_list_sort(&symref);
|
string_list_sort(&symref);
|
||||||
|
|
||||||
@ -205,21 +219,36 @@ static void annotate_refs_with_symref_info(struct ref *ref)
|
|||||||
string_list_clear(&symref, 0);
|
string_list_clear(&symref, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_capabilities(const char *line, int *len)
|
static void process_capabilities(struct packet_reader *reader, int *linelen)
|
||||||
{
|
{
|
||||||
|
const char *feat_val;
|
||||||
|
int feat_len;
|
||||||
|
const char *line = reader->line;
|
||||||
int nul_location = strlen(line);
|
int nul_location = strlen(line);
|
||||||
if (nul_location == *len)
|
if (nul_location == *linelen)
|
||||||
return;
|
return;
|
||||||
server_capabilities_v1 = xstrdup(line + nul_location + 1);
|
server_capabilities_v1 = xstrdup(line + nul_location + 1);
|
||||||
*len = nul_location;
|
*linelen = nul_location;
|
||||||
|
|
||||||
|
feat_val = server_feature_value("object-format", &feat_len);
|
||||||
|
if (feat_val) {
|
||||||
|
char *hash_name = xstrndup(feat_val, feat_len);
|
||||||
|
int hash_algo = hash_algo_by_name(hash_name);
|
||||||
|
if (hash_algo != GIT_HASH_UNKNOWN)
|
||||||
|
reader->hash_algo = &hash_algos[hash_algo];
|
||||||
|
free(hash_name);
|
||||||
|
} else {
|
||||||
|
reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_dummy_ref(const char *line)
|
static int process_dummy_ref(const struct packet_reader *reader)
|
||||||
{
|
{
|
||||||
|
const char *line = reader->line;
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if (parse_oid_hex(line, &oid, &name))
|
if (parse_oid_hex_algop(line, &oid, &name, reader->hash_algo))
|
||||||
return 0;
|
return 0;
|
||||||
if (*name != ' ')
|
if (*name != ' ')
|
||||||
return 0;
|
return 0;
|
||||||
@ -235,13 +264,15 @@ static void check_no_capabilities(const char *line, int len)
|
|||||||
line + strlen(line));
|
line + strlen(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_ref(const char *line, int len, struct ref ***list,
|
static int process_ref(const struct packet_reader *reader, int len,
|
||||||
unsigned int flags, struct oid_array *extra_have)
|
struct ref ***list, unsigned int flags,
|
||||||
|
struct oid_array *extra_have)
|
||||||
{
|
{
|
||||||
|
const char *line = reader->line;
|
||||||
struct object_id old_oid;
|
struct object_id old_oid;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if (parse_oid_hex(line, &old_oid, &name))
|
if (parse_oid_hex_algop(line, &old_oid, &name, reader->hash_algo))
|
||||||
return 0;
|
return 0;
|
||||||
if (*name != ' ')
|
if (*name != ' ')
|
||||||
return 0;
|
return 0;
|
||||||
@ -261,16 +292,17 @@ static int process_ref(const char *line, int len, struct ref ***list,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_shallow(const char *line, int len,
|
static int process_shallow(const struct packet_reader *reader, int len,
|
||||||
struct oid_array *shallow_points)
|
struct oid_array *shallow_points)
|
||||||
{
|
{
|
||||||
|
const char *line = reader->line;
|
||||||
const char *arg;
|
const char *arg;
|
||||||
struct object_id old_oid;
|
struct object_id old_oid;
|
||||||
|
|
||||||
if (!skip_prefix(line, "shallow ", &arg))
|
if (!skip_prefix(line, "shallow ", &arg))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (get_oid_hex(arg, &old_oid))
|
if (get_oid_hex_algop(arg, &old_oid, reader->hash_algo))
|
||||||
die(_("protocol error: expected shallow sha-1, got '%s'"), arg);
|
die(_("protocol error: expected shallow sha-1, got '%s'"), arg);
|
||||||
if (!shallow_points)
|
if (!shallow_points)
|
||||||
die(_("repository on the other end cannot be shallow"));
|
die(_("repository on the other end cannot be shallow"));
|
||||||
@ -317,20 +349,20 @@ struct ref **get_remote_heads(struct packet_reader *reader,
|
|||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case EXPECTING_FIRST_REF:
|
case EXPECTING_FIRST_REF:
|
||||||
process_capabilities(reader->line, &len);
|
process_capabilities(reader, &len);
|
||||||
if (process_dummy_ref(reader->line)) {
|
if (process_dummy_ref(reader)) {
|
||||||
state = EXPECTING_SHALLOW;
|
state = EXPECTING_SHALLOW;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state = EXPECTING_REF;
|
state = EXPECTING_REF;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case EXPECTING_REF:
|
case EXPECTING_REF:
|
||||||
if (process_ref(reader->line, len, &list, flags, extra_have))
|
if (process_ref(reader, len, &list, flags, extra_have))
|
||||||
break;
|
break;
|
||||||
state = EXPECTING_SHALLOW;
|
state = EXPECTING_SHALLOW;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case EXPECTING_SHALLOW:
|
case EXPECTING_SHALLOW:
|
||||||
if (process_shallow(reader->line, len, shallow_points))
|
if (process_shallow(reader, len, shallow_points))
|
||||||
break;
|
break;
|
||||||
die(_("protocol error: unexpected '%s'"), reader->line);
|
die(_("protocol error: unexpected '%s'"), reader->line);
|
||||||
case EXPECTING_DONE:
|
case EXPECTING_DONE:
|
||||||
@ -344,7 +376,7 @@ struct ref **get_remote_heads(struct packet_reader *reader,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
|
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
|
||||||
static int process_ref_v2(const char *line, struct ref ***list)
|
static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
|
||||||
{
|
{
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -352,6 +384,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
|
|||||||
struct ref *ref;
|
struct ref *ref;
|
||||||
struct string_list line_sections = STRING_LIST_INIT_DUP;
|
struct string_list line_sections = STRING_LIST_INIT_DUP;
|
||||||
const char *end;
|
const char *end;
|
||||||
|
const char *line = reader->line;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ref lines have a number of fields which are space deliminated. The
|
* Ref lines have a number of fields which are space deliminated. The
|
||||||
@ -364,7 +397,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_oid_hex(line_sections.items[i++].string, &old_oid, &end) ||
|
if (parse_oid_hex_algop(line_sections.items[i++].string, &old_oid, &end, reader->hash_algo) ||
|
||||||
*end) {
|
*end) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
@ -372,7 +405,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
|
|||||||
|
|
||||||
ref = alloc_ref(line_sections.items[i++].string);
|
ref = alloc_ref(line_sections.items[i++].string);
|
||||||
|
|
||||||
oidcpy(&ref->old_oid, &old_oid);
|
memcpy(ref->old_oid.hash, old_oid.hash, reader->hash_algo->rawsz);
|
||||||
**list = ref;
|
**list = ref;
|
||||||
*list = &ref->next;
|
*list = &ref->next;
|
||||||
|
|
||||||
@ -385,7 +418,8 @@ static int process_ref_v2(const char *line, struct ref ***list)
|
|||||||
struct object_id peeled_oid;
|
struct object_id peeled_oid;
|
||||||
char *peeled_name;
|
char *peeled_name;
|
||||||
struct ref *peeled;
|
struct ref *peeled;
|
||||||
if (parse_oid_hex(arg, &peeled_oid, &end) || *end) {
|
if (parse_oid_hex_algop(arg, &peeled_oid, &end,
|
||||||
|
reader->hash_algo) || *end) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -393,7 +427,8 @@ static int process_ref_v2(const char *line, struct ref ***list)
|
|||||||
peeled_name = xstrfmt("%s^{}", ref->name);
|
peeled_name = xstrfmt("%s^{}", ref->name);
|
||||||
peeled = alloc_ref(peeled_name);
|
peeled = alloc_ref(peeled_name);
|
||||||
|
|
||||||
oidcpy(&peeled->old_oid, &peeled_oid);
|
memcpy(peeled->old_oid.hash, peeled_oid.hash,
|
||||||
|
reader->hash_algo->rawsz);
|
||||||
**list = peeled;
|
**list = peeled;
|
||||||
*list = &peeled->next;
|
*list = &peeled->next;
|
||||||
|
|
||||||
@ -423,6 +458,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
|
|||||||
int stateless_rpc)
|
int stateless_rpc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
const char *hash_name;
|
||||||
*list = NULL;
|
*list = NULL;
|
||||||
|
|
||||||
if (server_supports_v2("ls-refs", 1))
|
if (server_supports_v2("ls-refs", 1))
|
||||||
@ -431,6 +467,16 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
|
|||||||
if (server_supports_v2("agent", 0))
|
if (server_supports_v2("agent", 0))
|
||||||
packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
|
packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
|
||||||
|
|
||||||
|
if (server_feature_v2("object-format", &hash_name)) {
|
||||||
|
int hash_algo = hash_algo_by_name(hash_name);
|
||||||
|
if (hash_algo == GIT_HASH_UNKNOWN)
|
||||||
|
die(_("unknown object format '%s' specified by server"), hash_name);
|
||||||
|
reader->hash_algo = &hash_algos[hash_algo];
|
||||||
|
packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name);
|
||||||
|
} else {
|
||||||
|
reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
|
||||||
|
}
|
||||||
|
|
||||||
if (server_options && server_options->nr &&
|
if (server_options && server_options->nr &&
|
||||||
server_supports_v2("server-option", 1))
|
server_supports_v2("server-option", 1))
|
||||||
for (i = 0; i < server_options->nr; i++)
|
for (i = 0; i < server_options->nr; i++)
|
||||||
@ -450,7 +496,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
|
|||||||
|
|
||||||
/* Process response from server */
|
/* Process response from server */
|
||||||
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
|
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
|
||||||
if (!process_ref_v2(reader->line, &list))
|
if (!process_ref_v2(reader, &list))
|
||||||
die(_("invalid ls-refs response: %s"), reader->line);
|
die(_("invalid ls-refs response: %s"), reader->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +509,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
|
const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
@ -471,6 +517,8 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
len = strlen(feature);
|
len = strlen(feature);
|
||||||
|
if (offset)
|
||||||
|
feature_list += *offset;
|
||||||
while (*feature_list) {
|
while (*feature_list) {
|
||||||
const char *found = strstr(feature_list, feature);
|
const char *found = strstr(feature_list, feature);
|
||||||
if (!found)
|
if (!found)
|
||||||
@ -485,9 +533,14 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
|
|||||||
}
|
}
|
||||||
/* feature with a value (e.g., "agent=git/1.2.3") */
|
/* feature with a value (e.g., "agent=git/1.2.3") */
|
||||||
else if (*value == '=') {
|
else if (*value == '=') {
|
||||||
|
int end;
|
||||||
|
|
||||||
value++;
|
value++;
|
||||||
|
end = strcspn(value, " \t\n");
|
||||||
if (lenp)
|
if (lenp)
|
||||||
*lenp = strcspn(value, " \t\n");
|
*lenp = end;
|
||||||
|
if (offset)
|
||||||
|
*offset = value + end - feature_list;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -500,14 +553,41 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int server_supports_hash(const char *desired, int *feature_supported)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
int len;
|
||||||
|
const char *hash;
|
||||||
|
|
||||||
|
hash = next_server_feature_value("object-format", &len, &offset);
|
||||||
|
if (feature_supported)
|
||||||
|
*feature_supported = !!hash;
|
||||||
|
if (!hash) {
|
||||||
|
hash = hash_algos[GIT_HASH_SHA1].name;
|
||||||
|
len = strlen(hash);
|
||||||
|
}
|
||||||
|
while (hash) {
|
||||||
|
if (!xstrncmpz(desired, hash, len))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
hash = next_server_feature_value("object-format", &len, &offset);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_feature_request(const char *feature_list, const char *feature)
|
int parse_feature_request(const char *feature_list, const char *feature)
|
||||||
{
|
{
|
||||||
return !!parse_feature_value(feature_list, feature, NULL);
|
return !!parse_feature_value(feature_list, feature, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *next_server_feature_value(const char *feature, int *len, int *offset)
|
||||||
|
{
|
||||||
|
return parse_feature_value(server_capabilities_v1, feature, len, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *server_feature_value(const char *feature, int *len)
|
const char *server_feature_value(const char *feature, int *len)
|
||||||
{
|
{
|
||||||
return parse_feature_value(server_capabilities_v1, feature, len);
|
return parse_feature_value(server_capabilities_v1, feature, len, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int server_supports(const char *feature)
|
int server_supports(const char *feature)
|
||||||
|
@ -18,7 +18,10 @@ int url_is_local_not_ssh(const char *url);
|
|||||||
struct packet_reader;
|
struct packet_reader;
|
||||||
enum protocol_version discover_version(struct packet_reader *reader);
|
enum protocol_version discover_version(struct packet_reader *reader);
|
||||||
|
|
||||||
|
int server_supports_hash(const char *desired, int *feature_supported);
|
||||||
|
const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset);
|
||||||
int server_supports_v2(const char *c, int die_on_error);
|
int server_supports_v2(const char *c, int die_on_error);
|
||||||
|
int server_feature_v2(const char *c, const char **v);
|
||||||
int server_supports_feature(const char *c, const char *feature,
|
int server_supports_feature(const char *c, const char *feature,
|
||||||
int die_on_error);
|
int die_on_error);
|
||||||
|
|
||||||
|
14
fetch-pack.c
14
fetch-pack.c
@ -1050,6 +1050,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
|||||||
print_verbose(args, _("Server supports %s"), "deepen-relative");
|
print_verbose(args, _("Server supports %s"), "deepen-relative");
|
||||||
else if (args->deepen_relative)
|
else if (args->deepen_relative)
|
||||||
die(_("Server does not support --deepen"));
|
die(_("Server does not support --deepen"));
|
||||||
|
if (!server_supports_hash(the_hash_algo->name, NULL))
|
||||||
|
die(_("Server does not support this repository's object format"));
|
||||||
|
|
||||||
if (!args->no_dependents) {
|
if (!args->no_dependents) {
|
||||||
mark_complete_and_common_ref(negotiator, args, &ref);
|
mark_complete_and_common_ref(negotiator, args, &ref);
|
||||||
@ -1188,6 +1190,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
|
|||||||
int sideband_all, int seen_ack)
|
int sideband_all, int seen_ack)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
const char *hash_name;
|
||||||
struct strbuf req_buf = STRBUF_INIT;
|
struct strbuf req_buf = STRBUF_INIT;
|
||||||
|
|
||||||
if (server_supports_v2("fetch", 1))
|
if (server_supports_v2("fetch", 1))
|
||||||
@ -1202,6 +1205,17 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
|
|||||||
args->server_options->items[i].string);
|
args->server_options->items[i].string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server_feature_v2("object-format", &hash_name)) {
|
||||||
|
int hash_algo = hash_algo_by_name(hash_name);
|
||||||
|
if (hash_algo_by_ptr(the_hash_algo) != hash_algo)
|
||||||
|
die(_("mismatched algorithms: client %s; server %s"),
|
||||||
|
the_hash_algo->name, hash_name);
|
||||||
|
packet_write_fmt(fd_out, "object-format=%s", the_hash_algo->name);
|
||||||
|
} else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) {
|
||||||
|
die(_("the server does not support algorithm '%s'"),
|
||||||
|
the_hash_algo->name);
|
||||||
|
}
|
||||||
|
|
||||||
packet_buf_delim(&req_buf);
|
packet_buf_delim(&req_buf);
|
||||||
if (args->use_thin_pack)
|
if (args->use_thin_pack)
|
||||||
packet_buf_write(&req_buf, "thin-pack");
|
packet_buf_write(&req_buf, "thin-pack");
|
||||||
|
@ -868,6 +868,12 @@ char *xgetcwd(void);
|
|||||||
FILE *fopen_for_writing(const char *path);
|
FILE *fopen_for_writing(const char *path);
|
||||||
FILE *fopen_or_warn(const char *path, const char *mode);
|
FILE *fopen_or_warn(const char *path, const char *mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like strncmp, but only return zero if s is NUL-terminated and exactly len
|
||||||
|
* characters long. If it is not, consider it greater than t.
|
||||||
|
*/
|
||||||
|
int xstrncmpz(const char *s, const char *t, size_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
|
* FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
|
||||||
* that ptr is used twice, so don't pass e.g. ptr++.
|
* that ptr is used twice, so don't pass e.g. ptr++.
|
||||||
|
2
git.c
2
git.c
@ -574,7 +574,7 @@ static struct cmd_struct commands[] = {
|
|||||||
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
|
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
|
||||||
{ "show", cmd_show, RUN_SETUP },
|
{ "show", cmd_show, RUN_SETUP },
|
||||||
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
||||||
{ "show-index", cmd_show_index },
|
{ "show-index", cmd_show_index, RUN_SETUP_GENTLY },
|
||||||
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
||||||
{ "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
|
{ "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
||||||
|
@ -70,6 +70,7 @@ struct packed_git {
|
|||||||
size_t index_size;
|
size_t index_size;
|
||||||
uint32_t num_objects;
|
uint32_t num_objects;
|
||||||
uint32_t num_bad_objects;
|
uint32_t num_bad_objects;
|
||||||
|
uint32_t crc_offset;
|
||||||
unsigned char *bad_object_sha1;
|
unsigned char *bad_object_sha1;
|
||||||
int index_version;
|
int index_version;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
|
@ -178,6 +178,7 @@ int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
|
|||||||
*/
|
*/
|
||||||
(sizeof(off_t) <= 4))
|
(sizeof(off_t) <= 4))
|
||||||
return error("pack too large for current definition of off_t in %s", path);
|
return error("pack too large for current definition of off_t in %s", path);
|
||||||
|
p->crc_offset = 8 + 4 * 256 + nr * hashsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->index_version = version;
|
p->index_version = version;
|
||||||
|
@ -490,6 +490,7 @@ void packet_reader_init(struct packet_reader *reader, int fd,
|
|||||||
reader->buffer_size = sizeof(packet_buffer);
|
reader->buffer_size = sizeof(packet_buffer);
|
||||||
reader->options = options;
|
reader->options = options;
|
||||||
reader->me = "git";
|
reader->me = "git";
|
||||||
|
reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
|
||||||
}
|
}
|
||||||
|
|
||||||
enum packet_read_status packet_reader_read(struct packet_reader *reader)
|
enum packet_read_status packet_reader_read(struct packet_reader *reader)
|
||||||
|
@ -177,6 +177,9 @@ struct packet_reader {
|
|||||||
|
|
||||||
unsigned use_sideband : 1;
|
unsigned use_sideband : 1;
|
||||||
const char *me;
|
const char *me;
|
||||||
|
|
||||||
|
/* hash algorithm in use */
|
||||||
|
const struct git_hash_algo *hash_algo;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -41,7 +41,9 @@ struct options {
|
|||||||
deepen_relative : 1,
|
deepen_relative : 1,
|
||||||
from_promisor : 1,
|
from_promisor : 1,
|
||||||
no_dependents : 1,
|
no_dependents : 1,
|
||||||
atomic : 1;
|
atomic : 1,
|
||||||
|
object_format : 1;
|
||||||
|
const struct git_hash_algo *hash_algo;
|
||||||
};
|
};
|
||||||
static struct options options;
|
static struct options options;
|
||||||
static struct string_list cas_options = STRING_LIST_INIT_DUP;
|
static struct string_list cas_options = STRING_LIST_INIT_DUP;
|
||||||
@ -190,6 +192,16 @@ static int set_option(const char *name, const char *value)
|
|||||||
} else if (!strcmp(name, "filter")) {
|
} else if (!strcmp(name, "filter")) {
|
||||||
options.filter = xstrdup(value);
|
options.filter = xstrdup(value);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!strcmp(name, "object-format")) {
|
||||||
|
int algo;
|
||||||
|
options.object_format = 1;
|
||||||
|
if (strcmp(value, "true")) {
|
||||||
|
algo = hash_algo_by_name(value);
|
||||||
|
if (algo == GIT_HASH_UNKNOWN)
|
||||||
|
die("unknown object format '%s'", value);
|
||||||
|
options.hash_algo = &hash_algos[algo];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return 1 /* unsupported */;
|
return 1 /* unsupported */;
|
||||||
}
|
}
|
||||||
@ -231,6 +243,7 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
|
|||||||
case protocol_v0:
|
case protocol_v0:
|
||||||
get_remote_heads(&reader, &list, for_push ? REF_NORMAL : 0,
|
get_remote_heads(&reader, &list, for_push ? REF_NORMAL : 0,
|
||||||
NULL, &heads->shallow);
|
NULL, &heads->shallow);
|
||||||
|
options.hash_algo = reader.hash_algo;
|
||||||
break;
|
break;
|
||||||
case protocol_unknown_version:
|
case protocol_unknown_version:
|
||||||
BUG("unknown protocol version");
|
BUG("unknown protocol version");
|
||||||
@ -239,6 +252,19 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct git_hash_algo *detect_hash_algo(struct discovery *heads)
|
||||||
|
{
|
||||||
|
const char *p = memchr(heads->buf, '\t', heads->len);
|
||||||
|
int algo;
|
||||||
|
if (!p)
|
||||||
|
return the_hash_algo;
|
||||||
|
|
||||||
|
algo = hash_algo_by_length((p - heads->buf) / 2);
|
||||||
|
if (algo == GIT_HASH_UNKNOWN)
|
||||||
|
return NULL;
|
||||||
|
return &hash_algos[algo];
|
||||||
|
}
|
||||||
|
|
||||||
static struct ref *parse_info_refs(struct discovery *heads)
|
static struct ref *parse_info_refs(struct discovery *heads)
|
||||||
{
|
{
|
||||||
char *data, *start, *mid;
|
char *data, *start, *mid;
|
||||||
@ -249,6 +275,12 @@ static struct ref *parse_info_refs(struct discovery *heads)
|
|||||||
struct ref *ref = NULL;
|
struct ref *ref = NULL;
|
||||||
struct ref *last_ref = NULL;
|
struct ref *last_ref = NULL;
|
||||||
|
|
||||||
|
options.hash_algo = detect_hash_algo(heads);
|
||||||
|
if (!options.hash_algo)
|
||||||
|
die("%sinfo/refs not valid: could not determine hash algorithm; "
|
||||||
|
"is this a git repository?",
|
||||||
|
transport_anonymize_url(url.buf));
|
||||||
|
|
||||||
data = heads->buf;
|
data = heads->buf;
|
||||||
start = NULL;
|
start = NULL;
|
||||||
mid = data;
|
mid = data;
|
||||||
@ -259,13 +291,13 @@ static struct ref *parse_info_refs(struct discovery *heads)
|
|||||||
if (data[i] == '\t')
|
if (data[i] == '\t')
|
||||||
mid = &data[i];
|
mid = &data[i];
|
||||||
if (data[i] == '\n') {
|
if (data[i] == '\n') {
|
||||||
if (mid - start != the_hash_algo->hexsz)
|
if (mid - start != options.hash_algo->hexsz)
|
||||||
die(_("%sinfo/refs not valid: is this a git repository?"),
|
die(_("%sinfo/refs not valid: is this a git repository?"),
|
||||||
transport_anonymize_url(url.buf));
|
transport_anonymize_url(url.buf));
|
||||||
data[i] = 0;
|
data[i] = 0;
|
||||||
ref_name = mid + 1;
|
ref_name = mid + 1;
|
||||||
ref = alloc_ref(ref_name);
|
ref = alloc_ref(ref_name);
|
||||||
get_oid_hex(start, &ref->old_oid);
|
get_oid_hex_algop(start, &ref->old_oid, options.hash_algo);
|
||||||
if (!refs)
|
if (!refs)
|
||||||
refs = ref;
|
refs = ref;
|
||||||
if (last_ref)
|
if (last_ref)
|
||||||
@ -509,11 +541,16 @@ static struct ref *get_refs(int for_push)
|
|||||||
static void output_refs(struct ref *refs)
|
static void output_refs(struct ref *refs)
|
||||||
{
|
{
|
||||||
struct ref *posn;
|
struct ref *posn;
|
||||||
|
if (options.object_format && options.hash_algo) {
|
||||||
|
printf(":object-format %s\n", options.hash_algo->name);
|
||||||
|
}
|
||||||
for (posn = refs; posn; posn = posn->next) {
|
for (posn = refs; posn; posn = posn->next) {
|
||||||
if (posn->symref)
|
if (posn->symref)
|
||||||
printf("@%s %s\n", posn->symref, posn->name);
|
printf("@%s %s\n", posn->symref, posn->name);
|
||||||
else
|
else
|
||||||
printf("%s %s\n", oid_to_hex(&posn->old_oid), posn->name);
|
printf("%s %s\n", hash_to_hex_algop(posn->old_oid.hash,
|
||||||
|
options.hash_algo),
|
||||||
|
posn->name);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@ -1499,6 +1536,7 @@ int cmd_main(int argc, const char **argv)
|
|||||||
printf("option\n");
|
printf("option\n");
|
||||||
printf("push\n");
|
printf("push\n");
|
||||||
printf("check-connectivity\n");
|
printf("check-connectivity\n");
|
||||||
|
printf("object-format\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
} else if (skip_prefix(buf.buf, "stateless-connect ", &arg)) {
|
} else if (skip_prefix(buf.buf, "stateless-connect ", &arg)) {
|
||||||
|
@ -363,6 +363,7 @@ int send_pack(struct send_pack_args *args,
|
|||||||
int atomic_supported = 0;
|
int atomic_supported = 0;
|
||||||
int use_push_options = 0;
|
int use_push_options = 0;
|
||||||
int push_options_supported = 0;
|
int push_options_supported = 0;
|
||||||
|
int object_format_supported = 0;
|
||||||
unsigned cmds_sent = 0;
|
unsigned cmds_sent = 0;
|
||||||
int ret;
|
int ret;
|
||||||
struct async demux;
|
struct async demux;
|
||||||
@ -389,6 +390,9 @@ int send_pack(struct send_pack_args *args,
|
|||||||
if (server_supports("push-options"))
|
if (server_supports("push-options"))
|
||||||
push_options_supported = 1;
|
push_options_supported = 1;
|
||||||
|
|
||||||
|
if (!server_supports_hash(the_hash_algo->name, &object_format_supported))
|
||||||
|
die(_("the receiving end does not support this repository's hash algorithm"));
|
||||||
|
|
||||||
if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
|
if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) {
|
||||||
int len;
|
int len;
|
||||||
push_cert_nonce = server_feature_value("push-cert", &len);
|
push_cert_nonce = server_feature_value("push-cert", &len);
|
||||||
@ -429,6 +433,8 @@ int send_pack(struct send_pack_args *args,
|
|||||||
strbuf_addstr(&cap_buf, " atomic");
|
strbuf_addstr(&cap_buf, " atomic");
|
||||||
if (use_push_options)
|
if (use_push_options)
|
||||||
strbuf_addstr(&cap_buf, " push-options");
|
strbuf_addstr(&cap_buf, " push-options");
|
||||||
|
if (object_format_supported)
|
||||||
|
strbuf_addf(&cap_buf, " object-format=%s", the_hash_algo->name);
|
||||||
if (agent_supported)
|
if (agent_supported)
|
||||||
strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
|
strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
|
||||||
|
|
||||||
|
27
serve.c
27
serve.c
@ -22,6 +22,14 @@ static int agent_advertise(struct repository *r,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int object_format_advertise(struct repository *r,
|
||||||
|
struct strbuf *value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
strbuf_addstr(value, r->hash_algo->name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
struct protocol_capability {
|
struct protocol_capability {
|
||||||
/*
|
/*
|
||||||
* The name of the capability. The server uses this name when
|
* The name of the capability. The server uses this name when
|
||||||
@ -57,6 +65,7 @@ static struct protocol_capability capabilities[] = {
|
|||||||
{ "ls-refs", always_advertise, ls_refs },
|
{ "ls-refs", always_advertise, ls_refs },
|
||||||
{ "fetch", upload_pack_advertise, upload_pack_v2 },
|
{ "fetch", upload_pack_advertise, upload_pack_v2 },
|
||||||
{ "server-option", always_advertise, NULL },
|
{ "server-option", always_advertise, NULL },
|
||||||
|
{ "object-format", object_format_advertise, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void advertise_capabilities(void)
|
static void advertise_capabilities(void)
|
||||||
@ -153,6 +162,22 @@ int has_capability(const struct argv_array *keys, const char *capability,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_algorithm(struct repository *r, struct argv_array *keys)
|
||||||
|
{
|
||||||
|
int client = GIT_HASH_SHA1, server = hash_algo_by_ptr(r->hash_algo);
|
||||||
|
const char *algo_name;
|
||||||
|
|
||||||
|
if (has_capability(keys, "object-format", &algo_name)) {
|
||||||
|
client = hash_algo_by_name(algo_name);
|
||||||
|
if (client == GIT_HASH_UNKNOWN)
|
||||||
|
die("unknown object format '%s'", algo_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client != server)
|
||||||
|
die("mismatched object format: server %s; client %s\n",
|
||||||
|
r->hash_algo->name, hash_algos[client].name);
|
||||||
|
}
|
||||||
|
|
||||||
enum request_state {
|
enum request_state {
|
||||||
PROCESS_REQUEST_KEYS,
|
PROCESS_REQUEST_KEYS,
|
||||||
PROCESS_REQUEST_DONE,
|
PROCESS_REQUEST_DONE,
|
||||||
@ -225,6 +250,8 @@ static int process_request(void)
|
|||||||
if (!command)
|
if (!command)
|
||||||
die("no command requested");
|
die("no command requested");
|
||||||
|
|
||||||
|
check_algorithm(the_repository, &keys);
|
||||||
|
|
||||||
command->command(the_repository, &keys, &reader);
|
command->command(the_repository, &keys, &reader);
|
||||||
|
|
||||||
argv_array_clear(&keys);
|
argv_array_clear(&keys);
|
||||||
|
1
setup.c
1
setup.c
@ -1308,6 +1308,7 @@ void check_repository_format(struct repository_format *fmt)
|
|||||||
fmt = &repo_fmt;
|
fmt = &repo_fmt;
|
||||||
check_repository_format_gently(get_git_dir(), fmt, NULL);
|
check_repository_format_gently(get_git_dir(), fmt, NULL);
|
||||||
startup_info->have_repository = 1;
|
startup_info->have_repository = 1;
|
||||||
|
repo_set_hash_algo(the_repository, fmt->hash_algo);
|
||||||
clear_repository_format(&repo_fmt);
|
clear_repository_format(&repo_fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ int cmd__oid_array(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
struct oid_array array = OID_ARRAY_INIT;
|
struct oid_array array = OID_ARRAY_INIT;
|
||||||
struct strbuf line = STRBUF_INIT;
|
struct strbuf line = STRBUF_INIT;
|
||||||
|
int nongit_ok;
|
||||||
|
|
||||||
|
setup_git_directory_gently(&nongit_ok);
|
||||||
|
|
||||||
while (strbuf_getline(&line, stdin) != EOF) {
|
while (strbuf_getline(&line, stdin) != EOF) {
|
||||||
const char *arg;
|
const char *arg;
|
||||||
|
@ -12,6 +12,7 @@ file_size () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test_expect_success setup '
|
test_expect_success setup '
|
||||||
|
test_oid_init &&
|
||||||
# clone does not allow us to pass core.bigfilethreshold to
|
# clone does not allow us to pass core.bigfilethreshold to
|
||||||
# new repos, so set core.bigfilethreshold globally
|
# new repos, so set core.bigfilethreshold globally
|
||||||
git config --global core.bigfilethreshold 200k &&
|
git config --global core.bigfilethreshold 200k &&
|
||||||
@ -64,7 +65,7 @@ test_expect_success 'add a large file or two' '
|
|||||||
test $count = 1 &&
|
test $count = 1 &&
|
||||||
cnt=$(git show-index <"$idx" | wc -l) &&
|
cnt=$(git show-index <"$idx" | wc -l) &&
|
||||||
test $cnt = 2 &&
|
test $cnt = 2 &&
|
||||||
for l in .git/objects/??/??????????????????????????????????????
|
for l in .git/objects/$OIDPATH_REGEX
|
||||||
do
|
do
|
||||||
test_path_is_file "$l" || continue
|
test_path_is_file "$l" || continue
|
||||||
bad=t
|
bad=t
|
||||||
@ -177,7 +178,8 @@ test_expect_success 'git-show a large file' '
|
|||||||
|
|
||||||
test_expect_success 'index-pack' '
|
test_expect_success 'index-pack' '
|
||||||
git clone file://"$(pwd)"/.git foo &&
|
git clone file://"$(pwd)"/.git foo &&
|
||||||
GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack
|
GIT_DIR=non-existent git index-pack --object-format=$(test_oid algo) \
|
||||||
|
--strict --verify foo/.git/objects/pack/*.pack
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'repack' '
|
test_expect_success 'repack' '
|
||||||
|
@ -8,6 +8,10 @@ test_description='Test repository version check'
|
|||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
|
test_oid_cache <<-\EOF &&
|
||||||
|
version sha1:0
|
||||||
|
version sha256:1
|
||||||
|
EOF
|
||||||
cat >test.patch <<-\EOF &&
|
cat >test.patch <<-\EOF &&
|
||||||
diff --git a/test.txt b/test.txt
|
diff --git a/test.txt b/test.txt
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
@ -23,7 +27,7 @@ test_expect_success 'setup' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'gitdir selection on normal repos' '
|
test_expect_success 'gitdir selection on normal repos' '
|
||||||
echo 0 >expect &&
|
echo $(test_oid version) >expect &&
|
||||||
git config core.repositoryformatversion >actual &&
|
git config core.repositoryformatversion >actual &&
|
||||||
git -C test config core.repositoryformatversion >actual2 &&
|
git -C test config core.repositoryformatversion >actual2 &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
@ -402,7 +402,7 @@ EOF
|
|||||||
|
|
||||||
mv .git/config .git/config-saved
|
mv .git/config .git/config-saved
|
||||||
|
|
||||||
test_expect_success 'git branch -m q q2 without config should succeed' '
|
test_expect_success SHA1 'git branch -m q q2 without config should succeed' '
|
||||||
git branch -m q q2 &&
|
git branch -m q q2 &&
|
||||||
git branch -m q2 q
|
git branch -m q2 q
|
||||||
'
|
'
|
||||||
|
@ -12,7 +12,8 @@ TRASH=$(pwd)
|
|||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'setup' \
|
'setup' \
|
||||||
'rm -f .git/index* &&
|
'test_oid_init &&
|
||||||
|
rm -f .git/index* &&
|
||||||
perl -e "print \"a\" x 4096;" > a &&
|
perl -e "print \"a\" x 4096;" > a &&
|
||||||
perl -e "print \"b\" x 4096;" > b &&
|
perl -e "print \"b\" x 4096;" > b &&
|
||||||
perl -e "print \"c\" x 4096;" > c &&
|
perl -e "print \"c\" x 4096;" > c &&
|
||||||
@ -412,18 +413,18 @@ test_expect_success 'set up pack for non-repo tests' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'index-pack --stdin complains of non-repo' '
|
test_expect_success 'index-pack --stdin complains of non-repo' '
|
||||||
nongit test_must_fail git index-pack --stdin <foo.pack &&
|
nongit test_must_fail git index-pack --object-format=$(test_oid algo) --stdin <foo.pack &&
|
||||||
test_path_is_missing non-repo/.git
|
test_path_is_missing non-repo/.git
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'index-pack <pack> works in non-repo' '
|
test_expect_success 'index-pack <pack> works in non-repo' '
|
||||||
nongit git index-pack ../foo.pack &&
|
nongit git index-pack --object-format=$(test_oid algo) ../foo.pack &&
|
||||||
test_path_is_file foo.idx
|
test_path_is_file foo.idx
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'index-pack --strict <pack> works in non-repo' '
|
test_expect_success 'index-pack --strict <pack> works in non-repo' '
|
||||||
rm -f foo.idx &&
|
rm -f foo.idx &&
|
||||||
nongit git index-pack --strict ../foo.pack &&
|
nongit git index-pack --strict --object-format=$(test_oid algo) ../foo.pack &&
|
||||||
test_path_is_file foo.idx
|
test_path_is_file foo.idx
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -36,36 +36,36 @@ test_expect_success 'setup' '
|
|||||||
git update-ref HEAD $commit
|
git update-ref HEAD $commit
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'pack-objects with index version 1' '
|
||||||
'pack-objects with index version 1' \
|
pack1=$(git pack-objects --index-version=1 test-1 <obj-list) &&
|
||||||
'pack1=$(git pack-objects --index-version=1 test-1 <obj-list) &&
|
git verify-pack -v "test-1-${pack1}.pack"
|
||||||
git verify-pack -v "test-1-${pack1}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'pack-objects with index version 2' '
|
||||||
'pack-objects with index version 2' \
|
pack2=$(git pack-objects --index-version=2 test-2 <obj-list) &&
|
||||||
'pack2=$(git pack-objects --index-version=2 test-2 <obj-list) &&
|
git verify-pack -v "test-2-${pack2}.pack"
|
||||||
git verify-pack -v "test-2-${pack2}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'both packs should be identical' '
|
||||||
'both packs should be identical' \
|
cmp "test-1-${pack1}.pack" "test-2-${pack2}.pack"
|
||||||
'cmp "test-1-${pack1}.pack" "test-2-${pack2}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'index v1 and index v2 should be different' '
|
||||||
'index v1 and index v2 should be different' \
|
! cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx"
|
||||||
'! cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'index-pack with index version 1' '
|
||||||
'index-pack with index version 1' \
|
git index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack"
|
||||||
'git index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'index-pack with index version 2' '
|
||||||
'index-pack with index version 2' \
|
git index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack"
|
||||||
'git index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'index-pack results should match pack-objects ones' '
|
||||||
'index-pack results should match pack-objects ones' \
|
cmp "test-1-${pack1}.idx" "1.idx" &&
|
||||||
'cmp "test-1-${pack1}.idx" "1.idx" &&
|
cmp "test-2-${pack2}.idx" "2.idx"
|
||||||
cmp "test-2-${pack2}.idx" "2.idx"'
|
'
|
||||||
|
|
||||||
test_expect_success 'index-pack --verify on index version 1' '
|
test_expect_success 'index-pack --verify on index version 1' '
|
||||||
git index-pack --verify "test-1-${pack1}.pack"
|
git index-pack --verify "test-1-${pack1}.pack"
|
||||||
@ -75,13 +75,13 @@ test_expect_success 'index-pack --verify on index version 2' '
|
|||||||
git index-pack --verify "test-2-${pack2}.pack"
|
git index-pack --verify "test-2-${pack2}.pack"
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'pack-objects --index-version=2, is not accepted' '
|
||||||
'pack-objects --index-version=2, is not accepted' \
|
test_must_fail git pack-objects --index-version=2, test-3 <obj-list
|
||||||
'test_must_fail git pack-objects --index-version=2, test-3 <obj-list'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success 'index v2: force some 64-bit offsets with pack-objects' '
|
||||||
'index v2: force some 64-bit offsets with pack-objects' \
|
pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)
|
||||||
'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)'
|
'
|
||||||
|
|
||||||
if msg=$(git verify-pack -v "test-3-${pack3}.pack" 2>&1) ||
|
if msg=$(git verify-pack -v "test-3-${pack3}.pack" 2>&1) ||
|
||||||
! (echo "$msg" | grep "pack too large .* off_t")
|
! (echo "$msg" | grep "pack too large .* off_t")
|
||||||
@ -91,21 +91,21 @@ else
|
|||||||
say "# skipping tests concerning 64-bit offsets"
|
say "# skipping tests concerning 64-bit offsets"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
test_expect_success OFF64_T \
|
test_expect_success OFF64_T 'index v2: verify a pack with some 64-bit offsets' '
|
||||||
'index v2: verify a pack with some 64-bit offsets' \
|
git verify-pack -v "test-3-${pack3}.pack"
|
||||||
'git verify-pack -v "test-3-${pack3}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success OFF64_T \
|
test_expect_success OFF64_T '64-bit offsets: should be different from previous index v2 results' '
|
||||||
'64-bit offsets: should be different from previous index v2 results' \
|
! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"
|
||||||
'! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"'
|
'
|
||||||
|
|
||||||
test_expect_success OFF64_T \
|
test_expect_success OFF64_T 'index v2: force some 64-bit offsets with index-pack' '
|
||||||
'index v2: force some 64-bit offsets with index-pack' \
|
git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"
|
||||||
'git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success OFF64_T \
|
test_expect_success OFF64_T '64-bit offsets: index-pack result should match pack-objects one' '
|
||||||
'64-bit offsets: index-pack result should match pack-objects one' \
|
cmp "test-3-${pack3}.idx" "3.idx"
|
||||||
'cmp "test-3-${pack3}.idx" "3.idx"'
|
'
|
||||||
|
|
||||||
test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2 (cheat)' '
|
test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2 (cheat)' '
|
||||||
# This cheats by knowing which lower offset should still be encoded
|
# This cheats by knowing which lower offset should still be encoded
|
||||||
@ -142,17 +142,17 @@ index_obj_offset()
|
|||||||
( read offs extra && echo "$offs" )
|
( read offs extra && echo "$offs" )
|
||||||
}
|
}
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success '[index v1] 1) stream pack to repository' '
|
||||||
'[index v1] 1) stream pack to repository' \
|
git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" &&
|
||||||
'git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" &&
|
|
||||||
git prune-packed &&
|
git prune-packed &&
|
||||||
git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
|
git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
|
||||||
cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
|
cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
|
||||||
cmp "test-1-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"'
|
cmp "test-1-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v1] 2) create a stealth corruption in a delta base reference' \
|
'[index v1] 2) create a stealth corruption in a delta base reference' '
|
||||||
'# This test assumes file_101 is a delta smaller than 16 bytes.
|
# This test assumes file_101 is a delta smaller than 16 bytes.
|
||||||
# It should be against file_100 but we substitute its base for file_099
|
# It should be against file_100 but we substitute its base for file_099
|
||||||
sha1_101=$(git hash-object file_101) &&
|
sha1_101=$(git hash-object file_101) &&
|
||||||
sha1_099=$(git hash-object file_099) &&
|
sha1_099=$(git hash-object file_099) &&
|
||||||
@ -164,37 +164,41 @@ test_expect_success \
|
|||||||
if=".git/objects/pack/pack-${pack1}.idx" \
|
if=".git/objects/pack/pack-${pack1}.idx" \
|
||||||
skip=$((4 + 256 * 4 + $nr_099 * recordsz)) \
|
skip=$((4 + 256 * 4 + $nr_099 * recordsz)) \
|
||||||
bs=1 count=$rawsz conv=notrunc &&
|
bs=1 count=$rawsz conv=notrunc &&
|
||||||
git cat-file blob $sha1_101 > file_101_foo1'
|
git cat-file blob $sha1_101 > file_101_foo1
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v1] 3) corrupted delta happily returned wrong data' \
|
'[index v1] 3) corrupted delta happily returned wrong data' '
|
||||||
'test -f file_101_foo1 && ! cmp file_101 file_101_foo1'
|
test -f file_101_foo1 && ! cmp file_101 file_101_foo1
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v1] 4) confirm that the pack is actually corrupted' \
|
'[index v1] 4) confirm that the pack is actually corrupted' '
|
||||||
'test_must_fail git fsck --full $commit'
|
test_must_fail git fsck --full $commit
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v1] 5) pack-objects happily reuses corrupted data' \
|
'[index v1] 5) pack-objects happily reuses corrupted data' '
|
||||||
'pack4=$(git pack-objects test-4 <obj-list) &&
|
pack4=$(git pack-objects test-4 <obj-list) &&
|
||||||
test -f "test-4-${pack4}.pack"'
|
test -f "test-4-${pack4}.pack"
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success '[index v1] 6) newly created pack is BAD !' '
|
||||||
'[index v1] 6) newly created pack is BAD !' \
|
test_must_fail git verify-pack -v "test-4-${pack4}.pack"
|
||||||
'test_must_fail git verify-pack -v "test-4-${pack4}.pack"'
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success '[index v2] 1) stream pack to repository' '
|
||||||
'[index v2] 1) stream pack to repository' \
|
rm -f .git/objects/pack/* &&
|
||||||
'rm -f .git/objects/pack/* &&
|
|
||||||
git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
|
git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
|
||||||
git prune-packed &&
|
git prune-packed &&
|
||||||
git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
|
git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
|
||||||
cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
|
cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
|
||||||
cmp "test-2-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"'
|
cmp "test-2-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v2] 2) create a stealth corruption in a delta base reference' \
|
'[index v2] 2) create a stealth corruption in a delta base reference' '
|
||||||
'# This test assumes file_101 is a delta smaller than 16 bytes.
|
# This test assumes file_101 is a delta smaller than 16 bytes.
|
||||||
# It should be against file_100 but we substitute its base for file_099
|
# It should be against file_100 but we substitute its base for file_099
|
||||||
sha1_101=$(git hash-object file_101) &&
|
sha1_101=$(git hash-object file_101) &&
|
||||||
sha1_099=$(git hash-object file_099) &&
|
sha1_099=$(git hash-object file_099) &&
|
||||||
@ -205,24 +209,28 @@ test_expect_success \
|
|||||||
if=".git/objects/pack/pack-${pack1}.idx" \
|
if=".git/objects/pack/pack-${pack1}.idx" \
|
||||||
skip=$((8 + 256 * 4 + $nr_099 * rawsz)) \
|
skip=$((8 + 256 * 4 + $nr_099 * rawsz)) \
|
||||||
bs=1 count=$rawsz conv=notrunc &&
|
bs=1 count=$rawsz conv=notrunc &&
|
||||||
git cat-file blob $sha1_101 > file_101_foo2'
|
git cat-file blob $sha1_101 > file_101_foo2
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v2] 3) corrupted delta happily returned wrong data' \
|
'[index v2] 3) corrupted delta happily returned wrong data' '
|
||||||
'test -f file_101_foo2 && ! cmp file_101 file_101_foo2'
|
test -f file_101_foo2 && ! cmp file_101 file_101_foo2
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v2] 4) confirm that the pack is actually corrupted' \
|
'[index v2] 4) confirm that the pack is actually corrupted' '
|
||||||
'test_must_fail git fsck --full $commit'
|
test_must_fail git fsck --full $commit
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v2] 5) pack-objects refuses to reuse corrupted data' \
|
'[index v2] 5) pack-objects refuses to reuse corrupted data' '
|
||||||
'test_must_fail git pack-objects test-5 <obj-list &&
|
test_must_fail git pack-objects test-5 <obj-list &&
|
||||||
test_must_fail git pack-objects --no-reuse-object test-6 <obj-list'
|
test_must_fail git pack-objects --no-reuse-object test-6 <obj-list
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'[index v2] 6) verify-pack detects CRC mismatch' \
|
'[index v2] 6) verify-pack detects CRC mismatch' '
|
||||||
'rm -f .git/objects/pack/* &&
|
rm -f .git/objects/pack/* &&
|
||||||
git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
|
git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
|
||||||
git verify-pack ".git/objects/pack/pack-${pack1}.pack" &&
|
git verify-pack ".git/objects/pack/pack-${pack1}.pack" &&
|
||||||
obj=$(git hash-object file_001) &&
|
obj=$(git hash-object file_001) &&
|
||||||
|
@ -871,9 +871,10 @@ test_expect_success 'shallow since with commit graph and already-seen commit' '
|
|||||||
|
|
||||||
GIT_PROTOCOL=version=2 git upload-pack . <<-EOF >/dev/null
|
GIT_PROTOCOL=version=2 git upload-pack . <<-EOF >/dev/null
|
||||||
0012command=fetch
|
0012command=fetch
|
||||||
|
$(echo "object-format=$(test_oid algo)" | packetize)
|
||||||
00010013deepen-since 1
|
00010013deepen-since 1
|
||||||
0032want $(git rev-parse other)
|
$(echo "want $(git rev-parse other)" | packetize)
|
||||||
0032have $(git rev-parse master)
|
$(echo "have $(git rev-parse master)" | packetize)
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
@ -50,6 +50,24 @@ test_expect_success 'create password-protected repository' '
|
|||||||
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
|
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'create empty remote repository' '
|
||||||
|
git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
|
||||||
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
|
||||||
|
mkdir -p hooks &&
|
||||||
|
write_script "hooks/post-update" <<-\EOF &&
|
||||||
|
exec git update-server-info
|
||||||
|
EOF
|
||||||
|
hooks/post-update
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'empty dumb HTTP repository has default hash algorithm' '
|
||||||
|
test_when_finished "rm -fr clone-empty" &&
|
||||||
|
git clone $HTTPD_URL/dumb/empty.git clone-empty &&
|
||||||
|
git -C clone-empty rev-parse --show-object-format >empty-format &&
|
||||||
|
test "$(cat empty-format)" = "$(test_oid algo)"
|
||||||
|
'
|
||||||
|
|
||||||
setup_askpass_helper
|
setup_askpass_helper
|
||||||
|
|
||||||
test_expect_success 'cloning password-protected repository can fail' '
|
test_expect_success 'cloning password-protected repository can fail' '
|
||||||
|
@ -46,6 +46,7 @@ ssize_b100dots() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test_expect_success 'setup' '
|
test_expect_success 'setup' '
|
||||||
|
test_oid_init &&
|
||||||
HTTP_CONTENT_ENCODING="identity" &&
|
HTTP_CONTENT_ENCODING="identity" &&
|
||||||
export HTTP_CONTENT_ENCODING &&
|
export HTTP_CONTENT_ENCODING &&
|
||||||
git config http.receivepack true &&
|
git config http.receivepack true &&
|
||||||
@ -62,8 +63,8 @@ test_expect_success 'setup' '
|
|||||||
test_copy_bytes 10 <fetch_body >fetch_body.trunc &&
|
test_copy_bytes 10 <fetch_body >fetch_body.trunc &&
|
||||||
hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) &&
|
hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) &&
|
||||||
{
|
{
|
||||||
printf "%s %s refs/heads/newbranch\\0report-status\\n" \
|
printf "%s %s refs/heads/newbranch\\0report-status object-format=%s\\n" \
|
||||||
"$ZERO_OID" "$hash_next" | packetize &&
|
"$ZERO_OID" "$hash_next" "$(test_oid algo)" | packetize &&
|
||||||
printf 0000 &&
|
printf 0000 &&
|
||||||
echo "$hash_next" | git pack-objects --stdout
|
echo "$hash_next" | git pack-objects --stdout
|
||||||
} >push_body &&
|
} >push_body &&
|
||||||
|
@ -5,12 +5,17 @@ test_description='test protocol v2 server commands'
|
|||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
test_expect_success 'test capability advertisement' '
|
test_expect_success 'test capability advertisement' '
|
||||||
|
test_oid_cache <<-EOF &&
|
||||||
|
wrong_algo sha1:sha256
|
||||||
|
wrong_algo sha256:sha1
|
||||||
|
EOF
|
||||||
cat >expect <<-EOF &&
|
cat >expect <<-EOF &&
|
||||||
version 2
|
version 2
|
||||||
agent=git/$(git version | cut -d" " -f3)
|
agent=git/$(git version | cut -d" " -f3)
|
||||||
ls-refs
|
ls-refs
|
||||||
fetch=shallow
|
fetch=shallow
|
||||||
server-option
|
server-option
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@ -45,6 +50,7 @@ test_expect_success 'request invalid capability' '
|
|||||||
test_expect_success 'request with no command' '
|
test_expect_success 'request with no command' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
agent=git/test
|
agent=git/test
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
|
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
|
||||||
@ -54,6 +60,7 @@ test_expect_success 'request with no command' '
|
|||||||
test_expect_success 'request invalid command' '
|
test_expect_success 'request invalid command' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=foo
|
command=foo
|
||||||
|
object-format=$(test_oid algo)
|
||||||
agent=git/test
|
agent=git/test
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
@ -61,6 +68,17 @@ test_expect_success 'request invalid command' '
|
|||||||
test_i18ngrep "invalid command" err
|
test_i18ngrep "invalid command" err
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'wrong object-format' '
|
||||||
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
|
command=fetch
|
||||||
|
agent=git/test
|
||||||
|
object-format=$(test_oid wrong_algo)
|
||||||
|
0000
|
||||||
|
EOF
|
||||||
|
test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in &&
|
||||||
|
test_i18ngrep "mismatched object format" err
|
||||||
|
'
|
||||||
|
|
||||||
# Test the basics of ls-refs
|
# Test the basics of ls-refs
|
||||||
#
|
#
|
||||||
test_expect_success 'setup some refs and tags' '
|
test_expect_success 'setup some refs and tags' '
|
||||||
@ -74,6 +92,7 @@ test_expect_success 'setup some refs and tags' '
|
|||||||
test_expect_success 'basics of ls-refs' '
|
test_expect_success 'basics of ls-refs' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=ls-refs
|
command=ls-refs
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@ -96,6 +115,7 @@ test_expect_success 'basics of ls-refs' '
|
|||||||
test_expect_success 'basic ref-prefixes' '
|
test_expect_success 'basic ref-prefixes' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=ls-refs
|
command=ls-refs
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0001
|
0001
|
||||||
ref-prefix refs/heads/master
|
ref-prefix refs/heads/master
|
||||||
ref-prefix refs/tags/one
|
ref-prefix refs/tags/one
|
||||||
@ -116,6 +136,7 @@ test_expect_success 'basic ref-prefixes' '
|
|||||||
test_expect_success 'refs/heads prefix' '
|
test_expect_success 'refs/heads prefix' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=ls-refs
|
command=ls-refs
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0001
|
0001
|
||||||
ref-prefix refs/heads/
|
ref-prefix refs/heads/
|
||||||
0000
|
0000
|
||||||
@ -136,6 +157,7 @@ test_expect_success 'refs/heads prefix' '
|
|||||||
test_expect_success 'peel parameter' '
|
test_expect_success 'peel parameter' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=ls-refs
|
command=ls-refs
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0001
|
0001
|
||||||
peel
|
peel
|
||||||
ref-prefix refs/tags/
|
ref-prefix refs/tags/
|
||||||
@ -157,6 +179,7 @@ test_expect_success 'peel parameter' '
|
|||||||
test_expect_success 'symrefs parameter' '
|
test_expect_success 'symrefs parameter' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=ls-refs
|
command=ls-refs
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0001
|
0001
|
||||||
symrefs
|
symrefs
|
||||||
ref-prefix refs/heads/
|
ref-prefix refs/heads/
|
||||||
@ -178,6 +201,7 @@ test_expect_success 'symrefs parameter' '
|
|||||||
test_expect_success 'sending server-options' '
|
test_expect_success 'sending server-options' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=ls-refs
|
command=ls-refs
|
||||||
|
object-format=$(test_oid algo)
|
||||||
server-option=hello
|
server-option=hello
|
||||||
server-option=world
|
server-option=world
|
||||||
0001
|
0001
|
||||||
@ -200,6 +224,7 @@ test_expect_success 'unexpected lines are not allowed in fetch request' '
|
|||||||
|
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
command=fetch
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0001
|
0001
|
||||||
this-is-not-a-command
|
this-is-not-a-command
|
||||||
0000
|
0000
|
||||||
|
@ -13,6 +13,7 @@ start_git_daemon --export-all --enable=receive-pack
|
|||||||
daemon_parent=$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent
|
daemon_parent=$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent
|
||||||
|
|
||||||
test_expect_success 'create repo to be served by git-daemon' '
|
test_expect_success 'create repo to be served by git-daemon' '
|
||||||
|
test_oid_init &&
|
||||||
git init "$daemon_parent" &&
|
git init "$daemon_parent" &&
|
||||||
test_commit -C "$daemon_parent" one
|
test_commit -C "$daemon_parent" one
|
||||||
'
|
'
|
||||||
@ -393,6 +394,7 @@ test_expect_success 'even with handcrafted request, filter does not work if not
|
|||||||
# Custom request that tries to filter even though it is not advertised.
|
# Custom request that tries to filter even though it is not advertised.
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
command=fetch
|
||||||
|
object-format=$(test_oid algo)
|
||||||
0001
|
0001
|
||||||
want $(git -C server rev-parse master)
|
want $(git -C server rev-parse master)
|
||||||
filter blob:none
|
filter blob:none
|
||||||
|
@ -27,6 +27,15 @@ check_output () {
|
|||||||
test_cmp sorted_commits actual_commits
|
test_cmp sorted_commits actual_commits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_command () {
|
||||||
|
echo "command=$1"
|
||||||
|
|
||||||
|
if test "$(test_oid algo)" != sha1
|
||||||
|
then
|
||||||
|
echo "object-format=$(test_oid algo)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# c(o/foo) d(o/bar)
|
# c(o/foo) d(o/bar)
|
||||||
# \ /
|
# \ /
|
||||||
# b e(baz) f(master)
|
# b e(baz) f(master)
|
||||||
@ -65,7 +74,7 @@ test_expect_success 'config controls ref-in-want advertisement' '
|
|||||||
|
|
||||||
test_expect_success 'invalid want-ref line' '
|
test_expect_success 'invalid want-ref line' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
$(write_command fetch)
|
||||||
0001
|
0001
|
||||||
no-progress
|
no-progress
|
||||||
want-ref refs/heads/non-existent
|
want-ref refs/heads/non-existent
|
||||||
@ -86,7 +95,7 @@ test_expect_success 'basic want-ref' '
|
|||||||
|
|
||||||
oid=$(git rev-parse a) &&
|
oid=$(git rev-parse a) &&
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
$(write_command fetch)
|
||||||
0001
|
0001
|
||||||
no-progress
|
no-progress
|
||||||
want-ref refs/heads/master
|
want-ref refs/heads/master
|
||||||
@ -110,7 +119,7 @@ test_expect_success 'multiple want-ref lines' '
|
|||||||
|
|
||||||
oid=$(git rev-parse b) &&
|
oid=$(git rev-parse b) &&
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
$(write_command fetch)
|
||||||
0001
|
0001
|
||||||
no-progress
|
no-progress
|
||||||
want-ref refs/heads/o/foo
|
want-ref refs/heads/o/foo
|
||||||
@ -132,7 +141,7 @@ test_expect_success 'mix want and want-ref' '
|
|||||||
git rev-parse e f >expected_commits &&
|
git rev-parse e f >expected_commits &&
|
||||||
|
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
$(write_command fetch)
|
||||||
0001
|
0001
|
||||||
no-progress
|
no-progress
|
||||||
want-ref refs/heads/master
|
want-ref refs/heads/master
|
||||||
@ -155,7 +164,7 @@ test_expect_success 'want-ref with ref we already have commit for' '
|
|||||||
|
|
||||||
oid=$(git rev-parse c) &&
|
oid=$(git rev-parse c) &&
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=fetch
|
$(write_command fetch)
|
||||||
0001
|
0001
|
||||||
no-progress
|
no-progress
|
||||||
want-ref refs/heads/o/foo
|
want-ref refs/heads/o/foo
|
||||||
|
@ -9,6 +9,7 @@ making sure that we do not segfault or otherwise behave badly.'
|
|||||||
test_expect_success 'extra delim packet in v2 ls-refs args' '
|
test_expect_success 'extra delim packet in v2 ls-refs args' '
|
||||||
{
|
{
|
||||||
packetize command=ls-refs &&
|
packetize command=ls-refs &&
|
||||||
|
packetize "object-format=$(test_oid algo)" &&
|
||||||
printf 0001 &&
|
printf 0001 &&
|
||||||
# protocol expects 0000 flush here
|
# protocol expects 0000 flush here
|
||||||
printf 0001
|
printf 0001
|
||||||
@ -21,6 +22,7 @@ test_expect_success 'extra delim packet in v2 ls-refs args' '
|
|||||||
test_expect_success 'extra delim packet in v2 fetch args' '
|
test_expect_success 'extra delim packet in v2 fetch args' '
|
||||||
{
|
{
|
||||||
packetize command=fetch &&
|
packetize command=fetch &&
|
||||||
|
packetize "object-format=$(test_oid algo)" &&
|
||||||
printf 0001 &&
|
printf 0001 &&
|
||||||
# protocol expects 0000 flush here
|
# protocol expects 0000 flush here
|
||||||
printf 0001
|
printf 0001
|
||||||
|
@ -52,9 +52,11 @@ do
|
|||||||
test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
|
test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
|
||||||
test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
|
test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
|
||||||
echo 'option'
|
echo 'option'
|
||||||
|
echo 'object-format'
|
||||||
echo
|
echo
|
||||||
;;
|
;;
|
||||||
list)
|
list)
|
||||||
|
echo ":object-format $(git rev-parse --show-object-format=storage)"
|
||||||
git for-each-ref --format='? %(refname)' 'refs/heads/' 'refs/tags/'
|
git for-each-ref --format='? %(refname)' 'refs/heads/' 'refs/tags/'
|
||||||
head=$(git symbolic-ref HEAD)
|
head=$(git symbolic-ref HEAD)
|
||||||
echo "@$head HEAD"
|
echo "@$head HEAD"
|
||||||
@ -139,6 +141,10 @@ do
|
|||||||
test $val = "true" && force="true" || force=
|
test $val = "true" && force="true" || force=
|
||||||
echo "ok"
|
echo "ok"
|
||||||
;;
|
;;
|
||||||
|
object-format)
|
||||||
|
test $val = "true" && object_format="true" || object_format=
|
||||||
|
echo "ok"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "unsupported"
|
echo "unsupported"
|
||||||
;;
|
;;
|
||||||
|
@ -1414,6 +1414,7 @@ test_oid_init
|
|||||||
|
|
||||||
ZERO_OID=$(test_oid zero)
|
ZERO_OID=$(test_oid zero)
|
||||||
OID_REGEX=$(echo $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
|
OID_REGEX=$(echo $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
|
||||||
|
OIDPATH_REGEX=$(test_oid_to_path $ZERO_OID | sed -e 's/0/[0-9a-f]/g')
|
||||||
EMPTY_TREE=$(test_oid empty_tree)
|
EMPTY_TREE=$(test_oid empty_tree)
|
||||||
EMPTY_BLOB=$(test_oid empty_blob)
|
EMPTY_BLOB=$(test_oid empty_blob)
|
||||||
_z40=$ZERO_OID
|
_z40=$ZERO_OID
|
||||||
|
@ -32,7 +32,8 @@ struct helper_data {
|
|||||||
signed_tags : 1,
|
signed_tags : 1,
|
||||||
check_connectivity : 1,
|
check_connectivity : 1,
|
||||||
no_disconnect_req : 1,
|
no_disconnect_req : 1,
|
||||||
no_private_update : 1;
|
no_private_update : 1,
|
||||||
|
object_format : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As an optimization, the transport code may invoke fetch before
|
* As an optimization, the transport code may invoke fetch before
|
||||||
@ -207,6 +208,8 @@ static struct child_process *get_helper(struct transport *transport)
|
|||||||
data->import_marks = xstrdup(arg);
|
data->import_marks = xstrdup(arg);
|
||||||
} else if (starts_with(capname, "no-private-update")) {
|
} else if (starts_with(capname, "no-private-update")) {
|
||||||
data->no_private_update = 1;
|
data->no_private_update = 1;
|
||||||
|
} else if (starts_with(capname, "object-format")) {
|
||||||
|
data->object_format = 1;
|
||||||
} else if (mandatory) {
|
} else if (mandatory) {
|
||||||
die(_("unknown mandatory capability %s; this remote "
|
die(_("unknown mandatory capability %s; this remote "
|
||||||
"helper probably needs newer version of Git"),
|
"helper probably needs newer version of Git"),
|
||||||
@ -1104,6 +1107,12 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
|
|||||||
data->get_refs_list_called = 1;
|
data->get_refs_list_called = 1;
|
||||||
helper = get_helper(transport);
|
helper = get_helper(transport);
|
||||||
|
|
||||||
|
if (data->object_format) {
|
||||||
|
write_str_in_full(helper->in, "option object-format\n");
|
||||||
|
if (recvline(data, &buf) || strcmp(buf.buf, "ok"))
|
||||||
|
exit(128);
|
||||||
|
}
|
||||||
|
|
||||||
if (data->push && for_push)
|
if (data->push && for_push)
|
||||||
write_str_in_full(helper->in, "list for-push\n");
|
write_str_in_full(helper->in, "list for-push\n");
|
||||||
else
|
else
|
||||||
@ -1116,6 +1125,17 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
|
|||||||
|
|
||||||
if (!*buf.buf)
|
if (!*buf.buf)
|
||||||
break;
|
break;
|
||||||
|
else if (buf.buf[0] == ':') {
|
||||||
|
const char *value;
|
||||||
|
if (skip_prefix(buf.buf, ":object-format ", &value)) {
|
||||||
|
int algo = hash_algo_by_name(value);
|
||||||
|
if (algo == GIT_HASH_UNKNOWN)
|
||||||
|
die(_("unsupported object format '%s'"),
|
||||||
|
value);
|
||||||
|
transport->hash_algo = &hash_algos[algo];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
eov = strchr(buf.buf, ' ');
|
eov = strchr(buf.buf, ' ');
|
||||||
if (!eov)
|
if (!eov)
|
||||||
@ -1128,7 +1148,7 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
|
|||||||
if (buf.buf[0] == '@')
|
if (buf.buf[0] == '@')
|
||||||
(*tail)->symref = xstrdup(buf.buf + 1);
|
(*tail)->symref = xstrdup(buf.buf + 1);
|
||||||
else if (buf.buf[0] != '?')
|
else if (buf.buf[0] != '?')
|
||||||
get_oid_hex(buf.buf, &(*tail)->old_oid);
|
get_oid_hex_algop(buf.buf, &(*tail)->old_oid, transport->hash_algo);
|
||||||
if (eon) {
|
if (eon) {
|
||||||
if (has_attribute(eon + 1, "unchanged")) {
|
if (has_attribute(eon + 1, "unchanged")) {
|
||||||
(*tail)->status |= REF_STATUS_UPTODATE;
|
(*tail)->status |= REF_STATUS_UPTODATE;
|
||||||
|
16
transport.c
16
transport.c
@ -143,6 +143,9 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
|
|||||||
data->fd = read_bundle_header(transport->url, &data->header);
|
data->fd = read_bundle_header(transport->url, &data->header);
|
||||||
if (data->fd < 0)
|
if (data->fd < 0)
|
||||||
die(_("could not read bundle '%s'"), transport->url);
|
die(_("could not read bundle '%s'"), transport->url);
|
||||||
|
|
||||||
|
transport->hash_algo = data->header.hash_algo;
|
||||||
|
|
||||||
for (i = 0; i < data->header.references.nr; i++) {
|
for (i = 0; i < data->header.references.nr; i++) {
|
||||||
struct ref_list_entry *e = data->header.references.list + i;
|
struct ref_list_entry *e = data->header.references.list + i;
|
||||||
struct ref *ref = alloc_ref(e->name);
|
struct ref *ref = alloc_ref(e->name);
|
||||||
@ -157,11 +160,14 @@ static int fetch_refs_from_bundle(struct transport *transport,
|
|||||||
int nr_heads, struct ref **to_fetch)
|
int nr_heads, struct ref **to_fetch)
|
||||||
{
|
{
|
||||||
struct bundle_transport_data *data = transport->data;
|
struct bundle_transport_data *data = transport->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!data->get_refs_from_bundle_called)
|
if (!data->get_refs_from_bundle_called)
|
||||||
get_refs_from_bundle(transport, 0, NULL);
|
get_refs_from_bundle(transport, 0, NULL);
|
||||||
return unbundle(the_repository, &data->header, data->fd,
|
ret = unbundle(the_repository, &data->header, data->fd,
|
||||||
transport->progress ? BUNDLE_VERBOSE : 0);
|
transport->progress ? BUNDLE_VERBOSE : 0);
|
||||||
|
transport->hash_algo = data->header.hash_algo;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int close_bundle(struct transport *transport)
|
static int close_bundle(struct transport *transport)
|
||||||
@ -312,6 +318,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
|
|||||||
BUG("unknown protocol version");
|
BUG("unknown protocol version");
|
||||||
}
|
}
|
||||||
data->got_remote_heads = 1;
|
data->got_remote_heads = 1;
|
||||||
|
transport->hash_algo = reader.hash_algo;
|
||||||
|
|
||||||
if (reader.line_peeked)
|
if (reader.line_peeked)
|
||||||
BUG("buffer must be empty at the end of handshake()");
|
BUG("buffer must be empty at the end of handshake()");
|
||||||
@ -989,9 +996,16 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
|||||||
ret->smart_options->receivepack = remote->receivepack;
|
ret->smart_options->receivepack = remote->receivepack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret->hash_algo = &hash_algos[GIT_HASH_SHA1];
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct git_hash_algo *transport_get_hash_algo(struct transport *transport)
|
||||||
|
{
|
||||||
|
return transport->hash_algo;
|
||||||
|
}
|
||||||
|
|
||||||
int transport_set_option(struct transport *transport,
|
int transport_set_option(struct transport *transport,
|
||||||
const char *name, const char *value)
|
const char *name, const char *value)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +115,8 @@ struct transport {
|
|||||||
struct git_transport_options *smart_options;
|
struct git_transport_options *smart_options;
|
||||||
|
|
||||||
enum transport_family family;
|
enum transport_family family;
|
||||||
|
|
||||||
|
const struct git_hash_algo *hash_algo;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TRANSPORT_PUSH_ALL (1<<0)
|
#define TRANSPORT_PUSH_ALL (1<<0)
|
||||||
@ -243,6 +245,12 @@ int transport_push(struct repository *repo,
|
|||||||
const struct ref *transport_get_remote_refs(struct transport *transport,
|
const struct ref *transport_get_remote_refs(struct transport *transport,
|
||||||
const struct argv_array *ref_prefixes);
|
const struct argv_array *ref_prefixes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the hash algorithm used by a remote.
|
||||||
|
*
|
||||||
|
* This can only be called after fetching the remote refs.
|
||||||
|
*/
|
||||||
|
const struct git_hash_algo *transport_get_hash_algo(struct transport *transport);
|
||||||
int transport_fetch_refs(struct transport *transport, struct ref *refs);
|
int transport_fetch_refs(struct transport *transport, struct ref *refs);
|
||||||
void transport_unlock_pack(struct transport *transport);
|
void transport_unlock_pack(struct transport *transport);
|
||||||
int transport_disconnect(struct transport *transport);
|
int transport_disconnect(struct transport *transport);
|
||||||
|
@ -1132,7 +1132,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
|
|||||||
struct strbuf symref_info = STRBUF_INIT;
|
struct strbuf symref_info = STRBUF_INIT;
|
||||||
|
|
||||||
format_symref_info(&symref_info, &data->symref);
|
format_symref_info(&symref_info, &data->symref);
|
||||||
packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s agent=%s\n",
|
packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s object-format=%s agent=%s\n",
|
||||||
oid_to_hex(oid), refname_nons,
|
oid_to_hex(oid), refname_nons,
|
||||||
0, capabilities,
|
0, capabilities,
|
||||||
(data->allow_uor & ALLOW_TIP_SHA1) ?
|
(data->allow_uor & ALLOW_TIP_SHA1) ?
|
||||||
@ -1142,6 +1142,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
|
|||||||
data->stateless_rpc ? " no-done" : "",
|
data->stateless_rpc ? " no-done" : "",
|
||||||
symref_info.buf,
|
symref_info.buf,
|
||||||
data->allow_filter ? " filter" : "",
|
data->allow_filter ? " filter" : "",
|
||||||
|
the_hash_algo->name,
|
||||||
git_user_agent_sanitized());
|
git_user_agent_sanitized());
|
||||||
strbuf_release(&symref_info);
|
strbuf_release(&symref_info);
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,6 +105,14 @@ char *xstrndup(const char *str, size_t len)
|
|||||||
return xmemdupz(str, p ? p - str : len);
|
return xmemdupz(str, p ? p - str : len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xstrncmpz(const char *s, const char *t, size_t len)
|
||||||
|
{
|
||||||
|
int res = strncmp(s, t, len);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
return s[len] == '\0' ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
void *xrealloc(void *ptr, size_t size)
|
void *xrealloc(void *ptr, size_t size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user