send-pack: generate packfiles via the object database
When pushing, git-send-pack(1) spawns git-pack-objects(1) directly to
generate the packfile that gets sent to the remote. Same as with
git-upload-pack(1), which has been adapted in the preceding commit,
this hard-codes the assumption that objects can be packed via
git-pack-objects(1), which is specific to the "files" backend.
Convert git-send-pack(1) to use the pack generation interface of the
object database instead.
Note that this requires us to adapt t5516 because the parameters passed
to git-pack-objects(1) are changing:
- The order of arguments changes.
- We pass "--quiet" instead of "-q".
- We don't pass "--all-progress-implied" anymore when not generating
output.
All of these changes are benign though and should not result in a change
in behaviour.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
parent
f0de4ab248
commit
7d2289a23d
101
send-pack.c
101
send-pack.c
|
|
@ -42,16 +42,17 @@ int option_parse_push_signed(const struct option *opt,
|
|||
die("bad %s argument: %s", opt->long_name, arg);
|
||||
}
|
||||
|
||||
static void feed_object(struct repository *r,
|
||||
const struct object_id *oid, FILE *fh, int negative)
|
||||
static void append_negative_object(struct repository *r,
|
||||
struct oid_array *haves,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
if (negative && !odb_has_object(r->objects, oid, 0))
|
||||
/*
|
||||
* The remote end may have advertised objects that we do not have in
|
||||
* our object database. Skip those, as we cannot use them as boundary.
|
||||
*/
|
||||
if (!odb_has_object(r->objects, oid, 0))
|
||||
return;
|
||||
|
||||
if (negative)
|
||||
putc('^', fh);
|
||||
fputs(oid_to_hex(oid), fh);
|
||||
putc('\n', fh);
|
||||
oid_array_append(haves, oid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -62,92 +63,58 @@ static int pack_objects(struct repository *r,
|
|||
struct oid_array *negotiated,
|
||||
struct send_pack_args *args)
|
||||
{
|
||||
/*
|
||||
* The child becomes pack-objects --revs; we feed
|
||||
* the revision parameters to it via its stdin and
|
||||
* let its stdout go back to the other end.
|
||||
*/
|
||||
struct child_process po = CHILD_PROCESS_INIT;
|
||||
FILE *po_in;
|
||||
struct odb_generate_pack_options opts = ODB_GENERATE_PACK_OPTIONS_INIT;
|
||||
struct odb_pack_generator *generator;
|
||||
int rc;
|
||||
|
||||
trace2_region_enter("send_pack", "pack_objects", r);
|
||||
strvec_push(&po.args, "pack-objects");
|
||||
strvec_push(&po.args, "--all-progress-implied");
|
||||
strvec_push(&po.args, "--revs");
|
||||
strvec_push(&po.args, "--stdout");
|
||||
if (args->use_thin_pack)
|
||||
strvec_push(&po.args, "--thin");
|
||||
if (args->use_ofs_delta)
|
||||
strvec_push(&po.args, "--delta-base-offset");
|
||||
if (args->quiet || !args->progress)
|
||||
strvec_push(&po.args, "-q");
|
||||
|
||||
opts.thin = args->use_thin_pack;
|
||||
opts.ofs_delta = args->use_ofs_delta;
|
||||
if (args->progress)
|
||||
strvec_push(&po.args, "--progress");
|
||||
if (is_repository_shallow(r))
|
||||
strvec_push(&po.args, "--shallow");
|
||||
if (args->disable_bitmaps)
|
||||
strvec_push(&po.args, "--no-use-bitmap-index");
|
||||
po.in = -1;
|
||||
po.out = args->stateless_rpc ? -1 : fd;
|
||||
po.git_cmd = 1;
|
||||
po.clean_on_exit = 1;
|
||||
if (start_command(&po))
|
||||
die_errno("git pack-objects failed");
|
||||
opts.progress = ODB_GENERATE_PACK_PROGRESS_VERBOSE;
|
||||
opts.shallow = is_repository_shallow(r);
|
||||
opts.disable_bitmaps = args->disable_bitmaps;
|
||||
|
||||
/*
|
||||
* We feed the pack-objects we just spawned with revision
|
||||
* parameters by writing to the pipe.
|
||||
* The pack is either written directly to the remote's descriptor, or,
|
||||
* in the case of a stateless RPC, read back from a pipe so that we
|
||||
* can wrap the pack data into pkt-lines.
|
||||
*/
|
||||
po_in = xfdopen(po.in, "w");
|
||||
opts.pack_fd = args->stateless_rpc ? -1 : fd;
|
||||
|
||||
for (size_t i = 0; i < advertised->nr; i++)
|
||||
feed_object(r, &advertised->oid[i], po_in, 1);
|
||||
append_negative_object(r, &opts.haves, &advertised->oid[i]);
|
||||
for (size_t i = 0; i < negotiated->nr; i++)
|
||||
feed_object(r, &negotiated->oid[i], po_in, 1);
|
||||
append_negative_object(r, &opts.haves, &negotiated->oid[i]);
|
||||
|
||||
while (refs) {
|
||||
if (!is_null_oid(&refs->old_oid))
|
||||
feed_object(r, &refs->old_oid, po_in, 1);
|
||||
append_negative_object(r, &opts.haves, &refs->old_oid);
|
||||
if (!is_null_oid(&refs->new_oid))
|
||||
feed_object(r, &refs->new_oid, po_in, 0);
|
||||
oid_array_append(&opts.wants, &refs->new_oid);
|
||||
refs = refs->next;
|
||||
}
|
||||
|
||||
fflush(po_in);
|
||||
if (ferror(po_in))
|
||||
die_errno("error writing to pack-objects");
|
||||
fclose(po_in);
|
||||
if (odb_generate_pack(r->objects, &generator, &opts))
|
||||
die("git pack-objects failed");
|
||||
odb_generate_pack_options_release(&opts);
|
||||
|
||||
if (args->stateless_rpc) {
|
||||
char *buf = xmalloc(LARGE_PACKET_MAX);
|
||||
while (1) {
|
||||
ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
|
||||
ssize_t n = xread(generator->out, buf, LARGE_PACKET_MAX);
|
||||
if (n <= 0)
|
||||
break;
|
||||
send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
|
||||
}
|
||||
free(buf);
|
||||
close(po.out);
|
||||
po.out = -1;
|
||||
close(generator->out);
|
||||
}
|
||||
|
||||
rc = finish_command(&po);
|
||||
if (rc) {
|
||||
/*
|
||||
* For a normal non-zero exit, we assume pack-objects wrote
|
||||
* something useful to stderr. For death by signal, though,
|
||||
* we should mention it to the user. The exception is SIGPIPE
|
||||
* (141), because that's a normal occurrence if the remote end
|
||||
* hangs up (and we'll report that by trying to read the unpack
|
||||
* status).
|
||||
*/
|
||||
if (rc > 128 && rc != 141)
|
||||
error("pack-objects died of signal %d", rc - 128);
|
||||
rc = odb_pack_generator_finish(generator);
|
||||
trace2_region_leave("send_pack", "pack_objects", r);
|
||||
return -1;
|
||||
}
|
||||
trace2_region_leave("send_pack", "pack_objects", r);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int receive_unpack_status(struct packet_reader *reader)
|
||||
|
|
@ -768,7 +735,7 @@ int send_pack(struct repository *r,
|
|||
goto out;
|
||||
}
|
||||
if (!args->stateless_rpc)
|
||||
/* Closed by pack_objects() via start_command() */
|
||||
/* Consumed by the pack generator in pack_objects() */
|
||||
fd[1] = -1;
|
||||
}
|
||||
if (args->stateless_rpc && cmds_sent)
|
||||
|
|
|
|||
|
|
@ -1903,20 +1903,20 @@ test_expect_success 'push with config push.useBitmaps' '
|
|||
test_unconfig push.useBitmaps &&
|
||||
GIT_TRACE2_EVENT="$PWD/default" \
|
||||
git push --quiet testrepo main:test &&
|
||||
test_subcommand git pack-objects --all-progress-implied --revs --stdout \
|
||||
--thin --delta-base-offset -q <default &&
|
||||
test_subcommand git pack-objects --revs --stdout --thin \
|
||||
--delta-base-offset --quiet <default &&
|
||||
|
||||
test_config push.useBitmaps true &&
|
||||
GIT_TRACE2_EVENT="$PWD/true" \
|
||||
git push --quiet testrepo main:test2 &&
|
||||
test_subcommand git pack-objects --all-progress-implied --revs --stdout \
|
||||
--thin --delta-base-offset -q <true &&
|
||||
test_subcommand git pack-objects --revs --stdout --thin \
|
||||
--delta-base-offset --quiet <true &&
|
||||
|
||||
test_config push.useBitmaps false &&
|
||||
GIT_TRACE2_EVENT="$PWD/false" \
|
||||
git push --quiet testrepo main:test3 &&
|
||||
test_subcommand git pack-objects --all-progress-implied --revs --stdout \
|
||||
--thin --delta-base-offset -q --no-use-bitmap-index <false
|
||||
test_subcommand git pack-objects --revs --stdout --thin \
|
||||
--delta-base-offset --no-use-bitmap-index --quiet <false
|
||||
'
|
||||
|
||||
test_expect_success 'push with config pack.usePathWalk=true' '
|
||||
|
|
|
|||
Loading…
Reference in New Issue