* git-core-0.99.9g: mailinfo.c:448: undefined reference to `libiconv_open'
From: Roberto Nibali @ 2005-11-12 10:27 UTC (permalink / raw)
To: git
Hello,
I've tried to compile git-core-0.99.9g on an old SuSE 9.1 box with a
self-compiled libiconv. Anyone can shed a light on the following?
gcc -o mailinfo.o -c -g -O2 -Wall -DSHA1_HEADER='<openssl/sha.h>' mailinfo.c
gcc -g -O2 -Wall -DSHA1_HEADER='<openssl/sha.h>' -o git-mailinfo
mailinfo.o libgit.a
mailinfo.o(.text+0x799): In function `convert_to_utf8':
/data/down/git-core-0.99.9g/mailinfo.c:448: undefined reference to
`libiconv_open'
mailinfo.o(.text+0x7f6):/data/down/git-core-0.99.9g/mailinfo.c:460:
undefined reference to `libiconv'
mailinfo.o(.text+0x801):/data/down/git-core-0.99.9g/mailinfo.c:461:
undefined reference to `libiconv_close'
collect2: ld returned 1 exit status
make: *** [git-mailinfo] Error 1
# nm /usr/local/lib/libiconv.so | grep -E "libiconv_open|libiconv_close"
0000f550 T libiconv_close
0000f580 T libiconv_open
I might be missing something really obvious. It's not very important;
just if you happen to know something regarding this issue I'd be interested.
Regards,
Roberto Nibali, ratz
--
echo
'[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq' | dc
^ permalink raw reply
* [PATCH 5/5] -D <depth> option to recurse into merged branches
From: Eric Wong @ 2005-11-12 9:32 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git list
In-Reply-To: <20051112093045.GE16218@Muzzle>
-D <depth> option to recurse into merged branches
-a auto-register Arch archive if it's on mirrors.sourcecontrol.net
fix for dealing with tag revisions
remove unused module loading (no more String::ShellQuote dep)
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-archimport.perl | 257 ++++++++++++++++++++++++++++-----------------------
1 files changed, 141 insertions(+), 116 deletions(-)
applies-to: d6d3e5272bc39ea086e5c1b0b39ceb5b51ade1ff
2fe160b44c5e5da1a139668767ba184b6b63f605
diff --git a/git-archimport.perl b/git-archimport.perl
index 5616d42..a0ea016 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -22,9 +22,10 @@ See man (1) git-archimport for more deta
=head1 TODO
- create tag objects instead of ref tags
- - audit shell-escaping of filenames
- hide our private tags somewhere smarter
- - find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
+ - sort and apply patches by graphing ancestry relations instead of just
+ relying in dates supplied in the changeset itself.
+ tla ancestry-graph -m could be helpful here...
=head1 Devel tricks
@@ -53,15 +54,9 @@ and can contain multiple, unrelated bran
use strict;
use warnings;
use Getopt::Std;
-use File::Spec;
-use File::Temp qw(tempfile tempdir);
+use File::Temp qw(tempdir);
use File::Path qw(mkpath rmtree);
use File::Basename qw(basename dirname);
-use String::ShellQuote;
-use Time::Local;
-use IO::Socket;
-use IO::Pipe;
-use POSIX qw(strftime dup2);
use Data::Dumper qw/ Dumper /;
use IPC::Open2;
@@ -72,29 +67,35 @@ my $git_dir = $ENV{"GIT_DIR"} || ".git";
$ENV{"GIT_DIR"} = $git_dir;
my $ptag_dir = "$git_dir/archimport/tags";
-our($opt_h,$opt_v, $opt_T,
- $opt_C,$opt_t);
+our($opt_h,$opt_v,$opt_T,$opt_t,$opt_D,$opt_a);
sub usage() {
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from Arch
- [ -h ] [ -v ] [ -T ] [ -t tempdir ]
+ [ -h ] [ -v ] [ -T ] [ -a ] [ -D depth ] [ -t tempdir ]
repository/arch-branch [ repository/arch-branch] ...
END
exit(1);
}
-getopts("Thvt:") or usage();
+getopts("Thvat:D:") or usage();
usage if $opt_h;
@ARGV >= 1 or usage();
-my @arch_roots = @ARGV;
+# $arch_branches:
+# values associated with keys:
+# =1 - Arch version / git 'branch' detected via abrowse on a limit
+# >1 - Arch version / git 'branch' of an auxilliary branch we've merged
+my %arch_branches = map { $_ => 1 } @ARGV;
+
my $tmptree;
$ENV{'TMPDIR'} = $opt_t if $opt_t;
$tmptree = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
$opt_v && print "+ Using $tmptree to store temporary trees\n";
+my %reachable = (); # Arch repositories we can access
+my %unreachable = (); # Arch repositories we can't access :<
my @psets = (); # the collection
my %psets = (); # the collection, by name
@@ -102,114 +103,117 @@ my %rptags = (); # my rev
# to map a SHA1 to a commitid
my $TLA = $ENV{'ARCH_CLIENT'} || 'tla';
-foreach my $root (@arch_roots) {
- my ($arepo, $abranch) = split(m!/!, $root);
- open ABROWSE, "tla abrowse -f -A $arepo --desc --merges $abranch |"
- or die "Problems with tla abrowse: $!";
-
- my %ps = (); # the current one
- my $mode = '';
- my $lastseen = '';
-
- while (<ABROWSE>) {
- chomp;
-
- # first record padded w 8 spaces
- if (s/^\s{8}\b//) {
-
- # store the record we just captured
- if (%ps) {
- my %temp = %ps; # break references
- push (@psets, \%temp);
- $psets{$temp{id}} = \%temp;
- %ps = ();
- }
-
- my ($id, $type) = split(m/\s{3}/, $_);
- $ps{id} = $id;
- $ps{repo} = $arepo;
-
- # deal with types
- if ($type =~ m/^\(simple changeset\)/) {
- $ps{type} = 's';
- } elsif ($type eq '(initial import)') {
- $ps{type} = 'i';
- } elsif ($type =~ m/^\(tag revision of (.+)\)/) {
- $ps{type} = 't';
- $ps{tag} = $1;
- } else {
- warn "Unknown type $type";
- }
- $lastseen = 'id';
- }
-
- if (s/^\s{10}//) {
- # 10 leading spaces or more
- # indicate commit metadata
-
- # date & author
- if ($lastseen eq 'id' && m/^\d{4}-\d{2}-\d{2}/) {
+sub do_abrowse {
+ my $stage = shift;
+ while (my ($limit, $level) = each %arch_branches) {
+ next unless $level == $stage;
+
+ open ABROWSE, "$TLA abrowse -fkD --merges $limit |"
+ or die "Problems with tla abrowse: $!";
+
+ my %ps = (); # the current one
+ my $lastseen = '';
+
+ while (<ABROWSE>) {
+ chomp;
+
+ # first record padded w 8 spaces
+ if (s/^\s{8}\b//) {
+ my ($id, $type) = split(m/\s+/, $_, 2);
+
+ my %last_ps;
+ # store the record we just captured
+ if (%ps && !exists $psets{ $ps{id} }) {
+ %last_ps = %ps; # break references
+ push (@psets, \%last_ps);
+ $psets{ $last_ps{id} } = \%last_ps;
+ }
- my ($date, $authoremail) = split(m/\s{2,}/, $_);
- $ps{date} = $date;
- $ps{date} =~ s/\bGMT$//; # strip off trailign GMT
- if ($ps{date} =~ m/\b\w+$/) {
- warn 'Arch dates not in GMT?! - imported dates will be wrong';
+ my $branch = extract_versionname($id);
+ %ps = ( id => $id, branch => $branch );
+ if (%last_ps && ($last_ps{branch} eq $branch)) {
+ $ps{parent_id} = $last_ps{id};
+ }
+
+ $arch_branches{$branch} = 1;
+ $lastseen = 'id';
+
+ # deal with types (should work with baz or tla):
+ if ($type =~ m/\(.*changeset\)/) {
+ $ps{type} = 's';
+ } elsif ($type =~ /\(.*import\)/) {
+ $ps{type} = 'i';
+ } elsif ($type =~ m/\(tag.*\)/) {
+ $ps{type} = 't';
+ # read which revision we've tagged when we parse the log
+ #$ps{tag} = $1;
+ } else {
+ warn "Unknown type $type";
+ }
+
+ $arch_branches{$branch} = 1;
+ $lastseen = 'id';
+ } elsif (s/^\s{10}//) {
+ # 10 leading spaces or more
+ # indicate commit metadata
+
+ # date
+ if ($lastseen eq 'id' && m/^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)/){
+ $ps{date} = $1;
+ $lastseen = 'date';
+ } elsif ($_ eq 'merges in:') {
+ $ps{merges} = [];
+ $lastseen = 'merges';
+ } elsif ($lastseen eq 'merges' && s/^\s{2}//) {
+ my $id = $_;
+ push (@{$ps{merges}}, $id);
+
+ # aggressive branch finding:
+ if ($opt_D) {
+ my $branch = extract_versionname($id);
+ my $repo = extract_reponame($branch);
+
+ if (archive_reachable($repo) &&
+ !defined $arch_branches{$branch}) {
+ $arch_branches{$branch} = $stage + 1;
+ }
+ }
+ } else {
+ warn "more metadata after merges!?: $_\n" unless /^\s*$/;
}
-
- $authoremail =~ m/^(.+)\s(\S+)$/;
- $ps{author} = $1;
- $ps{email} = $2;
-
- $lastseen = 'date';
-
- } elsif ($lastseen eq 'date') {
- # the only hint is position
- # subject is after date
- $ps{subj} = $_;
- $lastseen = 'subj';
-
- } elsif ($lastseen eq 'subj' && $_ eq 'merges in:') {
- $ps{merges} = [];
- $lastseen = 'merges';
-
- } elsif ($lastseen eq 'merges' && s/^\s{2}//) {
- push (@{$ps{merges}}, $_);
- } else {
- warn 'more metadata after merges!?';
}
-
}
- }
- if (%ps) {
- my %temp = %ps; # break references
- push (@psets, \%temp);
- $psets{ $temp{id} } = \%temp;
- %ps = ();
- }
- close ABROWSE;
+ if (%ps && !exists $psets{ $ps{id} }) {
+ my %temp = %ps; # break references
+ if ($psets[$#psets]{branch} eq $ps{branch}) {
+ $temp{parent_id} = $psets[$#psets]{id};
+ }
+ push (@psets, \%temp);
+ $psets{ $temp{id} } = \%temp;
+ }
+
+ close ABROWSE or die "$TLA abrowse failed on $limit\n";
+ }
} # end foreach $root
+do_abrowse(1);
+my $depth = 2;
+$opt_D ||= 0;
+while ($depth <= $opt_D) {
+ do_abrowse($depth);
+ $depth++;
+}
+
## Order patches by time
+# FIXME see if we can find a more optimal way to do this by graphing
+# the ancestry data and walking it, that way we won't have to rely on
+# client-supplied dates
@psets = sort {$a->{date}.$b->{id} cmp $b->{date}.$b->{id}} @psets;
-#print Dumper \@psets;
-
-##
-## TODO cleanup irrelevant patches
-## and put an initial import
-## or a full tag
-my $import = 0;
unless (-d $git_dir) { # initial import
- if ($psets[0]{type} eq 'i' || $psets[0]{type} eq 't') {
- print "Starting import from $psets[0]{id}\n";
- `git-init-db`;
- die $! if $?;
- $import = 1;
- } else {
- die "Need to start from an import or a tag -- cannot use $psets[0]{id}";
- }
+ print "Starting import from $psets[0]{id}\n";
+ system('git-init-db') == 0 or die "$! $?\n";
} else { # progressing an import
# load the rptags
opendir(DIR, $ptag_dir)
@@ -233,7 +237,6 @@ unless (-d $git_dir) { # initial import
closedir DIR;
}
-# process patchsets
# extract the Arch repository name (Arch "archive" in Arch-speak)
sub extract_reponame {
my $fq_cvbr = shift; # archivename/[[[[category]branch]version]revision]
@@ -266,21 +269,21 @@ sub tree_dirname {
*git_branchname = *tree_dirname;
-# process patchsets
+# process patchsets in ancestry order
foreach my $ps (@psets) {
$ps->{branch} = git_branchname($ps->{id});
#
# ensure we have a clean state
#
- if (`git diff-files`) {
+ if (`git-diff-files`) {
die "Unclean tree when about to process $ps->{id} " .
" - did we fail to commit cleanly before?";
}
die $! if $?;
#
- # skip commits already in repo
+ # skip commits already in git repo
#
if (ptag($ps->{id})) {
$opt_v && print " * Skipping already imported: $ps->{id}\n";
@@ -427,7 +430,7 @@ sub sync_to_ps {
my $tree_dir = $tmptree.'/'.tree_dirname($ps->{id});
if (-d $tree_dir) {
- if ($ps->{type} eq 't' && defined $ps->{tag}) {
+ if ($ps->{type} eq 't') {
# looks like a tag-only or (worse,) a mixed tags/changeset branch,
# can't rely on replay to work correctly on these
rmtree($tree_dir);
@@ -435,13 +438,16 @@ sub sync_to_ps {
} else {
my $tree_id = arch_tree_id($tree_dir);
if ($ps->{parent_id} eq $tree_id) {
+ # the common case (hopefully)
safe_pipe_capture($TLA,'replay','-d',$tree_dir,$ps->{id});
} else {
+ # this can happen if branches cherry-pick
safe_pipe_capture($TLA,'apply-delta','-d',$tree_dir,
$tree_id, $ps->{id});
}
}
} else {
+ # new branch work
safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
}
@@ -750,4 +756,23 @@ sub arch_tree_id {
return $ret;
}
+sub archive_reachable {
+ my $archive = shift;
+ return 1 if $reachable{$archive};
+ return 0 if $unreachable{$archive};
+
+ if (system "$TLA whereis-archive $archive >/dev/null") {
+ if ($opt_a && (system($TLA,'register-archive',
+ "http://mirrors.sourcecontrol.net/$archive") == 0)) {
+ $reachable{$archive} = 1;
+ return 1;
+ }
+ print STDERR "Archive is unreachable: $archive\n";
+ $unreachable{$archive} = 1;
+ return 0;
+ } else {
+ $reachable{$archive} = 1;
+ return 1;
+ }
+}
---
0.99.9.GIT
^ permalink raw reply related
* [PATCH 4/5] Overhaul of changeset application
From: Eric Wong @ 2005-11-12 9:30 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git list
In-Reply-To: <20051112092920.GD16218@Muzzle>
Overhaul of changeset application to use native Arch tree operations.
This results in:
- reliable rename handling (esp. when dealing with renamed with files
that already got renamed)
- permissions tracking (execute only for git).
- no need to shell-escape or pika-unescape anything. All arguments to
external programs are always passed as an array. File modifications
are automatically tracked using git (no need to parse Arch patch-log
to look for modified files).
- Correctly parse multi-line summary text in patch-logs
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-archimport.perl | 381 ++++++++++++++++++++-------------------------------
1 files changed, 146 insertions(+), 235 deletions(-)
applies-to: 12cd9f2d764e50ae4fe2c6cd8b64fc72c668e0dd
d3cbba7b8e8e3db61dac685ab55055d360e6138d
diff --git a/git-archimport.perl b/git-archimport.perl
index f2bcbb4..5616d42 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -55,7 +55,7 @@ use warnings;
use Getopt::Std;
use File::Spec;
use File::Temp qw(tempfile tempdir);
-use File::Path qw(mkpath);
+use File::Path qw(mkpath rmtree);
use File::Basename qw(basename dirname);
use String::ShellQuote;
use Time::Local;
@@ -90,16 +90,17 @@ usage if $opt_h;
@ARGV >= 1 or usage();
my @arch_roots = @ARGV;
-my ($tmpdir, $tmpdirname) = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
-my $tmp = $opt_t || 1;
-$tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
-$opt_v && print "+ Using $tmp as temporary directory\n";
+my $tmptree;
+$ENV{'TMPDIR'} = $opt_t if $opt_t;
+$tmptree = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
+$opt_v && print "+ Using $tmptree to store temporary trees\n";
my @psets = (); # the collection
my %psets = (); # the collection, by name
my %rptags = (); # my reverse private tags
# to map a SHA1 to a commitid
+my $TLA = $ENV{'ARCH_CLIENT'} || 'tla';
foreach my $root (@arch_roots) {
my ($arepo, $abranch) = split(m!/!, $root);
@@ -211,7 +212,7 @@ unless (-d $git_dir) { # initial import
}
} else { # progressing an import
# load the rptags
- opendir(DIR, "$git_dir/archimport/tags")
+ opendir(DIR, $ptag_dir)
|| die "can't opendir: $!";
while (my $file = readdir(DIR)) {
# skip non-interesting-files
@@ -288,26 +289,37 @@ foreach my $ps (@psets) {
print " * Starting to work on $ps->{id}\n";
- #
- # create the branch if needed
- #
- if ($ps->{type} eq 'i' && !$import) {
- die "Should not have more than one 'Initial import' per GIT import: $ps->{id}";
+ # switch to that branch if we're not already in that branch:
+ if (-e "$git_dir/refs/heads/$ps->{branch}") {
+ system('git-checkout','-f',$ps->{branch}) == 0 or die "$! $?\n";
+
+ # remove any old stuff that got leftover:
+ chomp(my @rm = safe_pipe_capture('git-ls-files','--others'));
+ rmtree(\@rm) if @rm;
}
-
- unless ($import) { # skip for import
- if ( -e "$git_dir/refs/heads/$ps->{branch}") {
- # we know about this branch
- `git checkout $ps->{branch}`;
- } else {
- # new branch! we need to verify a few things
- die "Branch on a non-tag!" unless $ps->{type} eq 't';
- my $branchpoint = ptag($ps->{tag});
- die "Tagging from unknown id unsupported: $ps->{tag}"
- unless $branchpoint;
+
+ # Apply the import/changeset/merge into the working tree
+ my $dir = sync_to_ps($ps);
+ # read the new log entry:
+ my @commitlog = safe_pipe_capture($TLA,'cat-log','-d',$dir,$ps->{id});
+ die "Error in cat-log: $!" if $?;
+ chomp @commitlog;
+
+ # grab variables we want from the log, new fields get added to $ps:
+ # (author, date, email, summary, message body ...)
+ parselog($ps, \@commitlog);
+
+ if ($ps->{id} =~ /--base-0$/ && $ps->{id} ne $psets[0]{id}) {
+ # this should work when importing continuations
+ if ($ps->{tag} && (my $branchpoint = eval { ptag($ps->{tag}) })) {
# find where we are supposed to branch from
- `git checkout -b $ps->{branch} $branchpoint`;
+ system('git-checkout','-f','-b',$ps->{branch},
+ $branchpoint) == 0 or die "$! $?\n";
+
+ # remove any old stuff that got leftover:
+ chomp(my @rm = safe_pipe_capture('git-ls-files','--others'));
+ rmtree(\@rm) if @rm;
# If we trust Arch with the fact that this is just
# a tag, and it does not affect the state of the tree
@@ -316,95 +328,26 @@ foreach my $ps (@psets) {
ptag($ps->{id}, $branchpoint);
print " * Tagged $ps->{id} at $branchpoint\n";
next;
- }
- die $! if $?;
+ } else {
+ warn "Tagging from unknown id unsupported\n" if $ps->{tag};
+ }
+ # allow multiple bases/imports here since Arch supports cherry-picks
+ # from unrelated trees
}
-
- #
- # Apply the import/changeset/merge into the working tree
- #
- if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
- apply_import($ps) or die $!;
- $import=0;
- } elsif ($ps->{type} eq 's') {
- apply_cset($ps);
- }
-
- #
- # prepare update git's index, based on what arch knows
- # about the pset, resolve parents, etc
- #
- my $tree;
- my $commitlog = `tla cat-archive-log -A $ps->{repo} $ps->{id}`;
- die "Error in cat-archive-log: $!" if $?;
-
- # parselog will git-add/rm files
- # and generally prepare things for the commit
- # NOTE: parselog will shell-quote filenames!
- my ($sum, $msg, $add, $del, $mod, $ren) = parselog($commitlog);
- my $logmessage = "$sum\n$msg";
-
-
- # imports don't give us good info
- # on added files. Shame on them
- if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
- `find . -type f -print0 | grep -zv '^./$git_dir' | xargs -0 -l100 git-update-index --add`;
- `git-ls-files --deleted -z | xargs --no-run-if-empty -0 -l100 git-update-index --remove`;
- }
-
- if (@$add) {
- while (@$add) {
- my @slice = splice(@$add, 0, 100);
- my $slice = join(' ', @slice);
- `git-update-index --add $slice`;
- die "Error in git-update-index --add: $!" if $?;
- }
- }
- if (@$del) {
- foreach my $file (@$del) {
- unlink $file or die "Problems deleting $file : $!";
- }
- while (@$del) {
- my @slice = splice(@$del, 0, 100);
- my $slice = join(' ', @slice);
- `git-update-index --remove $slice`;
- die "Error in git-update-index --remove: $!" if $?;
- }
- }
- if (@$ren) { # renamed
- if (@$ren % 2) {
- die "Odd number of entries in rename!?";
- }
- ;
- while (@$ren) {
- my $from = pop @$ren;
- my $to = pop @$ren;
-
- unless (-d dirname($to)) {
- mkpath(dirname($to)); # will die on err
- }
- #print "moving $from $to";
- `mv $from $to`;
- die "Error renaming $from $to : $!" if $?;
- `git-update-index --remove $from`;
- die "Error in git-update-index --remove: $!" if $?;
- `git-update-index --add $to`;
- die "Error in git-update-index --add: $!" if $?;
- }
-
- }
- if (@$mod) { # must be _after_ renames
- while (@$mod) {
- my @slice = splice(@$mod, 0, 100);
- my $slice = join(' ', @slice);
- `git-update-index $slice`;
- die "Error in git-update-index: $!" if $?;
- }
- }
-
- # warn "errors when running git-update-index! $!";
- $tree = `git-write-tree`;
+ # update the index with all the changes we got
+ system('git-ls-files --others -z | '.
+ 'git-update-index --add -z --stdin') == 0 or die "$! $?\n";
+ system('git-ls-files --deleted -z | '.
+ 'git-update-index --remove -z --stdin') == 0 or die "$! $?\n";
+
+ # just brute force this and update everything, it's faster than
+ # parsing the Modified-files header and then having to pika-unescape
+ # each one in case it has weird characters
+ system('git-ls-files -z | '.
+ 'git-update-index -z --stdin') == 0 or die "$! $?\n";
+
+ my $tree = `git-write-tree`;
die "cannot write tree $!" if $?;
chomp $tree;
@@ -414,7 +357,7 @@ foreach my $ps (@psets) {
#
my @par;
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
- if (open HEAD, "<$git_dir/refs/heads/$ps->{branch}") {
+ if (open HEAD, "<","$git_dir/refs/heads/$ps->{branch}") {
my $p = <HEAD>;
close HEAD;
chomp $p;
@@ -429,7 +372,6 @@ foreach my $ps (@psets) {
if ($ps->{merges}) {
push @par, find_parents($ps);
}
- my $par = join (' ', @par);
#
# Commit, tag and clean state
@@ -442,13 +384,14 @@ foreach my $ps (@psets) {
$ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
$ENV{GIT_COMMITTER_DATE} = $ps->{date};
- my ($pid, $commit_rh, $commit_wh);
- $commit_rh = 'commit_rh';
- $commit_wh = 'commit_wh';
-
- $pid = open2(*READER, *WRITER, "git-commit-tree $tree $par")
+ my $pid = open2(*READER, *WRITER, 'git-commit-tree',$tree,@par)
or die $!;
- print WRITER $logmessage; # write
+ print WRITER $ps->{summary},"\n";
+ print WRITER $ps->{message},"\n";
+
+ # make it easy to backtrack and figure out which Arch revision this was:
+ print WRITER 'git-archimport-id: ',$ps->{id},"\n";
+
close WRITER;
my $commitid = <READER>; # read
chomp $commitid;
@@ -461,7 +404,7 @@ foreach my $ps (@psets) {
#
# Update the branch
#
- open HEAD, ">$git_dir/refs/heads/$ps->{branch}";
+ open HEAD, ">","$git_dir/refs/heads/$ps->{branch}";
print HEAD $commitid;
close HEAD;
unlink ("$git_dir/HEAD");
@@ -476,71 +419,41 @@ foreach my $ps (@psets) {
print " + tree $tree\n";
print " + commit $commitid\n";
$opt_v && print " + commit date is $ps->{date} \n";
- $opt_v && print " + parents: $par \n";
+ $opt_v && print " + parents: ".join(' ',@par)."\n";
}
-sub apply_import {
+sub sync_to_ps {
my $ps = shift;
- my $bname = git_branchname($ps->{id});
+ my $tree_dir = $tmptree.'/'.tree_dirname($ps->{id});
- `mkdir -p $tmp`;
-
- `tla get -s --no-pristine -A $ps->{repo} $ps->{id} $tmp/import`;
- die "Cannot get import: $!" if $?;
- `rsync -v --archive --delete --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/import/* ./`;
- die "Cannot rsync import:$!" if $?;
-
- `rm -fr $tmp/import`;
- die "Cannot remove tempdir: $!" if $?;
-
-
- return 1;
-}
-
-sub apply_cset {
- my $ps = shift;
-
- `mkdir -p $tmp`;
-
- # get the changeset
- `tla get-changeset -A $ps->{repo} $ps->{id} $tmp/changeset`;
- die "Cannot get changeset: $!" if $?;
-
- # apply patches
- if (`find $tmp/changeset/patches -type f -name '*.patch'`) {
- # this can be sped up considerably by doing
- # (find | xargs cat) | patch
- # but that cna get mucked up by patches
- # with missing trailing newlines or the standard
- # 'missing newline' flag in the patch - possibly
- # produced with an old/buggy diff.
- # slow and safe, we invoke patch once per patchfile
- `find $tmp/changeset/patches -type f -name '*.patch' -print0 | grep -zv '{arch}' | xargs -iFILE -0 --no-run-if-empty patch -p1 --forward -iFILE`;
- die "Problem applying patches! $!" if $?;
- }
-
- # apply changed binary files
- if (my @modified = `find $tmp/changeset/patches -type f -name '*.modified'`) {
- foreach my $mod (@modified) {
- chomp $mod;
- my $orig = $mod;
- $orig =~ s/\.modified$//; # lazy
- $orig =~ s!^\Q$tmp\E/changeset/patches/!!;
- #print "rsync -p '$mod' '$orig'";
- `rsync -p $mod ./$orig`;
- die "Problem applying binary changes! $!" if $?;
+ if (-d $tree_dir) {
+ if ($ps->{type} eq 't' && defined $ps->{tag}) {
+ # looks like a tag-only or (worse,) a mixed tags/changeset branch,
+ # can't rely on replay to work correctly on these
+ rmtree($tree_dir);
+ safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
+ } else {
+ my $tree_id = arch_tree_id($tree_dir);
+ if ($ps->{parent_id} eq $tree_id) {
+ safe_pipe_capture($TLA,'replay','-d',$tree_dir,$ps->{id});
+ } else {
+ safe_pipe_capture($TLA,'apply-delta','-d',$tree_dir,
+ $tree_id, $ps->{id});
+ }
}
+ } else {
+ safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
}
-
- # bring in new files
- `rsync --archive --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/changeset/new-files-archive/* ./`;
-
- # deleted files are hinted from the commitlog processing
-
- `rm -fr $tmp/changeset`;
+
+ # added -I flag to rsync since we're going to fast! AIEEEEE!!!!
+ system('rsync','-aI','--delete','--exclude',$git_dir,
+# '--exclude','.arch-inventory',
+ '--exclude','.arch-ids','--exclude','{arch}',
+ '--exclude','+*','--exclude',',*',
+ "$tree_dir/",'./') == 0 or die "Cannot rsync $tree_dir: $! $?";
+ return $tree_dir;
}
-
# =for reference
# A log entry looks like
# Revision: moodle-org--moodle--1.3.3--patch-15
@@ -560,70 +473,42 @@ sub apply_cset {
# admin/editor.html backup/lib.php backup/restore.php
# New-patches: arch-eduforge@catalyst.net.nz--2004/moodle-org--moodle--1.3.3--patch-15
# Summary: Updating to latest from MOODLE_14_STABLE (1.4.5+)
+# summary can be multiline with a leading space just like the above fields
# Keywords:
#
# Updating yadda tadda tadda madda
sub parselog {
- my $log = shift;
- #print $log;
-
- my (@add, @del, @mod, @ren, @kw, $sum, $msg );
-
- if ($log =~ m/(?:\n|^)New-files:(.*?)(?=\n\w)/s ) {
- my $files = $1;
- @add = split(m/\s+/s, $files);
- }
-
- if ($log =~ m/(?:\n|^)Removed-files:(.*?)(?=\n\w)/s ) {
- my $files = $1;
- @del = split(m/\s+/s, $files);
- }
-
- if ($log =~ m/(?:\n|^)Modified-files:(.*?)(?=\n\w)/s ) {
- my $files = $1;
- @mod = split(m/\s+/s, $files);
- }
-
- if ($log =~ m/(?:\n|^)Renamed-files:(.*?)(?=\n\w)/s ) {
- my $files = $1;
- @ren = split(m/\s+/s, $files);
- }
-
- $sum ='';
- if ($log =~ m/^Summary:(.+?)$/m ) {
- $sum = $1;
- $sum =~ s/^\s+//;
- $sum =~ s/\s+$//;
- }
-
- $msg = '';
- if ($log =~ m/\n\n(.+)$/s) {
- $msg = $1;
- $msg =~ s/^\s+//;
- $msg =~ s/\s+$//;
- }
-
-
- # cleanup the arrays
- foreach my $ref ( (\@add, \@del, \@mod, \@ren) ) {
- my @tmp = ();
- while (my $t = pop @$ref) {
- next unless length ($t);
- next if $t =~ m!\{arch\}/!;
- next if $t =~ m!\.arch-ids/!;
- next if $t =~ m!\.arch-inventory$!;
- # tla cat-archive-log will give us filenames with spaces as file\(sp)name - why?
- # we can assume that any filename with \ indicates some pika escaping that we want to get rid of.
- if ($t =~ /\\/ ){
- $t = `tla escape --unescaped '$t'`;
- }
- push (@tmp, shell_quote($t));
+ my ($ps, $log) = @_;
+ my $key = undef;
+ while ($_ = shift @$log) {
+ if (/^Continuation-of:\s*(.*)/) {
+ $ps->{tag} = $1;
+ $key = undef;
+ } elsif (/^Summary:\s*(.*)$/ ) {
+ # summary can be multiline as long as it has a leading space
+ $ps->{summary} = [ $1 ];
+ $key = 'summary';
+ } elsif (/^Creator: (.*)\s*<([^\>]+)>/) {
+ $ps->{author} = $1;
+ $ps->{email} = $2;
+ $key = undef;
+ } elsif (/^$/) {
+ last; # remainder of @$log that didn't get shifted off is message
+ } elsif ($key) {
+ if (/^\s+(.*)$/) {
+ if ($key eq 'summary') {
+ push @{$ps->{$key}}, $1;
+ } else {
+ push @{$ps->{$key}}, split(/\s+/, $1);
+ }
+ } else {
+ $key = undef;
+ }
}
- @$ref = @tmp;
}
- #print Dumper [$sum, $msg, \@add, \@del, \@mod, \@ren];
- return ($sum, $msg, \@add, \@del, \@mod, \@ren);
+ $ps->{summary} = join("\n",@{$ps->{summary}})."\n";
+ $ps->{message} = join("\n",@$log);
}
# write/read a tag
@@ -816,8 +701,11 @@ sub find_parents {
}
}
}
- @parents = keys %parents;
- @parents = map { " -p " . ptag($_) } @parents;
+
+ @parents = ();
+ foreach (keys %parents) {
+ push @parents, '-p', ptag($_);
+ }
return @parents;
}
@@ -840,3 +728,26 @@ sub commitid2pset {
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
return $ps;
}
+
+
+# an alterative to `command` that allows input to be passed as an array
+# to work around shell problems with weird characters in arguments
+sub safe_pipe_capture {
+ my @output;
+ if (my $pid = open my $child, '-|') {
+ @output = (<$child>);
+ close $child or die join(' ',@_).": $! $?";
+ } else {
+ exec(@_) or die $?; # exec() can fail the executable can't be found
+ }
+ return wantarray ? @output : join('',@output);
+}
+
+# `tla logs -rf -d <dir> | head -n1` or `baz tree-id <dir>`
+sub arch_tree_id {
+ my $dir = shift;
+ chomp( my $ret = (safe_pipe_capture($TLA,'logs','-rf','-d',$dir))[0] );
+ return $ret;
+}
+
+
---
0.99.9.GIT
^ permalink raw reply related
* [PATCH 3/5] Disambiguate the term 'branch' in Arch vs git
From: Eric Wong @ 2005-11-12 9:29 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git list
In-Reply-To: <20051112092721.GC16218@Muzzle>
[-- Attachment #1: Type: text/plain, Size: 3647 bytes --]
Disambiguate the term 'branch' in Arch vs git,
and start using fully-qualified names.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-archimport.perl | 65 ++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 54 insertions(+), 11 deletions(-)
applies-to: bbfe032e4900efc45bb94fb687af0140ccb0a858
ede672b4cd544b5e5418cc5088e92f2e0d2f7394
diff --git a/git-archimport.perl b/git-archimport.perl
index 699d5f6..f2bcbb4 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -30,6 +30,24 @@ See man (1) git-archimport for more deta
Add print in front of the shell commands invoked via backticks.
+=head1 Devel Notes
+
+There are several places where Arch and git terminology are intermixed
+and potentially confused.
+
+The notion of a "branch" in git is approximately equivalent to
+a "archive/category--branch--version" in Arch. Also, it should be noted
+that the "--branch" portion of "archive/category--branch--version" is really
+optional in Arch although not many people (nor tools!) seem to know this.
+This means that "archive/category--version" is also a valid "branch"
+in git terms.
+
+We always refer to Arch names by their fully qualified variant (which
+means the "archive" name is prefixed.
+
+For people unfamiliar with Arch, an "archive" is the term for "repository",
+and can contain multiple, unrelated branches.
+
=cut
use strict;
@@ -215,9 +233,41 @@ unless (-d $git_dir) { # initial import
}
# process patchsets
-foreach my $ps (@psets) {
+# extract the Arch repository name (Arch "archive" in Arch-speak)
+sub extract_reponame {
+ my $fq_cvbr = shift; # archivename/[[[[category]branch]version]revision]
+ return (split(/\//, $fq_cvbr))[0];
+}
+
+sub extract_versionname {
+ my $name = shift;
+ $name =~ s/--(?:patch|version(?:fix)?|base)-\d+$//;
+ return $name;
+}
- $ps->{branch} = branchname($ps->{id});
+# convert a fully-qualified revision or version to a unique dirname:
+# normalperson@yhbt.net-05/mpd--uclinux--1--patch-2
+# becomes: normalperson@yhbt.net-05,mpd--uclinux--1
+#
+# the git notion of a branch is closer to
+# archive/category--branch--version than archive/category--branch, so we
+# use this to convert to git branch names.
+# Also, keep archive names but replace '/' with ',' since it won't require
+# subdirectories, and is safer than swapping '--' which could confuse
+# reverse-mapping when dealing with bastard branches that
+# are just archive/category--version (no --branch)
+sub tree_dirname {
+ my $revision = shift;
+ my $name = extract_versionname($revision);
+ $name =~ s#/#,#;
+ return $name;
+}
+
+*git_branchname = *tree_dirname;
+
+# process patchsets
+foreach my $ps (@psets) {
+ $ps->{branch} = git_branchname($ps->{id});
#
# ensure we have a clean state
@@ -429,16 +479,9 @@ foreach my $ps (@psets) {
$opt_v && print " + parents: $par \n";
}
-sub branchname {
- my $id = shift;
- $id =~ s#^.+?/##;
- my @parts = split(m/--/, $id);
- return join('--', @parts[0..1]);
-}
-
sub apply_import {
my $ps = shift;
- my $bname = branchname($ps->{id});
+ my $bname = git_branchname($ps->{id});
`mkdir -p $tmp`;
@@ -669,7 +712,7 @@ sub find_parents {
# simple loop to split the merges
# per branch
foreach my $merge (@{$ps->{merges}}) {
- my $branch = branchname($merge);
+ my $branch = git_branchname($merge);
unless (defined $branches{$branch} ){
$branches{$branch} = [];
}
---
0.99.9.GIT
--
Eric Wong
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply related
* [PATCH 2/5] archimport: don't die on merge-base failure
From: Eric Wong @ 2005-11-12 9:27 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git list
In-Reply-To: <20051112092533.GB16218@Muzzle>
Don't die if we can't find a merge base, Arch allows arbitrary
cherry-picks between unrelated branches and we should not
die when that happens
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-archimport.perl | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
applies-to: 07dfd96ba53890d6a20fa0b028cf96e0e49bc027
7d099adadc041d74a0defc107656f273b35f57cb
diff --git a/git-archimport.perl b/git-archimport.perl
index 7c15184..699d5f6 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -693,7 +693,13 @@ sub find_parents {
next unless -e "$git_dir/refs/heads/$branch";
my $mergebase = `git-merge-base $branch $ps->{branch}`;
- die "Cannot find merge base for $branch and $ps->{branch}" if $?;
+ if ($?) {
+ # Don't die here, Arch supports one-way cherry-picking
+ # between branches with no common base (or any relationship
+ # at all beforehand)
+ warn "Cannot find merge base for $branch and $ps->{branch}";
+ next;
+ }
chomp $mergebase;
# now walk up to the mergepoint collecting what patches we have
---
0.99.9.GIT
^ permalink raw reply related
* [PATCH 1/5] remove shellquote usage for tags
From: Eric Wong @ 2005-11-12 9:25 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git list
In-Reply-To: <20051112092336.GA16218@Muzzle>
use ',' to encode '/' in "archivename/foo--bar--0.0" so we can allow
"--branch"-less trees which are valid in Arch ("archivename/foo--0.0")
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-archimport.perl | 55 ++++++++++++++++++++++++++-------------------------
1 files changed, 28 insertions(+), 27 deletions(-)
applies-to: 76d3d1c302c20b82fd976e958aabd19f7f01e7b5
28d4f9ee8ba83b35eea66d4dd19b8ec26a0218c7
diff --git a/git-archimport.perl b/git-archimport.perl
index e22c816..7c15184 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -52,6 +52,7 @@ $ENV{'TZ'}="UTC";
my $git_dir = $ENV{"GIT_DIR"} || ".git";
$ENV{"GIT_DIR"} = $git_dir;
+my $ptag_dir = "$git_dir/archimport/tags";
our($opt_h,$opt_v, $opt_T,
$opt_C,$opt_t);
@@ -195,16 +196,19 @@ unless (-d $git_dir) { # initial import
opendir(DIR, "$git_dir/archimport/tags")
|| die "can't opendir: $!";
while (my $file = readdir(DIR)) {
- # skip non-interesting-files
- next unless -f "$git_dir/archimport/tags/$file";
- next if $file =~ m/--base-0$/; # don't care for base-0
+ # skip non-interesting-files
+ next unless -f "$ptag_dir/$file";
+
+ # convert first '--' to '/' from old git-archimport to use
+ # as an archivename/c--b--v private tag
+ if ($file !~ m!,!) {
+ my $oldfile = $file;
+ $file =~ s!--!,!;
+ print STDERR "converting old tag $oldfile to $file\n";
+ rename("$ptag_dir/$oldfile", "$ptag_dir/$file") or die $!;
+ }
my $sha = ptag($file);
chomp $sha;
- # reconvert the 3rd '--' sequence from the end
- # into a slash
- # $file = reverse $file;
- # $file =~ s!^(.+?--.+?--.+?--.+?)--(.+)$!$1/$2!;
- # $file = reverse $file;
$rptags{$sha} = $file;
}
closedir DIR;
@@ -582,19 +586,20 @@ sub parselog {
# write/read a tag
sub tag {
my ($tag, $commit) = @_;
- $tag =~ s|/|--|g;
- $tag = shell_quote($tag);
+
+ # don't use subdirs for tags yet, it could screw up other porcelains
+ $tag =~ s|/|,|;
if ($commit) {
- open(C,">$git_dir/refs/tags/$tag")
+ open(C,">","$git_dir/refs/tags/$tag")
or die "Cannot create tag $tag: $!\n";
print C "$commit\n"
or die "Cannot write tag $tag: $!\n";
close(C)
or die "Cannot write tag $tag: $!\n";
- print " * Created tag ' $tag' on '$commit'\n" if $opt_v;
+ print " * Created tag '$tag' on '$commit'\n" if $opt_v;
} else { # read
- open(C,"<$git_dir/refs/tags/$tag")
+ open(C,"<","$git_dir/refs/tags/$tag")
or die "Cannot read tag $tag: $!\n";
$commit = <C>;
chomp $commit;
@@ -609,15 +614,16 @@ sub tag {
# reads fail softly if the tag isn't there
sub ptag {
my ($tag, $commit) = @_;
- $tag =~ s|/|--|g;
- $tag = shell_quote($tag);
+
+ # don't use subdirs for tags yet, it could screw up other porcelains
+ $tag =~ s|/|,|g;
- unless (-d "$git_dir/archimport/tags") {
- mkpath("$git_dir/archimport/tags");
- }
+ my $tag_file = "$ptag_dir/$tag";
+ my $tag_branch_dir = dirname($tag_file);
+ mkpath($tag_branch_dir) unless (-d $tag_branch_dir);
if ($commit) { # write
- open(C,">$git_dir/archimport/tags/$tag")
+ open(C,">",$tag_file)
or die "Cannot create tag $tag: $!\n";
print C "$commit\n"
or die "Cannot write tag $tag: $!\n";
@@ -627,10 +633,10 @@ sub ptag {
unless $tag =~ m/--base-0$/;
} else { # read
# if the tag isn't there, return 0
- unless ( -s "$git_dir/archimport/tags/$tag") {
+ unless ( -s $tag_file) {
return 0;
}
- open(C,"<$git_dir/archimport/tags/$tag")
+ open(C,"<",$tag_file)
or die "Cannot read tag $tag: $!\n";
$commit = <C>;
chomp $commit;
@@ -780,12 +786,7 @@ sub commitid2pset {
chomp $commitid;
my $name = $rptags{$commitid}
|| die "Cannot find reverse tag mapping for $commitid";
- # the keys in %rptag are slightly munged; unmunge
- # reconvert the 3rd '--' sequence from the end
- # into a slash
- $name = reverse $name;
- $name =~ s!^(.+?--.+?--.+?--.+?)--(.+)$!$1/$2!;
- $name = reverse $name;
+ $name =~ s|,|/|;
my $ps = $psets{$name}
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
return $ps;
---
0.99.9.GIT
^ permalink raw reply related
* [PATCH] archimport improvements
From: Eric Wong @ 2005-11-12 9:23 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git list
Hello,
I'm another Arch-user trying out git. Unfortunately, I encountered
several problems with git-archimport that I needed fixed before my
development trees could be imported into git.
Here's a summary of the changes:
Bug Fixes:
* Support for '--branch'-less Arch version names.
Encoding '/' to '--' (as was previously done) is not 100% reversable
because the "--branch" portion of an fully-qualified Arch version name
is optional (though not many people or Arch-related tools know this).
* I'm encoding the '/' in the fully-qualified name as ',' to not confuse
other porcelains, but leaving '/' in branch names may be alright
provided porcelains can support them.
* Identify git branches as an Arch "archive,category<--branch>--version"
Anything less than that is ambiguous as far as history and patch
relationships go.
* Renamed directories containing renamed/moved files inside didn't get
tracked properly. The original code was inadequate for this, and
making it support all rename cases that Arch supports is too much
work. Instead, I maintain full-blown Arch trees in the temp dir and
replay patches + rsync based on that. Performance is slightly slower
than before, but accuracy is more important to me.
* Permission (execute bit only because of git) tracking as a side effect
of the above.
* Tracking changes from branches that are only cherry-picked now works
* Pika-escaped filenames unhandled. This seems fixed in the latest
git, but I fixed it more generally and removed the ShellQuote module
dependency along the way.
* Don't die() when a merge-base can't be found. Arch supports
merging between unrelated trees.
Usability enhancements:
* Optionally detect merged branches and attempt to import their history,
too. Use the -D <depth> option for this. Specifying a <depth>
greater than 1 is usually not needed unless the tree you're tracking
has had history pruned.
* Optionally attempt to auto-register unknown Arch archives from
mirrors.sourcecontrol.net to pull their history with the -a (boolean)
switch. Not sure how useful users will find this.
* Removed -A <archive> usage (unnecessary in all cases) and made all
Arch calls and output parsing to be compatible with both tla (tested
1.3.3) and baz (1.4.2). Default is still tla, but the ARCH_CLIENT
environment variable may be changed to baz.
Current weaknesses:
* (Present in the original code as well).
The code still assumes that dates in commit logs can be trusted, which is
fine in most cases, but a wayward branch can screw up git-archimport and
cause parents to be missed.
--
Eric Wong
^ permalink raw reply
* [PATCH] GIT commit statistics.
From: Junio C Hamano @ 2005-11-12 7:44 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Linus Torvalds, git
In-Reply-To: <43758D21.3060107@michonline.com>
Ryan Anderson <ryan@michonline.com> writes:
> Junio C Hamano wrote:
>
>> Just for fun, I randomly picked two heads/master commits from
>> linux-2.6 repository ... and fed the commits
>> between the two to a little script that looks at commits and
>> tries to stat what they did (the script ignores renames so they
>> appear as deletes and adds).
>
> Mind sharing the script?
>
> It'be nice to know if these stats are typical, or unusual when you get
> numbers from a variety of other trees.
Very unpolished but here they are.
I misread the trivial count in my original message. Trivial and
Merge are counted separately, so among 3957 commits, merges were
297 (72 trivials and 225 others).
-- >8 -- cut here -- >8 --
Subject: [PATCH] GIT commit statistics
A set of scripts that read the existing commit history, and
show various stats.
Sample usage:
# Arguments are given to git-rev-list; defaults to ORIG..
# if not given, to retrace what was just pulled.
$ ./contrib/jc-git-stat-1.sh v0.99.9g..maint |
./contrib/jc-git-stat-1-log.perl
Total commit objects: 43
Trivial Merges: 1 (2.33%)
Merges: 1 (2.33%)
Number of paths touched by non-merge commits:
average 3.00, median 2, min 2, max 18
Number of merge parents:
average 2.50, median 3, min 2, max 3
Number of merge bases:
average 1.00, median 1, min 1, max 1
File level merges:
average 0.50, median 1, min 0, max 1
Number of changed paths from the first parent:
average 28.00, median 52, min 4, max 52
File level 3-ways:
average 1.00, median 1, min 1, max 1
* "Trivial Merges" are the ones done by read-tree --trivial;
* "Merges" are other merges;
* "File level merges" are paths not collapsed by read-tree 3-way (i.e.
given to merge-one-file);
* "File level 3-ways" are paths merge-one-file would have run 'merge';
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
contrib/jc-git-stat-1-log.perl | 87 ++++++++++++++++++++++++++++++++++++++++
contrib/jc-git-stat-1-mof.sh | 59 +++++++++++++++++++++++++++
contrib/jc-git-stat-1.sh | 74 ++++++++++++++++++++++++++++++++++
3 files changed, 220 insertions(+), 0 deletions(-)
create mode 100755 contrib/jc-git-stat-1-log.perl
create mode 100755 contrib/jc-git-stat-1-mof.sh
create mode 100755 contrib/jc-git-stat-1.sh
applies-to: 9a0f0c748316751fbf593a21f2b16bcdd975095a
2cb3da4b260ed82dc379a11d91f55fe774a2ea49
diff --git a/contrib/jc-git-stat-1-log.perl b/contrib/jc-git-stat-1-log.perl
new file mode 100755
index 0000000..b70af2b
--- /dev/null
+++ b/contrib/jc-git-stat-1-log.perl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+
+my ($patches, $failures, $merges, $trivials) = (0, 0, 0, 0);
+my (@patch_paths,
+ @parent_counts,
+ @base_counts,
+ @merge_counts,
+ @path_counts,
+ @res_counts,
+ @merge_m,
+ @merge_a,
+ @merge_d,
+ @merge_c,
+ @merge_u);
+
+sub avg_median {
+ my ($ary) = shift;
+ my ($msg) = shift;
+ my @a = sort { $a <=> $b } @$ary;
+ my $sum = 0;
+ for (@a) { $sum += $_ }
+ return unless (@a && $sum);
+ my ($avg, $med) = ($sum/@a, $a[(@a/2)]);
+ my ($min, $max) = ($a[0], $a[$#a]);
+ printf "%s:\n\taverage %.2f, median %d, min %d, max %d\n",
+ $msg, $avg, $med, $min, $max;
+}
+
+while (<>) {
+ next unless (s/^([MCFT]) [0-9a-f]{40} //);
+ chomp;
+ my $type = $1;
+ if ($type eq 'F') {
+ $failures++;
+ next;
+ }
+ if ($type eq 'C') {
+ $patches++;
+ push @patch_paths, $_;
+ next;
+ }
+ if ($type eq 'M') {
+ $merges++;
+ }
+ elsif ($type eq 'T') {
+ $trivials++;
+ }
+ else {
+ die "?? $type";
+ }
+ s/^(\d+) (\d+) (\d+) (\d+) (\d+) *//;
+ push @parent_counts, $1;
+ push @base_counts, $2;
+ push @merge_counts, $3;
+ push @path_counts, $4;
+ push @res_counts, $5;
+ if ($type eq 'M') {
+ /M=(\d+) A=(\d+) D=(\d+) C=(\d+) U=(\d+)/ or die;
+ push @merge_m, $1;
+ push @merge_a, $2;
+ push @merge_d, $3;
+ push @merge_c, $4;
+ push @merge_u, $5;
+ }
+}
+
+my $total = ($failures+$patches+$merges+$trivials);
+print "Total commit objects: $total\n";
+printf "Trivial Merges: $trivials (%.2f%%)\n", ($trivials * 100.0/$total);
+printf "Merges: $merges (%.2f%%)\n", ($merges * 100.0/$total);
+if ($failures) {
+ print "Failures: $failures\n";
+}
+
+avg_median(\@patch_paths, "Number of paths touched by non-merge commits");
+avg_median(\@parent_counts, "Number of merge parents");
+avg_median(\@base_counts, "Number of merge bases");
+avg_median(\@merge_counts, "File level merges");
+avg_median(\@path_counts, "Number of changed paths from the first parent");
+#avg_median(\@res_counts, "");
+avg_median(\@merge_m, "File level 3-ways");
+avg_median(\@merge_a, "Paths added");
+avg_median(\@merge_d, "Paths deleted");
+avg_median(\@merge_c, "Paths identically added with wrong permission");
+avg_median(\@merge_u, "Paths added differently");
+
+
diff --git a/contrib/jc-git-stat-1-mof.sh b/contrib/jc-git-stat-1-mof.sh
new file mode 100755
index 0000000..2be6d8b
--- /dev/null
+++ b/contrib/jc-git-stat-1-mof.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# Copyright (c) Linus Torvalds, 2005
+# Copyright (c) Junio C Hamano, 2005
+#
+# This is modified from the git per-file merge script, called with
+#
+# $1 - original file SHA1 (or empty)
+# $2 - file in branch1 SHA1 (or empty)
+# $3 - file in branch2 SHA1 (or empty)
+# $4 - pathname in repository
+# $5 - orignal file mode (or empty)
+# $6 - file in branch1 mode (or empty)
+# $7 - file in branch2 mode (or empty)
+#
+# Handle some trivial cases.. The _really_ trivial cases have
+# been handled already by git-read-tree, but that one doesn't
+# do any merges that might change the tree layout.
+
+case "${1:-.}${2:-.}${3:-.}" in
+#
+# Deleted in both or deleted in one and unchanged in the other
+#
+"$1.." | "$1.$1" | "$1$1.")
+ echo D
+ ;;
+
+#
+# Added in one.
+#
+".$2." | "..$3" )
+ echo A
+ ;;
+
+#
+# Added in both (check for same permissions).
+#
+".$3$2")
+ if [ "$6" != "$7" ]; then
+ echo C
+ else
+ echo A
+ fi
+ ;;
+
+#
+# Modified in both, but differently.
+#
+"$1$2$3")
+ echo M
+ ;;
+
+".$2$3")
+ echo U
+ ;;
+*)
+ echo C
+ ;;
+esac
diff --git a/contrib/jc-git-stat-1.sh b/contrib/jc-git-stat-1.sh
new file mode 100755
index 0000000..b03c69d
--- /dev/null
+++ b/contrib/jc-git-stat-1.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+MOF=`dirname "$0"`/jc-git-stat-1-mof.sh
+
+GIT_INDEX_FILE=.tmp-index
+export GIT_INDEX_FILE
+LF='
+'
+
+check_merge () {
+ rm -f $GIT_INDEX_FILE
+ commit=$1
+ shift
+
+ case "$#" in
+ 2)
+ MB=$(git-merge-base --all "$@")
+ ;;
+ *)
+ MB=$(git-show-branch --merge-base "$@")
+ ;;
+ esac
+ basecnt=$(echo $MB | wc -l)
+
+ if git-read-tree --trivial -m $MB "$@" 2>/dev/null
+ then
+ type=T
+ pathcnt=$(git-diff-index --cached --name-status "$1" | wc -l)
+ rescnt=$(git-diff-index --cached --name-status "$commit" | wc -l)
+ echo "T $commit $# $basecnt 0 $pathcnt $rescnt"
+ elif git-read-tree -m $MB "$@" 2>/dev/null
+ then
+ script='s/^ *\([0-9]*\) *\([A-Z]\)/\2=\1/'
+ type=M
+ mergecnt=$(git-ls-files --unmerged | sort -k 4,4 -u | wc -l)
+ pathcnt=$(git-diff-index --cached --name-status "$1" | wc -l)
+
+ C=0 A=0 M=0 U=0 D=0
+ eval `git-merge-index -o "$MOF" -a |
+ sort |
+ uniq -c |
+ sed -e "$script"`
+ rescnt=$(git-diff-index --cached --name-status "$commit" | wc -l)
+ echo "M $commit $# $basecnt $mergecnt $pathcnt $rescnt M=$M A=$A D=$D C=$C U=$U"
+ else
+ echo "F $commit $# $basecnt"
+ fi
+}
+
+check_patch () {
+ pathcnt=$(git-diff-tree --name-status -r "$1" | wc -l)
+ echo "C $1 $pathcnt"
+}
+
+case "$#" in
+0)
+ set ORIG_HEAD.. ;;
+esac
+
+git-rev-list --parents "$@" |
+while read commit parents
+do
+ case "$parents" in
+ ?*' '?*)
+ # Merge
+ check_merge $commit $parents
+ ;;
+ *)
+ # Change
+ check_patch $commit $parents
+ ;;
+ esac
+done
+
---
0.99.9.GIT
^ permalink raw reply related
* linux tree, commit 7b7abfe3dd81d659a0889f88965168f7eef8c5c6
From: Marco Costalba @ 2005-11-12 7:01 UTC (permalink / raw)
To: git
Linux tree:
commit 7b7abfe3dd81d659a0889f88965168f7eef8c5c6
Author: Steve French <sfrench@us.ibm.com>
Date: Wed Nov 9 15:21:09 2005 -0800
Seems without subject and description.
Is this correct?
Marco
__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005
http://mail.yahoo.com
^ permalink raw reply
* Re: Comments on recursive merge..
From: Ryan Anderson @ 2005-11-12 6:35 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <7v4q6ilt3m.fsf@assigned-by-dhcp.cox.net>
[-- Attachment #1: Type: text/plain, Size: 875 bytes --]
Junio C Hamano wrote:
> Linus Torvalds <torvalds@osdl.org> writes:
>
>
>>>Another thing to consider is if it is fast enough for everyday
>>>trivial merges.
>>
>>Hmm. True. The _really_ trivial in-index case triggers for me pretty
>>often, but I haven't done any statistics. It might be only 50% of the
>>time.
>
>
> Just for fun, I randomly picked two heads/master commits from
> linux-2.6 repository (one was when I happened to have pulled the
> last time, and the other was when I thought this might be an
> interesting exercise and pulled again), and fed the commits
> between the two to a little script that looks at commits and
> tries to stat what they did (the script ignores renames so they
> appear as deletes and adds).
Mind sharing the script?
It'be nice to know if these stats are typical, or unusual when you get
numbers from a variety of other trees.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply
* Re: [PATCH] Fix bunch of fd leaks in http-fetch
From: Junio C Hamano @ 2005-11-12 5:45 UTC (permalink / raw)
To: Petr Baudis, Nick Hengeveld; +Cc: git
In-Reply-To: <20051111235516.GY30496@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
> The current http-fetch is rather careless about fd leakage, causing
> problems while fetching large repositories. This patch does not reserve
> exhaustiveness, but I covered everything I spotted...
Thanks. While I am sure a quick fix is better for the end user
than not doing anything at all, I am a bit reluctant.
It strikes me somewhat odd that these close() are not tied to
the lifetime rule of the transfer_request structure. When the
program falls back from an individual object to alternates, the
same request structure is reused, but in that case ->local stays
the same. Otherwise, the original request structure is released
so I wonder if would make things cleaner to close ->local inside
request_release()...
Nick?
^ permalink raw reply
* Re: git-core-arch: Missing dependency
From: Chris Wright @ 2005-11-12 1:26 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: Junio C Hamano, Andreas Ericsson, git, Chris Wright
In-Reply-To: <43754083.4090501@zytor.com>
* H. Peter Anvin (hpa@zytor.com) wrote:
> Junio C Hamano wrote:
> >Andreas Ericsson <ae@op5.se> writes:
> >>Just to be anal;
> >>Requires doesn't usually include the %release,...
> >
> >Obviously both you and Chris (who did the part you are quoting
> >for us) know RPM spec a lot better than I do, and I see two
> >experts contradicting with each other. It could have been just
> >an oversight, or it might have done deliberately --- I cannot
> >judge myself, so I punt here. I'll remove "-%{release}" when I
> >hear Chris says he agrees with you.
>
> You can do it either way. It's a matter of the strictness of the
> binding. If you put %{version} there, then it has to come from the same
> upstream release; for %{version}-%{release} it has to come from the same
> SRPM, i.e. usually from the same build.
>
> In this case I think %{version}-%{release} is appropriate.
Yeah, I was being conservative. In reality, the release is rarely
bumped, so it's probably not critical either way.
thanks,
-chris
^ permalink raw reply
* Re: [PATCH] Show URL in the "Getting <foo> list" http-fetch messages
From: Junio C Hamano @ 2005-11-12 1:17 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20051112005803.GZ30496@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
> By the way, this is only a pathetic remnant of my brave effort to get
> rid of seeing the "Getting alternates list" message on the same
> repository 20 times now since the parallel fetching got introduced.
> I know how to do silence the messages, but doing the _fetching_ itself
> seems as downright stupid thing in the first place.
>
> Therefore, can I somehow stall fetching of an object? The idea is:
>
> I want to check the alternates list!
> I don't have it yet...
> ...but a request for it is already queued. Ok, I'll wait.
I agree, and probably this applies when index request is in
transit as well.
^ permalink raw reply
* Re: git-core-arch: Missing dependency
From: H. Peter Anvin @ 2005-11-12 1:08 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Andreas Ericsson, git, Chris Wright
In-Reply-To: <7vu0ejm30l.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
> Andreas Ericsson <ae@op5.se> writes:
>
>
>>Junio C Hamano wrote:
>>
>>>Horst von Brand <vonbrand@inf.utfsm.cl> writes:
>>>
>>>
>>>>The command git-archimport makes use of tla, but the relevant package(s) are
>>>>not on the requirements
>>>
>>>Thanks. Should the fix be like this?
>>> Group: Development/Tools
>>>-Requires: git-core = %{version}-%{release}
>>>+Requires: git-core = %{version}-%{release}, tla
>>
>>Just to be anal;
>>Requires doesn't usually include the %release,...
>
>
> Obviously both you and Chris (who did the part you are quoting
> for us) know RPM spec a lot better than I do, and I see two
> experts contradicting with each other. It could have been just
> an oversight, or it might have done deliberately --- I cannot
> judge myself, so I punt here. I'll remove "-%{release}" when I
> hear Chris says he agrees with you.
>
You can do it either way. It's a matter of the strictness of the
binding. If you put %{version} there, then it has to come from the same
upstream release; for %{version}-%{release} it has to come from the same
SRPM, i.e. usually from the same build.
In this case I think %{version}-%{release} is appropriate.
-hpa
^ permalink raw reply
* Re: [PATCH] Show URL in the "Getting <foo> list" http-fetch messages
From: Petr Baudis @ 2005-11-12 0:58 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <20051112004958.21857.95728.stgit@machine.or.cz>
Dear diary, on Sat, Nov 12, 2005 at 01:49:59AM CET, I got a letter
where Petr Baudis <pasky@suse.cz> said that...
> Signed-off-by: Petr Baudis <pasky@suse.cz>
> ---
>
> http-fetch.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/http-fetch.c b/http-fetch.c
> index e7655d1..e6e7df6 100644
> --- a/http-fetch.c
> +++ b/http-fetch.c
> @@ -795,7 +795,7 @@ static int fetch_alternates(char *base)
> buffer.buffer = data;
>
> if (get_verbosely)
> - fprintf(stderr, "Getting alternates list\n");
> + fprintf(stderr, "Getting alternates list for %s\n", base);
>
> url = xmalloc(strlen(base) + 31);
> sprintf(url, "%s/objects/info/http-alternates", base);
> @@ -918,7 +918,7 @@ static int fetch_indices(struct alt_base
> buffer.buffer = data;
>
> if (get_verbosely)
> - fprintf(stderr, "Getting pack list\n");
> + fprintf(stderr, "Getting pack list for %s\n", repo->base);
>
> url = xmalloc(strlen(repo->base) + 21);
> sprintf(url, "%s/objects/info/packs", repo->base);
By the way, this is only a pathetic remnant of my brave effort to get
rid of seeing the "Getting alternates list" message on the same
repository 20 times now since the parallel fetching got introduced.
I know how to do silence the messages, but doing the _fetching_ itself
seems as downright stupid thing in the first place.
Therefore, can I somehow stall fetching of an object? The idea is:
I want to check the alternates list!
I don't have it yet...
...but a request for it is already queued. Ok, I'll wait.
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.
^ permalink raw reply
* Re: Strange merge conflicts against earlier merge.
From: Junio C Hamano @ 2005-11-12 0:50 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0511111806070.25300@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
> On Fri, 11 Nov 2005, Junio C Hamano wrote:
>
>> Come to think of it, we should signal that we are punting by
>> either exiting non-zero, or stuffing 0{40} SHA1 in stage1, so
>> that we can distinguish the case with two sides adding things
>> differently. Daniel, what do you think?
>
> Probably don't want to exit non-zero, since we can deal with the rest of
> the paths sensibly. All 0 SHA1 would work, if we want to identify this
> case. On the other hand, I think the desired behavior at present is to
> tell the user to pick the correct version of the two, which is the same as
> if it's new in both sides, which is why I had it like that.
Yeah, and I have an updated merge-one-file in "pu" that tries to
do a bit more interesting thing than just punting and asking the
user, when both sides added different contents. I did not want
to trigger that logic when we are doing case #16, and that was
what my comment was about.
^ permalink raw reply
* [PATCH] Show URL in the "Getting <foo> list" http-fetch messages
From: Petr Baudis @ 2005-11-12 0:49 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Signed-off-by: Petr Baudis <pasky@suse.cz>
---
http-fetch.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/http-fetch.c b/http-fetch.c
index e7655d1..e6e7df6 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -795,7 +795,7 @@ static int fetch_alternates(char *base)
buffer.buffer = data;
if (get_verbosely)
- fprintf(stderr, "Getting alternates list\n");
+ fprintf(stderr, "Getting alternates list for %s\n", base);
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
@@ -918,7 +918,7 @@ static int fetch_indices(struct alt_base
buffer.buffer = data;
if (get_verbosely)
- fprintf(stderr, "Getting pack list\n");
+ fprintf(stderr, "Getting pack list for %s\n", repo->base);
url = xmalloc(strlen(repo->base) + 21);
sprintf(url, "%s/objects/info/packs", repo->base);
^ permalink raw reply related
* Re: Comments on recursive merge..
From: Junio C Hamano @ 2005-11-12 0:42 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0511111437410.3228@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> I actually don't think that is surprisingly high, and would actually have
> expected it to be closer to 50%.
>
> On the other hand, the merges that end up being pure fast-forwards aren't
> counted as merges at all (since they don't show up as commits), so maybe
> that's what skews my preception of a big percentage of merges as being
> really trivial.
That is what I meant by "it does not show just what you saw".
It shows the whole community experience by everybody who has
commit there. Being _the_ integration point, I imagine that
most of the pure fast-forwards you saw were real merges for
somebody else, and that merge being fast/safe/convenient
counts, not for you but for your subsystem people.
>> All three of these points together is a fine demonstration
>> that you designed git really right.
>
> Well, it's self-re-inforcing. It was designed for the kernel
> usage patterns, so using the kernel to confirm that it's the
> "right design" is a bit self-serving.
That is true. My point was that it's not like git was done
right only for _you_, sacrificing subsystem people. The sample
4k commits show that the assumption of the usage pattern git is
optimized for actually holds (commits being small, merges being
mostly trivial) for kernel people other than you.
It is yet to be seen if the same assumption holds for other
projects.
^ permalink raw reply
* [PATCH] Fix bunch of fd leaks in http-fetch
From: Petr Baudis @ 2005-11-11 23:55 UTC (permalink / raw)
To: Becky Bruce; +Cc: git
In-Reply-To: <dd9dee136a573d72fc7332373cfd8ac1@freescale.com>
Dear diary, on Fri, Nov 11, 2005 at 11:58:39PM CET, I got a letter
where Becky Bruce <becky.bruce@freescale.com> said that...
> I grabbed 0.99.9g this morning, and tried to clone Paul Mackerras'
> linux merge tree. The clone failed and reported errors in http-fetch
> with a bunch of messages of the form:
>
> error: Couldn't create temporary file
> .git/objects/04/48fa7de8a416a48cd1977f29858be54e67c078.temp for .git
> /objects/04/48fa7de8a416a48cd1977f29858be54e67c078: Error 24: Too many
> open files
---
The current http-fetch is rather careless about fd leakage, causing
problems while fetching large repositories. This patch does not reserve
exhaustiveness, but I covered everything I spotted. I also left some
safeguards in place in case I missed something, so that we get to know,
sooner or later.
Reported by Becky Bruce <becky.bruce@freescale.com>.
Signed-off-by: Petr Baudis <pasky@suse.cz>
---
http-fetch.c | 16 ++++++++++++++--
1 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/http-fetch.c b/http-fetch.c
index 99921cc..e7655d1 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -413,6 +413,8 @@ static void start_request(struct transfe
rename(request->tmpfile, prevfile);
unlink(request->tmpfile);
+ if (request->local != -1)
+ error("fd leakage in start: %d", request->local);
request->local = open(request->tmpfile,
O_WRONLY | O_CREAT | O_EXCL, 0666);
/* This could have failed due to the "lazy directory creation";
@@ -511,7 +513,7 @@ static void start_request(struct transfe
/* Try to get the request started, abort the request on error */
if (!start_active_slot(slot)) {
request->state = ABORTED;
- close(request->local);
+ close(request->local); request->local = -1;
free(request->url);
return;
}
@@ -525,7 +527,7 @@ static void finish_request(struct transf
struct stat st;
fchmod(request->local, 0444);
- close(request->local);
+ close(request->local); request->local = -1;
if (request->http_code == 416) {
fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
@@ -557,6 +559,8 @@ static void release_request(struct trans
{
struct transfer_request *entry = request_queue_head;
+ if (request->local != -1)
+ error("fd leakage in release: %d", request->local);
if (request == request_queue_head) {
request_queue_head = request->next;
} else {
@@ -613,6 +617,8 @@ static void process_curl_messages(void)
if (request->repo->next != NULL) {
request->repo =
request->repo->next;
+ close(request->local);
+ request->local = -1;
start_request(request);
}
} else {
@@ -743,6 +749,7 @@ static int fetch_index(struct alt_base *
curl_errorstr);
}
} else {
+ fclose(indexfile);
return error("Unable to start request");
}
@@ -1025,6 +1032,7 @@ static int fetch_pack(struct alt_base *r
curl_errorstr);
}
} else {
+ fclose(packfile);
return error("Unable to start request");
}
@@ -1087,6 +1095,7 @@ static int fetch_object(struct alt_base
fetch_alternates(alt->base);
if (request->repo->next != NULL) {
request->repo = request->repo->next;
+ close(request->local); request->local = -1;
start_request(request);
}
} else {
@@ -1095,6 +1104,9 @@ static int fetch_object(struct alt_base
}
#endif
}
+ if (request->local != -1) {
+ close(request->local); request->local = -1;
+ }
if (request->state == ABORTED) {
release_request(request);
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.
^ permalink raw reply related
* [PATCH 3/3] merge-recursive: Use '~' instead of '_' to separate file names from branch names
From: Fredrik Kuivinen @ 2005-11-11 23:55 UTC (permalink / raw)
To: git; +Cc: junkio
Makes it less probable that we get a clash with an existing file,
furthermore Cogito already uses '~' for this purpose.
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
---
git-merge-recursive.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
applies-to: cd30fe9db68f151066eeadd75eb2fdcb7ff89148
188d233dddacf754d1b7e8c7154293f9a4668180
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
index 21f1e92..1bf73f3 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -304,13 +304,13 @@ def uniquePath(path, branch):
raise
branch = branch.replace('/', '_')
- newPath = path + '_' + branch
+ newPath = path + '~' + branch
suffix = 0
while newPath in currentFileSet or \
newPath in currentDirectorySet or \
fileExists(newPath):
suffix += 1
- newPath = path + '_' + branch + '_' + str(suffix)
+ newPath = path + '~' + branch + '_' + str(suffix)
currentFileSet.add(newPath)
return newPath
---
0.99.9.GIT
^ permalink raw reply related
* [PATCH 2/3] merge-recursive: Add copyright notice
From: Fredrik Kuivinen @ 2005-11-11 23:54 UTC (permalink / raw)
To: git; +Cc: junkio
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
---
git-merge-recursive.py | 3 +++
gitMergeCommon.py | 4 ++++
2 files changed, 7 insertions(+), 0 deletions(-)
applies-to: ec5d71bfe5c1519652081888a49f36b1bd044975
eeffb2de39045197fe945959e7029ca146540353
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
index e6cbdde..21f1e92 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -1,4 +1,7 @@
#!/usr/bin/python
+#
+# Copyright (C) 2005 Fredrik Kuivinen
+#
import sys, math, random, os, re, signal, tempfile, stat, errno, traceback
from heapq import heappush, heappop
diff --git a/gitMergeCommon.py b/gitMergeCommon.py
index 1b5bddd..ff6f58a 100644
--- a/gitMergeCommon.py
+++ b/gitMergeCommon.py
@@ -1,3 +1,7 @@
+#
+# Copyright (C) 2005 Fredrik Kuivinen
+#
+
import sys, re, os, traceback
from sets import Set
---
0.99.9.GIT
^ permalink raw reply related
* [PATCH 1/3] merge-recursive: Indent the output properly
From: Fredrik Kuivinen @ 2005-11-11 23:53 UTC (permalink / raw)
To: git; +Cc: junkio
If we have multiple common ancestors and have to recursively merge
them then the output will be much more readable with this commit.
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
---
git-merge-recursive.py | 132 +++++++++++++++++++++++++-----------------------
1 files changed, 70 insertions(+), 62 deletions(-)
applies-to: 61d3c7b885a193afa970b5dd319d5264dcbd11ad
66f3f641939645d4f26849adfdc54f4f00cb72f1
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
index 90e889c..e6cbdde 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -7,6 +7,11 @@ from sets import Set
sys.path.append('''@@GIT_PYTHON_PATH@@''')
from gitMergeCommon import *
+outputIndent = 0
+def output(*args):
+ sys.stdout.write(' '*outputIndent)
+ printList(args)
+
originalIndexFile = os.environ.get('GIT_INDEX_FILE',
os.environ.get('GIT_DIR', '.git') + '/index')
temporaryIndexFile = os.environ.get('GIT_DIR', '.git') + \
@@ -41,27 +46,27 @@ def merge(h1, h2, branch1Name, branch2Na
assert(isinstance(h1, Commit) and isinstance(h2, Commit))
assert(isinstance(graph, Graph))
- def infoMsg(*args):
- sys.stdout.write(' '*callDepth)
- printList(args)
-
- infoMsg('Merging:')
- infoMsg(h1)
- infoMsg(h2)
+ global outputIndent
+
+ output('Merging:')
+ output(h1)
+ output(h2)
sys.stdout.flush()
ca = getCommonAncestors(graph, h1, h2)
- infoMsg('found', len(ca), 'common ancestor(s):')
+ output('found', len(ca), 'common ancestor(s):')
for x in ca:
- infoMsg(x)
+ output(x)
sys.stdout.flush()
mergedCA = ca[0]
for h in ca[1:]:
+ outputIndent = callDepth+1
[mergedCA, dummy] = merge(mergedCA, h,
- 'Temporary shared merge branch 1',
- 'Temporary shared merge branch 2',
+ 'Temporary merge branch 1',
+ 'Temporary merge branch 2',
graph, callDepth+1)
+ outputIndent = callDepth
assert(isinstance(mergedCA, Commit))
global cacheOnly
@@ -116,7 +121,7 @@ def mergeTrees(head, merge, common, bran
assert(isSha(head) and isSha(merge) and isSha(common))
if common == merge:
- print 'Already uptodate!'
+ output('Already uptodate!')
return [head, True]
if cacheOnly:
@@ -554,23 +559,24 @@ def processRenames(renamesA, renamesB, b
ren2.processed = True
if ren1.dstName != ren2.dstName:
- print 'CONFLICT (rename/rename): Rename', \
- fmtRename(path, ren1.dstName), 'in branch', branchName1, \
- 'rename', fmtRename(path, ren2.dstName), 'in', branchName2
+ output('CONFLICT (rename/rename): Rename',
+ fmtRename(path, ren1.dstName), 'in branch', branchName1,
+ 'rename', fmtRename(path, ren2.dstName), 'in',
+ branchName2)
cleanMerge = False
if ren1.dstName in currentDirectorySet:
dstName1 = uniquePath(ren1.dstName, branchName1)
- print ren1.dstName, 'is a directory in', branchName2, \
- 'adding as', dstName1, 'instead.'
+ output(ren1.dstName, 'is a directory in', branchName2,
+ 'adding as', dstName1, 'instead.')
removeFile(False, ren1.dstName)
else:
dstName1 = ren1.dstName
if ren2.dstName in currentDirectorySet:
dstName2 = uniquePath(ren2.dstName, branchName2)
- print ren2.dstName, 'is a directory in', branchName1, \
- 'adding as', dstName2, 'instead.'
+ output(ren2.dstName, 'is a directory in', branchName1,
+ 'adding as', dstName2, 'instead.')
removeFile(False, ren2.dstName)
else:
dstName2 = ren1.dstName
@@ -585,13 +591,14 @@ def processRenames(renamesA, renamesB, b
branchName1, branchName2)
if merge or not clean:
- print 'Renaming', fmtRename(path, ren1.dstName)
+ output('Renaming', fmtRename(path, ren1.dstName))
if merge:
- print 'Auto-merging', ren1.dstName
+ output('Auto-merging', ren1.dstName)
if not clean:
- print 'CONFLICT (content): merge conflict in', ren1.dstName
+ output('CONFLICT (content): merge conflict in',
+ ren1.dstName)
cleanMerge = False
if not cacheOnly:
@@ -615,25 +622,25 @@ def processRenames(renamesA, renamesB, b
if ren1.dstName in currentDirectorySet:
newPath = uniquePath(ren1.dstName, branchName1)
- print 'CONFLICT (rename/directory): Rename', \
- fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,\
- 'directory', ren1.dstName, 'added in', branchName2
- print 'Renaming', ren1.srcName, 'to', newPath, 'instead'
+ output('CONFLICT (rename/directory): Rename',
+ fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,
+ 'directory', ren1.dstName, 'added in', branchName2)
+ output('Renaming', ren1.srcName, 'to', newPath, 'instead')
cleanMerge = False
removeFile(False, ren1.dstName)
updateFile(False, ren1.dstSha, ren1.dstMode, newPath)
elif srcShaOtherBranch == None:
- print 'CONFLICT (rename/delete): Rename', \
- fmtRename(ren1.srcName, ren1.dstName), 'in', \
- branchName1, 'and deleted in', branchName2
+ output('CONFLICT (rename/delete): Rename',
+ fmtRename(ren1.srcName, ren1.dstName), 'in',
+ branchName1, 'and deleted in', branchName2)
cleanMerge = False
updateFile(False, ren1.dstSha, ren1.dstMode, ren1.dstName)
elif dstShaOtherBranch:
newPath = uniquePath(ren1.dstName, branchName2)
- print 'CONFLICT (rename/add): Rename', \
- fmtRename(ren1.srcName, ren1.dstName), 'in', \
- branchName1 + '.', ren1.dstName, 'added in', branchName2
- print 'Adding as', newPath, 'instead'
+ output('CONFLICT (rename/add): Rename',
+ fmtRename(ren1.srcName, ren1.dstName), 'in',
+ branchName1 + '.', ren1.dstName, 'added in', branchName2)
+ output('Adding as', newPath, 'instead')
updateFile(False, dstShaOtherBranch, dstModeOtherBranch, newPath)
cleanMerge = False
tryMerge = True
@@ -641,12 +648,12 @@ def processRenames(renamesA, renamesB, b
dst2 = renames2.getDst(ren1.dstName)
newPath1 = uniquePath(ren1.dstName, branchName1)
newPath2 = uniquePath(dst2.dstName, branchName2)
- print 'CONFLICT (rename/rename): Rename', \
- fmtRename(ren1.srcName, ren1.dstName), 'in', \
- branchName1+'. Rename', \
- fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2
- print 'Renaming', ren1.srcName, 'to', newPath1, 'and', \
- dst2.srcName, 'to', newPath2, 'instead'
+ output('CONFLICT (rename/rename): Rename',
+ fmtRename(ren1.srcName, ren1.dstName), 'in',
+ branchName1+'. Rename',
+ fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2)
+ output('Renaming', ren1.srcName, 'to', newPath1, 'and',
+ dst2.srcName, 'to', newPath2, 'instead')
removeFile(False, ren1.dstName)
updateFile(False, ren1.dstSha, ren1.dstMode, newPath1)
updateFile(False, dst2.dstSha, dst2.dstMode, newPath2)
@@ -663,13 +670,14 @@ def processRenames(renamesA, renamesB, b
branchName1, branchName2)
if merge or not clean:
- print 'Renaming', fmtRename(ren1.srcName, ren1.dstName)
+ output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
if merge:
- print 'Auto-merging', ren1.dstName
+ output('Auto-merging', ren1.dstName)
if not clean:
- print 'CONFLICT (rename/modify): Merge conflict in', ren1.dstName
+ output('CONFLICT (rename/modify): Merge conflict in',
+ ren1.dstName)
cleanMerge = False
if not cacheOnly:
@@ -714,21 +722,21 @@ def processEntry(entry, branch1Name, bra
(not aSha and bSha == oSha):
# Deleted in both or deleted in one and unchanged in the other
if aSha:
- print 'Removing', path
+ output('Removing', path)
removeFile(True, path)
else:
# Deleted in one and changed in the other
cleanMerge = False
if not aSha:
- print 'CONFLICT (delete/modify):', path, 'deleted in', \
- branch1Name, 'and modified in', branch2Name + '.', \
- 'Version', branch2Name, 'of', path, 'left in tree.'
+ output('CONFLICT (delete/modify):', path, 'deleted in',
+ branch1Name, 'and modified in', branch2Name + '.',
+ 'Version', branch2Name, 'of', path, 'left in tree.')
mode = bMode
sha = bSha
else:
- print 'CONFLICT (modify/delete):', path, 'deleted in', \
- branch2Name, 'and modified in', branch1Name + '.', \
- 'Version', branch1Name, 'of', path, 'left in tree.'
+ output('CONFLICT (modify/delete):', path, 'deleted in',
+ branch2Name, 'and modified in', branch1Name + '.',
+ 'Version', branch1Name, 'of', path, 'left in tree.')
mode = aMode
sha = aSha
@@ -755,14 +763,14 @@ def processEntry(entry, branch1Name, bra
if path in currentDirectorySet:
cleanMerge = False
newPath = uniquePath(path, addBranch)
- print 'CONFLICT (' + conf + '):', \
- 'There is a directory with name', path, 'in', \
- otherBranch + '. Adding', path, 'as', newPath
+ output('CONFLICT (' + conf + '):',
+ 'There is a directory with name', path, 'in',
+ otherBranch + '. Adding', path, 'as', newPath)
removeFile(False, path)
updateFile(False, sha, mode, newPath)
else:
- print 'Adding', path
+ output('Adding', path)
updateFile(True, sha, mode, path)
elif not oSha and aSha and bSha:
@@ -772,10 +780,10 @@ def processEntry(entry, branch1Name, bra
if aSha == bSha:
if aMode != bMode:
cleanMerge = False
- print 'CONFLICT: File', path, \
- 'added identically in both branches, but permissions', \
- 'conflict', '0%o' % aMode, '->', '0%o' % bMode
- print 'CONFLICT: adding with permission:', '0%o' % aMode
+ output('CONFLICT: File', path,
+ 'added identically in both branches, but permissions',
+ 'conflict', '0%o' % aMode, '->', '0%o' % bMode)
+ output('CONFLICT: adding with permission:', '0%o' % aMode)
updateFile(False, aSha, aMode, path)
else:
@@ -785,9 +793,9 @@ def processEntry(entry, branch1Name, bra
cleanMerge = False
newPath1 = uniquePath(path, branch1Name)
newPath2 = uniquePath(path, branch2Name)
- print 'CONFLICT (add/add): File', path, \
- 'added non-identically in both branches. Adding as', \
- newPath1, 'and', newPath2, 'instead.'
+ output('CONFLICT (add/add): File', path,
+ 'added non-identically in both branches. Adding as',
+ newPath1, 'and', newPath2, 'instead.')
removeFile(False, path)
updateFile(False, aSha, aMode, newPath1)
updateFile(False, bSha, bMode, newPath2)
@@ -796,7 +804,7 @@ def processEntry(entry, branch1Name, bra
#
# case D: Modified in both, but differently.
#
- print 'Auto-merging', path
+ output('Auto-merging', path)
[sha, mode, clean, dummy] = \
mergeFile(path, oSha, oMode,
path, aSha, aMode,
@@ -806,7 +814,7 @@ def processEntry(entry, branch1Name, bra
updateFile(True, sha, mode, path)
else:
cleanMerge = False
- print 'CONFLICT (content): Merge conflict in', path
+ output('CONFLICT (content): Merge conflict in', path)
if cacheOnly:
updateFile(False, sha, mode, path)
---
0.99.9.GIT
^ permalink raw reply related
* Re: Strange merge conflicts against earlier merge.
From: Daniel Barkalow @ 2005-11-11 23:33 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Petr Baudis, git
In-Reply-To: <7vy83ukdwf.fsf@assigned-by-dhcp.cox.net>
On Fri, 11 Nov 2005, Junio C Hamano wrote:
> Petr Baudis <pasky@ucw.cz> writes:
>
> > 16 anc1/anc2 anc1 anc2 no merge
> >
> > What ends up in the index at this moment as "stage 1"? anc1? anc2?
> > Two stage 1 entries? And what does git-merge-index do about this?
>
> I think we decided there is no single sensible resolution, and
> we leave stage 1 empty.
>
> Come to think of it, we should signal that we are punting by
> either exiting non-zero, or stuffing 0{40} SHA1 in stage1, so
> that we can distinguish the case with two sides adding things
> differently. Daniel, what do you think?
Probably don't want to exit non-zero, since we can deal with the rest of
the paths sensibly. All 0 SHA1 would work, if we want to identify this
case. On the other hand, I think the desired behavior at present is to
tell the user to pick the correct version of the two, which is the same as
if it's new in both sides, which is why I had it like that.
Someday, we ought to do a combined merge-base and read-tree, which would
be able to correctly handle revert wars, but it's too very exciting
currently, since the multi-base merge cases have generally turned out to
be user error (i.e., the user didn't actually mean to merge those things).
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: git-archimport
From: Kevin Geiss @ 2005-11-11 23:24 UTC (permalink / raw)
To: Martin Langhoff; +Cc: Kevin Geiss, git
In-Reply-To: <46a038f90511102158k5078e37fn2558cf69bc5794fa@mail.gmail.com>
it's not really public, perhaps I can make it public though. can a tla mirror
be served over http? or does it require ssh?
I'm confident the gpg signatures aren't the problem. I imported some branches
yesterday which were all signed, they worked fine.
I suspuect the problem is that after tagging the oco branch from the base
branch, there are several places where I replayed some patches from one of the
branches to the other. some patches were skipped, some were replayed. there
was definitely a lot of hard core cherry picking going on, in both directions.
do you think that would cause a problem?
the branches I've imported successfully were things where I had version 1, then
tagged that to create version 2, then tagged that to create version 3, with no
replay or merging going on between the branches. (everything was gpg signed
though)
On Fri, Nov 11, 2005 at 06:58:34PM +1300, Martin Langhoff wrote:
> On 11/11/05, Kevin Geiss <kevin@desertsol.com> wrote:
> > gpg: Signature made Mon Feb 14 12:28:10 2005 MST using DSA key ID E1E6A3B1
>
> I've never imported a signed changeset, perhaps that's the problem. Is
> the repo public so I can test it myself?
>
> cheers,
>
> martin
>
^ permalink raw reply
* Re: file descriptor leak? or expected behavior?
From: Becky Bruce @ 2005-11-11 23:22 UTC (permalink / raw)
To: Becky Bruce; +Cc: git
In-Reply-To: <dd9dee136a573d72fc7332373cfd8ac1@freescale.com>
On Nov 11, 2005, at 4:58 PM, Becky Bruce wrote:
>
> error: Couldn't create temporary file
> .git/objects/04/48fa7de8a416a48cd1977f29858be54e67c078.temp for .git
> /objects/04/48fa7de8a416a48cd1977f29858be54e67c078: Error 24: Too many
> open files
By the way, in case this looks funny to anyone, this isn't the default
message - I added the "Error 24" part because I'm used to looking at
error numbers.
This is what the message looks like from an unmodified git:
error: Couldn't create temporary file
.git/objects/a0/7e2c9307fa338896ecca300dc88033a8922885.temp for
.git/objects/a0/7e2c9307fa338896ecca300dc88033a8922885: Too many open
files
Cheers,
B
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox