Merge branch 'ew/rerere' into next

* ew/rerere:
  rerere: record (or avoid misrecording) resolved, skipped or aborted rebase/am
  git-rerere: add 'gc' command.
  rerere: add clear, diff, and status commands
  Documentation: simpler shared repository creation
  shortlog: fix segfault on empty authorname
  Add branch.*.merge warning and documentation update
  Fix perl/ build.
  git-svn: use do_switch for --follow-parent if the SVN library supports it
  Fix documentation copy&paste typo
  git-svn: extra error check to ensure we open a file correctly
This commit is contained in:
Junio C Hamano
2006-12-09 12:25:51 -08:00
12 changed files with 187 additions and 28 deletions

View File

@@ -125,10 +125,17 @@ apply.whitespace::
branch.<name>.remote::
When in branch <name>, it tells `git fetch` which remote to fetch.
If this option is not given, `git fetch` defaults to remote "origin".
branch.<name>.merge::
When in branch <name>, it tells `git fetch` the default remote branch
to be merged.
When in branch <name>, it tells `git fetch` the default refspec to
be marked for merging in FETCH_HEAD. The value has exactly to match
a remote part of one of the refspecs which are fetched from the remote
given by "branch.<name>.remote".
The merge information is used by `git pull` (which at first calls
`git fetch`) to lookup the default branch for merging. Without
this option, `git pull` defaults to merge the first refspec fetched.
Specify multiple values to get an octopus merge.
pager.color::
A boolean to enable/disable colored output when the pager is in

View File

@@ -43,8 +43,8 @@ Pull: refs/heads/master:refs/remotes/origin/master
------------
================================
You can update the shared repository with your changes by first commiting
your changes, and then using:
You can update the shared repository with your changes by first committing
your changes, and then using the gitlink:git-push[1] command:
------------------------------------------------
$ git push origin master
@@ -76,11 +76,15 @@ possibly created from scratch or from a tarball (see the
link:tutorial.html[tutorial]), or imported from an already existing CVS
repository (see the next section).
If your project's working directory is /home/alice/myproject, you can
create a shared repository at /pub/repo.git with:
Assume your existing repo is at /home/alice/myproject. Create a new "bare"
repository (a repository without a working tree) and fetch your project into
it:
------------------------------------------------
$ git clone -bare /home/alice/myproject /pub/repo.git
$ mkdir /pub/my-repo.git
$ cd /pub/my-repo.git
$ git --bare init-db --shared
$ git --bare fetch /home/alice/myproject master:master
------------------------------------------------
Next, give every team member read/write access to this repository. One
@@ -93,10 +97,7 @@ Put all the committers in the same group, and make the repository
writable by that group:
------------------------------------------------
$ cd /pub
$ chgrp -R $group repo.git
$ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
$ GIT_DIR=repo.git git repo-config core.sharedrepository true
$ chgrp -R $group /pub/my-repo.git
------------------------------------------------
Make sure committers have a umask of at most 027, so that the directories
@@ -107,15 +108,15 @@ Importing a CVS archive
First, install version 2.1 or higher of cvsps from
link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
sure it is in your path. The magic command line is then
sure it is in your path. Then cd to a checked out CVS working directory
of the project you are interested in and run gitlink:git-cvsimport[1]:
-------------------------------------------
$ git cvsimport -v -d <cvsroot> -C <destination> <module>
$ git cvsimport -C <destination>
-------------------------------------------
This puts a git archive of the named CVS module in the directory
<destination>, which will be created if necessary. The -v option makes
the conversion script very chatty.
<destination>, which will be created if necessary.
The import checks out from CVS every revision of every file. Reportedly
cvsimport can average some twenty revisions per second, so for a

View File

@@ -7,8 +7,7 @@ git-rerere - Reuse recorded resolve
SYNOPSIS
--------
'git-rerere'
'git-rerere' [clear|diff|status]
DESCRIPTION
-----------
@@ -27,6 +26,38 @@ results and applying the previously recorded hand resolution.
You need to create `$GIT_DIR/rr-cache` directory to enable this
command.
COMMANDS
--------
Normally, git-rerere is run without arguments or user-intervention.
However, it has several commands that allow it to interact with
its working state.
'clear'::
This resets the metadata used by rerere if a merge resolution is to be
is aborted. Calling gitlink:git-am[1] --skip or gitlink:git-rebase[1]
[--skip|--abort] will automatcally invoke this command.
'diff'::
This displays diffs for the current state of the resolution. It is
useful for tracking what has changed while the user is resolving
conflicts. Additional arguments are passed directly to the system
diff(1) command installed in PATH.
'status'::
Like diff, but this only prints the filenames that will be tracked
for resolutions.
'gc'::
This command is used to prune records of conflicted merge that
occurred long time ago.
DISCUSSION
----------

View File

@@ -188,7 +188,7 @@ static void read_from_stdin(struct path_list *list)
bob = buffer + strlen(buffer);
else {
offset = 8;
while (isspace(bob[-1]))
if (isspace(bob[-1]))
bob--;
}
@@ -236,7 +236,7 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
author = scratch;
authorlen = strlen(scratch);
} else {
while (bracket[-1] == ' ')
if (bracket[-1] == ' ')
bracket--;
author = buffer + 7;

View File

@@ -246,6 +246,10 @@ last=`cat "$dotest/last"`
this=`cat "$dotest/next"`
if test "$skip" = t
then
if test -d "$GIT_DIR/rr-cache"
then
git-rerere clear
fi
this=`expr "$this" + 1`
resume=
fi
@@ -408,6 +412,10 @@ do
stop_here_user_resolve $this
fi
apply_status=0
if test -d "$GIT_DIR/rr-cache"
then
git rerere
fi
;;
esac

View File

@@ -134,6 +134,8 @@ canon_refs_list_for_fetch () {
# or the first one otherwise; add prefix . to the rest
# to prevent the secondary branches to be merged by default.
merge_branches=
found_mergeref=
curr_branch=
if test "$1" = "-d"
then
shift ; remote="$1" ; shift
@@ -171,6 +173,10 @@ canon_refs_list_for_fetch () {
dot_prefix= && break
done
fi
if test -z $dot_prefix
then
found_mergeref=true
fi
case "$remote" in
'') remote=HEAD ;;
refs/heads/* | refs/tags/* | refs/remotes/*) ;;
@@ -191,6 +197,11 @@ canon_refs_list_for_fetch () {
fi
echo "${dot_prefix}${force}${remote}:${local}"
done
if test -z "$found_mergeref" -a "$curr_branch"
then
echo >&2 "Warning: No merge candidate found because value of config option
\"branch.${curr_branch}.merge\" does not match any remote branch fetched."
fi
}
# Returns list of src: (no store), or src:dst (store)

View File

@@ -139,6 +139,10 @@ do
--skip)
if test -d "$dotest"
then
if test -d "$GIT_DIR/rr-cache"
then
git-rerere clear
fi
prev_head="`cat $dotest/prev_head`"
end="`cat $dotest/end`"
msgnum="`cat $dotest/msgnum`"
@@ -157,6 +161,10 @@ do
exit
;;
--abort)
if test -d "$GIT_DIR/rr-cache"
then
git-rerere clear
fi
if test -d "$dotest"
then
rm -r "$dotest"

View File

@@ -169,9 +169,66 @@ sub merge {
return 0;
}
sub garbage_collect_rerere {
# We should allow specifying these from the command line and
# that is why the caller gives @ARGV to us, but I am lazy.
my $cutoff_noresolve = 15; # two weeks
my $cutoff_resolve = 60; # two months
my @to_remove;
while (<$rr_dir/*/preimage>) {
my ($dir) = /^(.*)\/preimage$/;
my $cutoff = ((-f "$dir/postimage")
? $cutoff_resolve
: $cutoff_noresolve);
my $age = -M "$_";
if ($cutoff <= $age) {
push @to_remove, $dir;
}
}
if (@to_remove) {
rmtree(\@to_remove);
}
}
-d "$rr_dir" || exit(0);
read_rr();
if (@ARGV) {
my $arg = shift @ARGV;
if ($arg eq 'clear') {
for my $path (keys %merge_rr) {
my $name = $merge_rr{$path};
if (-d "$rr_dir/$name" &&
! -f "$rr_dir/$name/postimage") {
rmtree(["$rr_dir/$name"]);
}
}
unlink $merge_rr;
}
elsif ($arg eq 'status') {
for my $path (keys %merge_rr) {
print $path, "\n";
}
}
elsif ($arg eq 'diff') {
for my $path (keys %merge_rr) {
my $name = $merge_rr{$path};
system('diff', ((@ARGV == 0) ? ('-u') : @ARGV),
'-L', "a/$path", '-L', "b/$path",
"$rr_dir/$name/preimage", $path);
}
}
elsif ($arg eq 'gc') {
garbage_collect_rerere(@ARGV);
}
else {
die "$0 unknown command: $arg\n";
}
exit 0;
}
my %conflict = map { $_ => 1 } find_conflict();
# MERGE_RR records paths with conflicts immediately after merge

