mirror of
https://github.com/git/git
synced 2024-10-30 14:03:28 +00:00
92251b1b5b
Fetching from a shallow-cloned repository used to be forbidden, primarily because the codepaths involved were not carefully vetted and we did not bother supporting such usage. This attempts to allow object transfer out of a shallow-cloned repository in a controlled way (i.e. the receiver become a shallow repository with truncated history). * nd/shallow-clone: (31 commits) t5537: fix incorrect expectation in test case 10 shallow: remove unused code send-pack.c: mark a file-local function static git-clone.txt: remove shallow clone limitations prune: clean .git/shallow after pruning objects clone: use git protocol for cloning shallow repo locally send-pack: support pushing from a shallow clone via http receive-pack: support pushing to a shallow clone via http smart-http: support shallow fetch/clone remote-curl: pass ref SHA-1 to fetch-pack as well send-pack: support pushing to a shallow clone receive-pack: allow pushes that update .git/shallow connected.c: add new variant that runs with --shallow-file add GIT_SHALLOW_FILE to propagate --shallow-file to subprocesses receive/send-pack: support pushing from a shallow clone receive-pack: reorder some code in unpack() fetch: add --update-shallow to accept refs that update .git/shallow upload-pack: make sure deepening preserves shallow roots fetch: support fetching from a shallow repository clone: support remote shallow repository ...
120 lines
3.3 KiB
C
120 lines
3.3 KiB
C
#include "cache.h"
|
|
#include "run-command.h"
|
|
#include "sigchain.h"
|
|
#include "connected.h"
|
|
#include "transport.h"
|
|
|
|
int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data)
|
|
{
|
|
return check_everything_connected_with_transport(fn, quiet, cb_data, NULL);
|
|
}
|
|
/*
|
|
* If we feed all the commits we want to verify to this command
|
|
*
|
|
* $ git rev-list --objects --stdin --not --all
|
|
*
|
|
* and if it does not error out, that means everything reachable from
|
|
* these commits locally exists and is connected to our existing refs.
|
|
* Note that this does _not_ validate the individual objects.
|
|
*
|
|
* Returns 0 if everything is connected, non-zero otherwise.
|
|
*/
|
|
static int check_everything_connected_real(sha1_iterate_fn fn,
|
|
int quiet,
|
|
void *cb_data,
|
|
struct transport *transport,
|
|
const char *shallow_file)
|
|
{
|
|
struct child_process rev_list;
|
|
const char *argv[9];
|
|
char commit[41];
|
|
unsigned char sha1[20];
|
|
int err = 0, ac = 0;
|
|
struct packed_git *new_pack = NULL;
|
|
|
|
if (fn(cb_data, sha1))
|
|
return err;
|
|
|
|
if (transport && transport->smart_options &&
|
|
transport->smart_options->self_contained_and_connected &&
|
|
transport->pack_lockfile &&
|
|
ends_with(transport->pack_lockfile, ".keep")) {
|
|
struct strbuf idx_file = STRBUF_INIT;
|
|
strbuf_addstr(&idx_file, transport->pack_lockfile);
|
|
strbuf_setlen(&idx_file, idx_file.len - 5); /* ".keep" */
|
|
strbuf_addstr(&idx_file, ".idx");
|
|
new_pack = add_packed_git(idx_file.buf, idx_file.len, 1);
|
|
strbuf_release(&idx_file);
|
|
}
|
|
|
|
if (shallow_file) {
|
|
argv[ac++] = "--shallow-file";
|
|
argv[ac++] = shallow_file;
|
|
}
|
|
argv[ac++] = "rev-list";
|
|
argv[ac++] = "--objects";
|
|
argv[ac++] = "--stdin";
|
|
argv[ac++] = "--not";
|
|
argv[ac++] = "--all";
|
|
if (quiet)
|
|
argv[ac++] = "--quiet";
|
|
argv[ac] = NULL;
|
|
|
|
memset(&rev_list, 0, sizeof(rev_list));
|
|
rev_list.argv = argv;
|
|
rev_list.git_cmd = 1;
|
|
rev_list.in = -1;
|
|
rev_list.no_stdout = 1;
|
|
rev_list.no_stderr = quiet;
|
|
if (start_command(&rev_list))
|
|
return error(_("Could not run 'git rev-list'"));
|
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
commit[40] = '\n';
|
|
do {
|
|
/*
|
|
* If index-pack already checked that:
|
|
* - there are no dangling pointers in the new pack
|
|
* - the pack is self contained
|
|
* Then if the updated ref is in the new pack, then we
|
|
* are sure the ref is good and not sending it to
|
|
* rev-list for verification.
|
|
*/
|
|
if (new_pack && find_pack_entry_one(sha1, new_pack))
|
|
continue;
|
|
|
|
memcpy(commit, sha1_to_hex(sha1), 40);
|
|
if (write_in_full(rev_list.in, commit, 41) < 0) {
|
|
if (errno != EPIPE && errno != EINVAL)
|
|
error(_("failed write to rev-list: %s"),
|
|
strerror(errno));
|
|
err = -1;
|
|
break;
|
|
}
|
|
} while (!fn(cb_data, sha1));
|
|
|
|
if (close(rev_list.in)) {
|
|
error(_("failed to close rev-list's stdin: %s"), strerror(errno));
|
|
err = -1;
|
|
}
|
|
|
|
sigchain_pop(SIGPIPE);
|
|
return finish_command(&rev_list) || err;
|
|
}
|
|
|
|
int check_everything_connected_with_transport(sha1_iterate_fn fn,
|
|
int quiet,
|
|
void *cb_data,
|
|
struct transport *transport)
|
|
{
|
|
return check_everything_connected_real(fn, quiet, cb_data,
|
|
transport, NULL);
|
|
}
|
|
|
|
int check_shallow_connected(sha1_iterate_fn fn, int quiet, void *cb_data,
|
|
const char *shallow_file)
|
|
{
|
|
return check_everything_connected_real(fn, quiet, cb_data,
|
|
NULL, shallow_file);
|
|
}
|