Merge branch 'mk/unpack-careful'
* mk/unpack-careful: t5300: add test for "index-pack --strict" receive-pack: allow using --strict mode for unpacking objects unpack-objects: fix --strict handling t5300: add test for "unpack-objects --strict" unpack-objects: prevent writing of inconsistent objects
This commit is contained in:
commit
3c993de9f2
@ -991,6 +991,12 @@ imap::
|
|||||||
The configuration variables in the 'imap' section are described
|
The configuration variables in the 'imap' section are described
|
||||||
in linkgit:git-imap-send[1].
|
in linkgit:git-imap-send[1].
|
||||||
|
|
||||||
|
receive.fsckObjects::
|
||||||
|
If it is set to true, git-receive-pack will check all received
|
||||||
|
objects. It will abort in the case of a malformed object or a
|
||||||
|
broken link. The result of an abort are only dangling objects.
|
||||||
|
Defaults to false.
|
||||||
|
|
||||||
receive.unpackLimit::
|
receive.unpackLimit::
|
||||||
If the number of objects received in a push is below this
|
If the number of objects received in a push is below this
|
||||||
limit then the objects will be unpacked into loose object
|
limit then the objects will be unpacked into loose object
|
||||||
|
@ -40,6 +40,9 @@ OPTIONS
|
|||||||
and make the best effort to recover as many objects as
|
and make the best effort to recover as many objects as
|
||||||
possible.
|
possible.
|
||||||
|
|
||||||
|
--strict::
|
||||||
|
Don't write objects with broken content or links.
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -7,11 +7,13 @@
|
|||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "tree-walk.h"
|
||||||
#include "progress.h"
|
#include "progress.h"
|
||||||
#include "decorate.h"
|
#include "decorate.h"
|
||||||
|
#include "fsck.h"
|
||||||
|
|
||||||
static int dry_run, quiet, recover, has_errors;
|
static int dry_run, quiet, recover, has_errors, strict;
|
||||||
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
|
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
|
||||||
|
|
||||||
/* We always read in 4kB chunks. */
|
/* We always read in 4kB chunks. */
|
||||||
static unsigned char buffer[4096];
|
static unsigned char buffer[4096];
|
||||||
@ -19,6 +21,11 @@ static unsigned int offset, len;
|
|||||||
static off_t consumed_bytes;
|
static off_t consumed_bytes;
|
||||||
static SHA_CTX ctx;
|
static SHA_CTX ctx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When running under --strict mode, objects whose reachability are
|
||||||
|
* suspect are kept in core without getting written in the object
|
||||||
|
* store.
|
||||||
|
*/
|
||||||
struct obj_buffer {
|
struct obj_buffer {
|
||||||
char *buffer;
|
char *buffer;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
@ -31,6 +38,16 @@ static struct obj_buffer *lookup_object_buffer(struct object *base)
|
|||||||
return lookup_decoration(&obj_decorate, base);
|
return lookup_decoration(&obj_decorate, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
|
||||||
|
{
|
||||||
|
struct obj_buffer *obj;
|
||||||
|
obj = xcalloc(1, sizeof(struct obj_buffer));
|
||||||
|
obj->buffer = buffer;
|
||||||
|
obj->size = size;
|
||||||
|
if (add_decoration(&obj_decorate, object, obj))
|
||||||
|
die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure at least "min" bytes are available in the buffer, and
|
* Make sure at least "min" bytes are available in the buffer, and
|
||||||
* return the pointer to the buffer.
|
* return the pointer to the buffer.
|
||||||
@ -134,19 +151,110 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
|
|||||||
struct obj_info {
|
struct obj_info {
|
||||||
off_t offset;
|
off_t offset;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
struct object *obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FLAG_OPEN (1u<<20)
|
||||||
|
#define FLAG_WRITTEN (1u<<21)
|
||||||
|
|
||||||
static struct obj_info *obj_list;
|
static struct obj_info *obj_list;
|
||||||
|
unsigned nr_objects;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called only from check_object() after it verified this object
|
||||||
|
* is Ok.
|
||||||
|
*/
|
||||||
|
static void write_cached_object(struct object *obj)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
||||||
|
if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
|
||||||
|
die("failed to write object %s", sha1_to_hex(obj->sha1));
|
||||||
|
obj->flags |= FLAG_WRITTEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the very end of the processing, write_rest() scans the objects
|
||||||
|
* that have reachability requirements and calls this function.
|
||||||
|
* Verify its reachability and validity recursively and write it out.
|
||||||
|
*/
|
||||||
|
static int check_object(struct object *obj, int type, void *data)
|
||||||
|
{
|
||||||
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (obj->flags & FLAG_WRITTEN)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (type != OBJ_ANY && obj->type != type)
|
||||||
|
die("object type mismatch");
|
||||||
|
|
||||||
|
if (!(obj->flags & FLAG_OPEN)) {
|
||||||
|
unsigned long size;
|
||||||
|
int type = sha1_object_info(obj->sha1, &size);
|
||||||
|
if (type != obj->type || type <= 0)
|
||||||
|
die("object of unexpected type");
|
||||||
|
obj->flags |= FLAG_WRITTEN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsck_object(obj, 1, fsck_error_function))
|
||||||
|
die("Error in object");
|
||||||
|
if (!fsck_walk(obj, check_object, 0))
|
||||||
|
die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
|
||||||
|
write_cached_object(obj);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_rest(void)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < nr_objects; i++)
|
||||||
|
check_object(obj_list[i].obj, OBJ_ANY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void added_object(unsigned nr, enum object_type type,
|
static void added_object(unsigned nr, enum object_type type,
|
||||||
void *data, unsigned long size);
|
void *data, unsigned long size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out nr-th object from the list, now we know the contents
|
||||||
|
* of it. Under --strict, this buffers structured objects in-core,
|
||||||
|
* to be checked at the end.
|
||||||
|
*/
|
||||||
static void write_object(unsigned nr, enum object_type type,
|
static void write_object(unsigned nr, enum object_type type,
|
||||||
void *buf, unsigned long size)
|
void *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
if (!strict) {
|
||||||
die("failed to write object");
|
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||||
added_object(nr, type, buf, size);
|
die("failed to write object");
|
||||||
|
added_object(nr, type, buf, size);
|
||||||
|
free(buf);
|
||||||
|
obj_list[nr].obj = NULL;
|
||||||
|
} else if (type == OBJ_BLOB) {
|
||||||
|
struct blob *blob;
|
||||||
|
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||||
|
die("failed to write object");
|
||||||
|
added_object(nr, type, buf, size);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
blob = lookup_blob(obj_list[nr].sha1);
|
||||||
|
if (blob)
|
||||||
|
blob->object.flags |= FLAG_WRITTEN;
|
||||||
|
else
|
||||||
|
die("invalid blob object");
|
||||||
|
obj_list[nr].obj = NULL;
|
||||||
|
} else {
|
||||||
|
struct object *obj;
|
||||||
|
int eaten;
|
||||||
|
hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
|
||||||
|
added_object(nr, type, buf, size);
|
||||||
|
obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
|
||||||
|
if (!obj)
|
||||||
|
die("invalid %s", typename(type));
|
||||||
|
add_object_buffer(obj, buf, size);
|
||||||
|
obj->flags |= FLAG_OPEN;
|
||||||
|
obj_list[nr].obj = obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolve_delta(unsigned nr, enum object_type type,
|
static void resolve_delta(unsigned nr, enum object_type type,
|
||||||
@ -163,9 +271,12 @@ static void resolve_delta(unsigned nr, enum object_type type,
|
|||||||
die("failed to apply delta");
|
die("failed to apply delta");
|
||||||
free(delta);
|
free(delta);
|
||||||
write_object(nr, type, result, result_size);
|
write_object(nr, type, result, result_size);
|
||||||
free(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We now know the contents of an object (which is nr-th in the pack);
|
||||||
|
* resolve all the deltified objects that are based on it.
|
||||||
|
*/
|
||||||
static void added_object(unsigned nr, enum object_type type,
|
static void added_object(unsigned nr, enum object_type type,
|
||||||
void *data, unsigned long size)
|
void *data, unsigned long size)
|
||||||
{
|
{
|
||||||
@ -193,7 +304,24 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
|
|||||||
|
|
||||||
if (!dry_run && buf)
|
if (!dry_run && buf)
|
||||||
write_object(nr, type, buf, size);
|
write_object(nr, type, buf, size);
|
||||||
free(buf);
|
else
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resolve_against_held(unsigned nr, const unsigned char *base,
|
||||||
|
void *delta_data, unsigned long delta_size)
|
||||||
|
{
|
||||||
|
struct object *obj;
|
||||||
|
struct obj_buffer *obj_buffer;
|
||||||
|
obj = lookup_object(base);
|
||||||
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
obj_buffer = lookup_object_buffer(obj);
|
||||||
|
if (!obj_buffer)
|
||||||
|
return 0;
|
||||||
|
resolve_delta(nr, obj->type, obj_buffer->buffer,
|
||||||
|
obj_buffer->size, delta_data, delta_size);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||||
@ -202,7 +330,6 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||||||
void *delta_data, *base;
|
void *delta_data, *base;
|
||||||
unsigned long base_size;
|
unsigned long base_size;
|
||||||
unsigned char base_sha1[20];
|
unsigned char base_sha1[20];
|
||||||
struct object *obj;
|
|
||||||
|
|
||||||
if (type == OBJ_REF_DELTA) {
|
if (type == OBJ_REF_DELTA) {
|
||||||
hashcpy(base_sha1, fill(20));
|
hashcpy(base_sha1, fill(20));
|
||||||
@ -212,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||||||
free(delta_data);
|
free(delta_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!has_sha1_file(base_sha1)) {
|
if (has_sha1_file(base_sha1))
|
||||||
|
; /* Ok we have this one */
|
||||||
|
else if (resolve_against_held(nr, base_sha1,
|
||||||
|
delta_data, delta_size))
|
||||||
|
return; /* we are done */
|
||||||
|
else {
|
||||||
|
/* cannot resolve yet --- queue it */
|
||||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||||
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
|
add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
|
||||||
return;
|
return;
|
||||||
@ -258,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!base_found) {
|
if (!base_found) {
|
||||||
/* The delta base object is itself a delta that
|
/*
|
||||||
has not been resolved yet. */
|
* The delta base object is itself a delta that
|
||||||
|
* has not been resolved yet.
|
||||||
|
*/
|
||||||
hashcpy(obj_list[nr].sha1, null_sha1);
|
hashcpy(obj_list[nr].sha1, null_sha1);
|
||||||
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
|
add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = lookup_object(base_sha1);
|
if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
|
||||||
if (obj) {
|
return;
|
||||||
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
|
||||||
if (obj_buf) {
|
|
||||||
resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base = read_sha1_file(base_sha1, &type, &base_size);
|
base = read_sha1_file(base_sha1, &type, &base_size);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
@ -336,7 +465,8 @@ static void unpack_all(void)
|
|||||||
int i;
|
int i;
|
||||||
struct progress *progress = NULL;
|
struct progress *progress = NULL;
|
||||||
struct pack_header *hdr = fill(sizeof(struct pack_header));
|
struct pack_header *hdr = fill(sizeof(struct pack_header));
|
||||||
unsigned nr_objects = ntohl(hdr->hdr_entries);
|
|
||||||
|
nr_objects = ntohl(hdr->hdr_entries);
|
||||||
|
|
||||||
if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
|
if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
|
||||||
die("bad pack file");
|
die("bad pack file");
|
||||||
@ -347,6 +477,7 @@ static void unpack_all(void)
|
|||||||
if (!quiet)
|
if (!quiet)
|
||||||
progress = start_progress("Unpacking objects", nr_objects);
|
progress = start_progress("Unpacking objects", nr_objects);
|
||||||
obj_list = xmalloc(nr_objects * sizeof(*obj_list));
|
obj_list = xmalloc(nr_objects * sizeof(*obj_list));
|
||||||
|
memset(obj_list, 0, nr_objects * sizeof(*obj_list));
|
||||||
for (i = 0; i < nr_objects; i++) {
|
for (i = 0; i < nr_objects; i++) {
|
||||||
unpack_one(i);
|
unpack_one(i);
|
||||||
display_progress(progress, i + 1);
|
display_progress(progress, i + 1);
|
||||||
@ -382,6 +513,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
recover = 1;
|
recover = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--strict")) {
|
||||||
|
strict = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!prefixcmp(arg, "--pack_header=")) {
|
if (!prefixcmp(arg, "--pack_header=")) {
|
||||||
struct pack_header *hdr;
|
struct pack_header *hdr;
|
||||||
char *c;
|
char *c;
|
||||||
@ -407,6 +542,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
unpack_all();
|
unpack_all();
|
||||||
SHA1_Update(&ctx, buffer, offset);
|
SHA1_Update(&ctx, buffer, offset);
|
||||||
SHA1_Final(sha1, &ctx);
|
SHA1_Final(sha1, &ctx);
|
||||||
|
if (strict)
|
||||||
|
write_rest();
|
||||||
if (hashcmp(fill(20), sha1))
|
if (hashcmp(fill(20), sha1))
|
||||||
die("final sha1 did not match");
|
die("final sha1 did not match");
|
||||||
use(20);
|
use(20);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||||
|
|
||||||
static int deny_non_fast_forwards = 0;
|
static int deny_non_fast_forwards = 0;
|
||||||
|
static int receive_fsck_objects;
|
||||||
static int receive_unpack_limit = -1;
|
static int receive_unpack_limit = -1;
|
||||||
static int transfer_unpack_limit = -1;
|
static int transfer_unpack_limit = -1;
|
||||||
static int unpack_limit = 100;
|
static int unpack_limit = 100;
|
||||||
@ -35,6 +36,11 @@ static int receive_pack_config(const char *var, const char *value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(var, "receive.fsckobjects") == 0) {
|
||||||
|
receive_fsck_objects = git_config_bool(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return git_default_config(var, value);
|
return git_default_config(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,11 +374,13 @@ static const char *unpack(void)
|
|||||||
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
|
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
|
||||||
|
|
||||||
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
||||||
int code;
|
int code, i = 0;
|
||||||
const char *unpacker[3];
|
const char *unpacker[4];
|
||||||
unpacker[0] = "unpack-objects";
|
unpacker[i++] = "unpack-objects";
|
||||||
unpacker[1] = hdr_arg;
|
if (receive_fsck_objects)
|
||||||
unpacker[2] = NULL;
|
unpacker[i++] = "--strict";
|
||||||
|
unpacker[i++] = hdr_arg;
|
||||||
|
unpacker[i++] = NULL;
|
||||||
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
|
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -393,8 +401,8 @@ static const char *unpack(void)
|
|||||||
return "unpacker exited with error code";
|
return "unpacker exited with error code";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char *keeper[6];
|
const char *keeper[7];
|
||||||
int s, status;
|
int s, status, i = 0;
|
||||||
char keep_arg[256];
|
char keep_arg[256];
|
||||||
struct child_process ip;
|
struct child_process ip;
|
||||||
|
|
||||||
@ -402,12 +410,14 @@ static const char *unpack(void)
|
|||||||
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
||||||
strcpy(keep_arg + s, "localhost");
|
strcpy(keep_arg + s, "localhost");
|
||||||
|
|
||||||
keeper[0] = "index-pack";
|
keeper[i++] = "index-pack";
|
||||||
keeper[1] = "--stdin";
|
keeper[i++] = "--stdin";
|
||||||
keeper[2] = "--fix-thin";
|
if (receive_fsck_objects)
|
||||||
keeper[3] = hdr_arg;
|
keeper[i++] = "--strict";
|
||||||
keeper[4] = keep_arg;
|
keeper[i++] = "--fix-thin";
|
||||||
keeper[5] = NULL;
|
keeper[i++] = hdr_arg;
|
||||||
|
keeper[i++] = keep_arg;
|
||||||
|
keeper[i++] = NULL;
|
||||||
memset(&ip, 0, sizeof(ip));
|
memset(&ip, 0, sizeof(ip));
|
||||||
ip.argv = keeper;
|
ip.argv = keeper;
|
||||||
ip.out = -1;
|
ip.out = -1;
|
||||||
|
@ -274,4 +274,99 @@ test_expect_success \
|
|||||||
packname_4=$(git pack-objects test-4 <obj-list) &&
|
packname_4=$(git pack-objects test-4 <obj-list) &&
|
||||||
test 3 = $(ls test-4-*.pack | wc -l)'
|
test 3 = $(ls test-4-*.pack | wc -l)'
|
||||||
|
|
||||||
|
test_expect_success 'unpacking with --strict' '
|
||||||
|
|
||||||
|
git config --unset pack.packsizelimit &&
|
||||||
|
for j in a b c d e f g
|
||||||
|
do
|
||||||
|
for i in 0 1 2 3 4 5 6 7 8 9
|
||||||
|
do
|
||||||
|
o=$(echo $j$i | git hash-object -w --stdin) &&
|
||||||
|
echo "100644 $o 0 $j$i"
|
||||||
|
done
|
||||||
|
done >LIST &&
|
||||||
|
rm -f .git/index &&
|
||||||
|
git update-index --index-info <LIST &&
|
||||||
|
LIST=$(git write-tree) &&
|
||||||
|
rm -f .git/index &&
|
||||||
|
head -n 10 LIST | git update-index --index-info &&
|
||||||
|
LI=$(git write-tree) &&
|
||||||
|
rm -f .git/index &&
|
||||||
|
tail -n 10 LIST | git update-index --index-info &&
|
||||||
|
ST=$(git write-tree) &&
|
||||||
|
PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
|
||||||
|
git pack-objects test-5 ) &&
|
||||||
|
PACK6=$( (
|
||||||
|
echo "$LIST"
|
||||||
|
echo "$LI"
|
||||||
|
echo "$ST"
|
||||||
|
) | git pack-objects test-6 ) &&
|
||||||
|
test_create_repo test-5 &&
|
||||||
|
(
|
||||||
|
cd test-5 &&
|
||||||
|
git unpack-objects --strict <../test-5-$PACK5.pack &&
|
||||||
|
git ls-tree -r $LIST &&
|
||||||
|
git ls-tree -r $LI &&
|
||||||
|
git ls-tree -r $ST
|
||||||
|
) &&
|
||||||
|
test_create_repo test-6 &&
|
||||||
|
(
|
||||||
|
# tree-only into empty repo -- many unreachables
|
||||||
|
cd test-6 &&
|
||||||
|
test_must_fail git unpack-objects --strict <../test-6-$PACK6.pack
|
||||||
|
) &&
|
||||||
|
(
|
||||||
|
# already populated -- no unreachables
|
||||||
|
cd test-5 &&
|
||||||
|
git unpack-objects --strict <../test-6-$PACK6.pack
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'index-pack with --strict' '
|
||||||
|
|
||||||
|
for j in a b c d e f g
|
||||||
|
do
|
||||||
|
for i in 0 1 2 3 4 5 6 7 8 9
|
||||||
|
do
|
||||||
|
o=$(echo $j$i | git hash-object -w --stdin) &&
|
||||||
|
echo "100644 $o 0 $j$i"
|
||||||
|
done
|
||||||
|
done >LIST &&
|
||||||
|
rm -f .git/index &&
|
||||||
|
git update-index --index-info <LIST &&
|
||||||
|
LIST=$(git write-tree) &&
|
||||||
|
rm -f .git/index &&
|
||||||
|
head -n 10 LIST | git update-index --index-info &&
|
||||||
|
LI=$(git write-tree) &&
|
||||||
|
rm -f .git/index &&
|
||||||
|
tail -n 10 LIST | git update-index --index-info &&
|
||||||
|
ST=$(git write-tree) &&
|
||||||
|
PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
|
||||||
|
git pack-objects test-5 ) &&
|
||||||
|
PACK6=$( (
|
||||||
|
echo "$LIST"
|
||||||
|
echo "$LI"
|
||||||
|
echo "$ST"
|
||||||
|
) | git pack-objects test-6 ) &&
|
||||||
|
test_create_repo test-7 &&
|
||||||
|
(
|
||||||
|
cd test-7 &&
|
||||||
|
git index-pack --strict --stdin <../test-5-$PACK5.pack &&
|
||||||
|
git ls-tree -r $LIST &&
|
||||||
|
git ls-tree -r $LI &&
|
||||||
|
git ls-tree -r $ST
|
||||||
|
) &&
|
||||||
|
test_create_repo test-8 &&
|
||||||
|
(
|
||||||
|
# tree-only into empty repo -- many unreachables
|
||||||
|
cd test-8 &&
|
||||||
|
test_must_fail git index-pack --strict --stdin <../test-6-$PACK6.pack
|
||||||
|
) &&
|
||||||
|
(
|
||||||
|
# already populated -- no unreachables
|
||||||
|
cd test-7 &&
|
||||||
|
git index-pack --strict --stdin <../test-6-$PACK6.pack
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user