View File

@@ -72,7 +72,7 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
$_username, $_config_dir, $_no_auth_cache, $_xfer_delta,
$_pager, $_color);
my (@_branch_from, %tree_map, %users, %rusers, %equiv);
my ($_svn_co_url_revs, $_svn_pg_peg_revs);
my ($_svn_co_url_revs, $_svn_pg_peg_revs, $_svn_can_do_switch);
my @repo_path_split_cache;
my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
@@ -2877,6 +2877,24 @@ sub libsvn_connect {
return $ra;
}
sub libsvn_can_do_switch {
unless (defined $_svn_can_do_switch) {
my $pool = SVN::Pool->new;
my $rep = eval {
$SVN->do_switch(1, '', 0, $SVN->{url},
SVN::Delta::Editor->new, $pool);
};
if ($@) {
$_svn_can_do_switch = 0;
} else {
$rep->abort_report($pool);
$_svn_can_do_switch = 1;
}
$pool->clear;
}
$_svn_can_do_switch;
}
sub libsvn_dup_ra {
my ($ra) = @_;
SVN::Ra->new(map { $_ => $ra->{$_} } qw/config url
@@ -3198,12 +3216,26 @@ sub libsvn_find_parent_branch {
unlink $GIT_SVN_INDEX;
print STDERR "Found branch parent: ($GIT_SVN) $parent\n";
sys(qw/git-read-tree/, $parent);
# I can't seem to get do_switch() to work correctly with
# the SWIG interface (TypeError when passing switch_url...),
# so we'll unconditionally bypass the delta interface here
# for now
return libsvn_fetch_full($parent, $paths, $rev,
$author, $date, $msg);
unless (libsvn_can_do_switch()) {
return libsvn_fetch_full($parent, $paths, $rev,
$author, $date, $msg);
}
# do_switch works with svn/trunk >= r22312, but that is not
# included with SVN 1.4.2 (the latest version at the moment),
# so we can't rely on it.
my $ra = libsvn_connect("$url/$branch_from");
my $ed = SVN::Git::Fetcher->new({c => $parent, q => $_q});
my $pool = SVN::Pool->new;
my $reporter = $ra->do_switch($rev, '', 1, $SVN->{url},
$ed, $pool);
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
$reporter->set_path('', $r0, 0, @lock, $pool);
$reporter->finish_report($pool);
$pool->clear;
unless ($ed->{git_commit_ok}) {
die "SVN connection failed somewhere...\n";
}
return libsvn_log_entry($rev, $author, $date, $msg, [$parent]);
}
print STDERR "Nope, branch point not imported or unknown\n";
return undef;
@@ -3438,6 +3470,9 @@ sub open_file {
my ($self, $path, $pb, $rev) = @_;
my ($mode, $blob) = (safe_qx('git-ls-tree',$self->{c},'--',$path)
=~ /^(\d{6}) blob ([a-f\d]{40})\t/);
unless (defined $mode && defined $blob) {
die "$path was not found in commit $self->{c} (r$rev)\n";
}
{ path => $path, mode_a => $mode, mode_b => $mode, blob => $blob,
pool => SVN::Pool->new, action => 'M' };
}

View File

@@ -120,7 +120,7 @@ our %feature = (
# To disable system wide have in $GITWEB_CONFIG
# $feature{'snapshot'}{'default'} = [undef];
# To have project specific config enable override in $GITWEB_CONFIG
# $feature{'blame'}{'override'} = 1;
# $feature{'snapshot'}{'override'} = 1;
# and in project config gitweb.snapshot = none|gzip|bzip2;
'snapshot' => {
'sub' => \&feature_snapshot,

View File

@@ -29,7 +29,7 @@ $(makfile): ../GIT-CFLAGS Makefile
echo ' echo $(instdir_SQ)' >> $@
else
$(makfile): Makefile.PL ../GIT-CFLAGS
'$(PERL_PATH_SQ)' $< FIRST_MAKEFILE='$@' PREFIX='$(prefix_SQ)'
'$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)'
endif
# this is just added comfort for calling make directly in perl dir

View File

@@ -24,5 +24,6 @@ WriteMakefile(
NAME => 'Git',
VERSION_FROM => 'Git.pm',
PM => \%pm,
MAKEFILE => 'perl.mak',
%extra
);