Git development
 help / color / mirror / Atom feed
* [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

* file descriptor leak? or expected behavior?
From: Becky Bruce @ 2005-11-11 22:58 UTC (permalink / raw)
  To: git

Folks,

My apologies if this is a known issue/question - I've searched the list 
and haven't found anything about this, but given the volume of traffic, 
it's easy to miss things.....

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

I did some experimenting, and it looks like this crops up somewhere 
between git versions  0.99.8f and 0.99.9a.  My question is, is git 
expected to try to open huge numbers of files, or is this a fd leak? I 
cranked up my ulimit, and am still unable to successfully clone this 
tree, although it fails differently (tail end of output....):

progress: 22 objects, 56146 bytes
Also look at 
http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/
Getting pack list
error: The requested URL returned error: 404
Getting pack list
Getting index for pack e0d76ffe354ef5665028a6cb4506ea902f72e1d0
Getting pack e0d76ffe354ef5665028a6cb4506ea902f72e1d0
which contains 5014bfa48ac169e0748e1e9651897788feb306dc
progress: 1322 objects, 5736795 bytes
cg-fetch: objects fetch failed
cg-clone: fetch failed


The command I ran, and the tree I tried to clone are:

 > cg-clone 
http://www.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge.git 
linux-2.6.paul

Cheers,
-B

^ permalink raw reply

* Re: Comments on recursive merge..
From: Linus Torvalds @ 2005-11-11 22:53 UTC (permalink / raw)
  To: Junio C Hamano, Paul Mackerras; +Cc: Git Mailing List
In-Reply-To: <7v4q6ilt3m.fsf@assigned-by-dhcp.cox.net>



On Fri, 11 Nov 2005, Junio C Hamano wrote:
> 
> Some observations.
> 
>  - Trivial Merges count is surprisingly high.  About 1/3 of
>    merges are pure in-index merges.

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.

>  - Most of the commits (developer commits, not merges) are
>    small and touches only a couple of paths.

This is something where I think the kernel is perhaps unusual, especially 
for a big project. We really do encourage people to make lots of small and 
well-defined changes, and the whole flow of development has been geared 
towards it. 

>  - Nobody does octopus ;-).

I do think octopus is really cool, and still think seeing that five-way 
octopus-merge in gitk in the git history was really really cool.

It doesn't look as good any more, btw: do "gitk" on the current git tree, 
and search for "Octopus merge", and you'll see some of the history lines 
crossing each other. Paul?

But yeah, it's a pretty special thing. I think its coolness factor way 
outweighs its usefullness factor ;^p

>  - We did not have multi-base merge case during the period
>    looked at (but the sample count is very low).

Again, this is possibly because the kernel has already had a few years of 
distributed SCM usage under its belt, and we've tried to not only merge 
in a timely manner, but also try to keep history reasonably clean and not 
have a lot of cross-merging back and forth. That cuts down on multi-base 
possibilities.

>  - merge-one-file was called for only a handful (median 8)
>    files, which is negligibly small compared to the total 17K
>    files in the kernel tree, and fairly small compared to the
>    number of changed paths from the first parent (meaning,
>    read-tree trivial collapsing helped majorly).  Among them,
>    the number of paths that needed real file-level 3-way merges
>    were even smaller (avg 1.96).

I definitely think this is true for any big project.

Small projects will inevitably have changes that modify large portions of 
the source base. But with small projects, it doesn't really matter _what_ 
you do, you can do it fast.

Big projects (at least the sane kind) will never have lots of changes that 
modify a very big percentage of the source-tree. It's just too painful 
(and I'm not talking from a SCM angle, just from a developer angle).

>    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. Sure, it's a good sign that my mental model of what the 
usage patters are does actually match reality, but at the same time it 
might be more interesting to see if other projects that use git end up 
using it the same way and/or have different statistics.

I do expect that the size of the project will impact the statistics a lot. 

		Linus

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox