Re: [PATCH] Introduce git-mirror, a tool for exactly mirroring another repository.
- From
Junio C Hamano <junkio@cox.net>
- Date
- Sep 26, 2006, 04:45 UTC
- Message-ID
- <7vpsdjtew4.fsf@assigned-by-dhcp.cox.net>
- In-Reply-To
- <20060925044641.GB15757@spearce.org>
Shawn Pearce <spearce@spearce.org> writes:
Show 11 quoted lines
> Sometimes its handy to be able to efficiently backup or mirror one > Git repository to another Git repository by employing the native > Git object transfer protocol. But when mirroring or backing up a > repository you really want: > > 1) Every object in the source to go to the mirror. > 2) Every ref in the source to go to the mirror. > 3) Any ref removed from the source to be removed from the mirror. > 4) Automatically repack and prune the mirror when necessary. > > and since git-fetch doesn't do 2, 3, and 4 here's a tool that does.
Just a note. I usually use git-push the other way for backups, and I believe that is how Linus does it, too.
Show 7 quoted lines
> diff --git a/git-mirror.perl b/git-mirror.perl > new file mode 100755 > index 0000000..bff2003 > --- /dev/null > +++ b/git-mirror.perl > @@ -0,0 +1,111 @@ > +#!/usr/bin/env perl
Please don't. "#!/usr/bin/env perl" is a disease.
> +# This file is licensed under the GPL v2, or a later version > +# at the discretion of Linus.
Heh ;-).
Show 5 quoted lines
> +use warnings; > +use strict; > +use Git; > + > +sub ls_refs ($$);
I wonder why people like line-noise prototypes. Do you ever call ls_refs with parameters that benefit from this? Otherwise I prefer not to see them.
Show 7 quoted lines
> +my $remote = shift || 'origin';
> +my $repo = Git->repository();
> +
> +# Verify its OK to execute in this repository.
> +#
> +my $mirror_ok = $repo->config('mirror.allowed') || 0;
> +unless ($mirror_ok =~ /^(?:true|t|yes|y|1)$/i) {This _is_ ugly. Doesn't $repo->config() know how to drive underlying "git-repo-config" with specific type argument?
Show 11 quoted lines
> +# Delete any local refs which the server no longer contains.
> +#
> +foreach my $ref (keys %$local_refs) {
> + next if $remote_refs->{$ref};
> + print "removing $ref\n";
> + my $log = "logs/$ref";
> + unlink($repo->repo_path() . '/' . $ref);
> + unlink($repo->repo_path() . '/' . $log);
> + rmdir($repo->repo_path() . '/' . $ref) while $ref =~ s,/[^/]*$,,;
> + rmdir($repo->repo_path() . '/' . $log) while $log =~ s,/[^/]*$,,;
> +}If you do this upfront and then you lose connection while the real fetch, next fetch may need to take a lot longer than needed because it cannot rely on the refs you are losing here. Ref removal is rather a rare event, so we may not care too much about it, though.
> +# Execute the fetch for any refs which differ from our own. > +# We don't worry about trying to optimize for rewinds or > +# exact branch copies as they are rather uncommon.
If we need to support only git-native protocols, all of this optimization is not needed at all. It's kind of sad that we need to support commit walkers...
Show 7 quoted lines
> +if (@to_fetch) {
> + git_cmd_try {
> + $repo->command_noisy('fetch',
> + '--force',
> + '--update-head-ok',
> + $remote, sort @to_fetch);
> + } '%s failed w/ code %d';Why sort (no objection, just curious)?
Show 13 quoted lines
> +# Repack if we have a large number of loose objects.
> +#
> +if (@to_fetch) {
> + my $count_output = $repo->command('count-objects');
> + my ($cur_loose) = ($count_output =~ /^(\d+) objects/);
> + my $max_loose = $repo->config('mirror.maxlooseobjects') || 100;
> + if ($cur_loose >= $max_loose) {
> + git_cmd_try {
> + $repo->command_noisy('repack', '-a', '-d');
> + $repo->command_noisy('prune');
> + } '%s failed w/ code %d';
> + }
> +}If we truly have a large number of objects (in pack and loose), you do not want to do "repack -a -d", do you?