Code

Merge branches 'jc/apply', 'lt/ls-tree', 'lt/bisect' and 'lt/merge'
authorJunio C Hamano <junkio@cox.net>
Wed, 30 Nov 2005 19:05:48 +0000 (11:05 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 30 Nov 2005 19:05:48 +0000 (11:05 -0800)
24 files changed:
Documentation/git-diff-files.txt
Documentation/git-svnimport.txt
Documentation/pull-fetch-param.txt
Documentation/tutorial.txt
diff-files.c
git-applymbox.sh
git-applypatch.sh
git-clone.sh
git-diff.sh
git-format-patch.sh
git-merge-one-file.sh
git-merge-recursive.py
git-mv.perl
git-svnimport.perl
gitk
http-push.c
ls-tree.c
setup.c
t/t0000-basic.sh
t/t3100-ls-tree-restrict.sh
t/t3101-ls-tree-dirname.sh
t/t7001-mv.sh [new file with mode: 0755]
tree.c
tree.h

index 3b04bfeec6ad18edffd9b6d44709a10fdda36b8c..67f51265e6aeadf85db582fe89c2c5752b36745a 100644 (file)
@@ -21,6 +21,15 @@ OPTIONS
 -------
 include::diff-options.txt[]
 
+-1 -2 -3 or --base --ours --theirs, and -0::
+       Diff against the "base" version, "our branch" or "their
+       branch" respectively.  With these options, diffs for
+       merged entries are not shown.
++
+The default is to diff against our branch (-2) and the 
+cleanly resolved paths.  The option -0 can be given to
+omit diff output for unmerged entries and just show "Unmerged".
+
 -q::
        Remain silent even on nonexisting files
 
index fcc79fa93a18444e5df42bc9e98bb18fe4b55ce5..f8dbee70961f932e1c2be29bd11d862d9b1c002c 100644 (file)
@@ -10,7 +10,7 @@ git-svnimport - Import a SVN repository into git
 SYNOPSIS
 --------
 'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ]
-                       [ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_nr_changes]
+                       [ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
                        [ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ]
                        [ -s start_chg ] [ -m ] [ -M regex ]
                        <SVN_repository_URL> [ <path> ]
@@ -71,14 +71,11 @@ When importing incementally, you might need to edit the .git/svn2git file.
        regex. It can be used with -m to also see the default regexes.
        You must escape forward slashes.
 
--l <max_num_changes>::
-       Limit the number of SVN changesets we pull before quitting.
-       This option is necessary because the SVN library has serious memory
-       leaks; the recommended value for nontrivial imports is 100.
+-l <max_rev>::
+       Specify a maximum revision number to pull.
 
-       git-svnimport will still exit with a zero exit code. You can check
-       the size of the file ".git/svn2git" to determine whether to call
-       the importer again.
+       Formerly, this option controlled how many revisions to pull, due to
+       SVN memory leaks. (These have been worked around.)
 
 -v::
        Verbosity: let 'svnimport' report what it is doing.
index 6413d525ce1d7fa046f81b1d31c6e8ca3b2dbecb..b5b979242ca809d121ef10826ab083159ea2195c 100644 (file)
 - ssh://host.xz/~/path/to/repo.git
 ===============================================================
 +
-       SSH Is the default transport protocol and also supports an
-       scp-like syntax.  Both syntaxes support username expansion,
-       as does the native git protocol. The following three are
-       identical to the last three above, respectively:
+SSH Is the default transport protocol and also supports an
+scp-like syntax.  Both syntaxes support username expansion,
+as does the native git protocol. The following three are
+identical to the last three above, respectively:
 +
 ===============================================================
 - host.xz:/path/to/repo.git/
@@ -26,8 +26,8 @@
 - host.xz:path/to/repo.git
 ===============================================================
 +
-       To sync with a local directory, use:
-
+To sync with a local directory, use:
++
 ===============================================================
 - /path/to/repo.git/
 ===============================================================
@@ -113,7 +113,7 @@ on the remote branch, merge it into your development branch with
 `git pull . remote-B`, while you are on `my-B` branch.
 The common `Pull: master:origin` mapping of a remote `master`
 branch to a local `origin` branch, which is then merged to a
-ocal development branch, again typically named `master`, is made
+local development branch, again typically named `master`, is made
 when you run `git clone` for you to follow this pattern.
 +
 [NOTE]
index e2dfb00ab10de601204715e4b244420a0a2cb7c8..cf7ba76ddfb76b4e92b71474a3386d0573820ac5 100644 (file)
@@ -898,9 +898,8 @@ file, which had no differences in the `mybranch` branch), and say:
        fatal: Merge requires file-level merging
        Nope.
        ...
-       merge: warning: conflicts during merge
-       ERROR: Merge conflict in hello.
-       fatal: merge program failed
+       Auto-merging hello 
+       CONFLICT (content): Merge conflict in hello 
        Automatic merge failed/prevented; fix up by hand
 ----------------
 
@@ -942,10 +941,10 @@ environment, is `git show-branch`.
 
 ------------------------------------------------
 $ git show-branch master mybranch
-* [master] Merged "mybranch" changes.
+* [master] Merge work in mybranch
  ! [mybranch] Some work.
 --
-+  [master] Merged "mybranch" changes.
++  [master] Merge work in mybranch
 ++ [mybranch] Some work.
 ------------------------------------------------
 
@@ -998,10 +997,10 @@ looks like, or run `show-branch`, which tells you this.
 
 ------------------------------------------------
 $ git show-branch master mybranch
-! [master] Merged "mybranch" changes.
- * [mybranch] Merged "mybranch" changes.
+! [master] Merge work in mybranch
+ * [mybranch] Merge work in mybranch
 --
-++ [master] Merged "mybranch" changes.
+++ [master] Merge work in mybranch
 ------------------------------------------------
 
 
index 38599b5b755df431e3e061df8a304698cc4496fc..6c0696c34f0af95acbfe06f644f7df7fb1e93509 100644 (file)
@@ -7,12 +7,12 @@
 #include "diff.h"
 
 static const char diff_files_usage[] =
-"git-diff-files [-q] "
-"[<common diff options>] [<path>...]"
+"git-diff-files [-q] [-0/-1/2/3] [<common diff options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 static struct diff_options diff_options;
 static int silent = 0;
+static int diff_unmerged_stage = 2;
 
 static void show_unmerge(const char *path)
 {
@@ -46,7 +46,21 @@ int main(int argc, const char **argv)
                        argc--;
                        break;
                }
-               if (!strcmp(argv[1], "-q"))
+               if (!strcmp(argv[1], "-0"))
+                       diff_unmerged_stage = 0;
+               else if (!strcmp(argv[1], "-1"))
+                       diff_unmerged_stage = 1;
+               else if (!strcmp(argv[1], "-2"))
+                       diff_unmerged_stage = 2;
+               else if (!strcmp(argv[1], "-3"))
+                       diff_unmerged_stage = 3;
+               else if (!strcmp(argv[1], "--base"))
+                       diff_unmerged_stage = 1;
+               else if (!strcmp(argv[1], "--ours"))
+                       diff_unmerged_stage = 2;
+               else if (!strcmp(argv[1], "--theirs"))
+                       diff_unmerged_stage = 3;
+               else if (!strcmp(argv[1], "-q"))
                        silent = 1;
                else if (!strcmp(argv[1], "-r"))
                        ; /* no-op */
@@ -95,11 +109,26 @@ int main(int argc, const char **argv)
 
                if (ce_stage(ce)) {
                        show_unmerge(ce->name);
-                       while (i < entries &&
-                              !strcmp(ce->name, active_cache[i]->name))
+                       while (i < entries) {
+                               struct cache_entry *nce = active_cache[i];
+
+                               if (strcmp(ce->name, nce->name))
+                                       break;
+                               /* diff against the proper unmerged stage */
+                               if (ce_stage(nce) == diff_unmerged_stage)
+                                       ce = nce;
                                i++;
-                       i--; /* compensate for loop control increments */
-                       continue;
+                       }
+                       /*
+                        * Compensate for loop update
+                        */
+                       i--;
+                       /*
+                        * Show the diff for the 'ce' if we found the one
+                        * from the desired stage.
+                        */
+                       if (ce_stage(ce) != diff_unmerged_stage)
+                               continue;
                }
 
                if (lstat(ce->name, &st) < 0) {
index 24d4a8cb4eb95a5201c205be879d3ac6a62a8a15..c686cc8d27a64998c141cca2989375910601f90f 100755 (executable)
@@ -33,7 +33,7 @@ do
        -k)     keep_subject=-k ;;
        -q)     query_apply=t ;;
        -c)     continue="$2"; resume=f; shift ;;
-       -m)     fallback_3way=t ;;
+       -m)     fall_back_3way=t ;;
        -*)     usage ;;
        *)      break ;;
        esac
index f0549960fbd706f06fff5b2c602450917505a1ad..4c577eb835b877dd0766edbc5a603ee4e3db049a 100755 (executable)
@@ -120,26 +120,36 @@ git-apply --index "$PATCHFILE" || {
        O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
        rm -fr .patch-merge-*
 
+       if git-apply -z --index-info "$PATCHFILE" \
+               >.patch-merge-index-info 2>/dev/null &&
+               GIT_INDEX_FILE=.patch-merge-tmp-index \
+               git-update-index -z --index-info <.patch-merge-index-info &&
+               GIT_INDEX_FILE=.patch-merge-tmp-index \
+               git-write-tree >.patch-merge-tmp-base &&
+               (
+                       mkdir .patch-merge-tmp-dir &&
+                       cd .patch-merge-tmp-dir &&
+                       GIT_INDEX_FILE="../.patch-merge-tmp-index" \
+                       GIT_OBJECT_DIRECTORY="$O_OBJECT" \
+                       git-apply $binary --index
+               ) <"$PATCHFILE"
+       then
+               echo Using index info to reconstruct a base tree...
+               mv .patch-merge-tmp-base .patch-merge-base
+               mv .patch-merge-tmp-index .patch-merge-index
+       else
        (
                N=10
 
-               # if the patch records the base tree...
-               sed -ne '
-                       /^diff /q
-                       /^applies-to: \([0-9a-f]*\)$/{
-                               s//\1/p
-                               q
-                       }
-               ' "$PATCHFILE"
-
-               # or hoping the patch is against our recent commits...
+               # Otherwise, try nearby trees that can be used to apply the
+               # patch.
                git-rev-list --max-count=$N HEAD
 
                # or hoping the patch is against known tags...
                git-ls-remote --tags .
        ) |
-       while read base junk
-       do
+           while read base junk
+           do
                # Try it if we have it as a tree.
                git-cat-file tree "$base" >/dev/null 2>&1 || continue
 
@@ -155,7 +165,8 @@ git-apply --index "$PATCHFILE" || {
                        mv ../.patch-merge-tmp-index ../.patch-merge-index &&
                        echo "$base" >../.patch-merge-base
                ) <"$PATCHFILE"  2>/dev/null && break
-       done
+           done
+       fi
 
        test -f .patch-merge-index &&
        his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
index c09979a7a49e36b35e333b902cb0e0d689b693f4..699205eb6644aeb8668aa56abddf4f00d9af2642 100755 (executable)
@@ -73,7 +73,7 @@ while
        *,-n) no_checkout=yes ;;
        *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
-          local_shared=yes ;;
+          local_shared=yes; use_local=yes ;;
        *,-q|*,--quiet) quiet=-q ;;
        1,-u|1,--upload-pack) usage ;;
        *,-u|*,--upload-pack)
index b3ec84be698311b30e8c7c793873e6caa41daf71..7baf7044e440e6d052f5e92e1008f710dd319c67 100755 (executable)
@@ -7,8 +7,6 @@ rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
 flags=$(git-rev-parse --no-revs --flags --sq "$@")
 files=$(git-rev-parse --no-revs --no-flags --sq "$@")
 
-: ${flags:="'-M' '-p'"}
-
 # I often say 'git diff --cached -p' and get scolded by git-diff-files, but
 # obviously I mean 'git diff --cached -p HEAD' in that case.
 case "$rev" in
@@ -20,6 +18,21 @@ case "$rev" in
        esac
 esac
 
+# If we do not have --name-status, --name-only nor -r, default to -p.
+# If we do not have -B nor -C, default to -M.
+case " $flags " in
+*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* )
+       ;;
+*)
+       flags="$flags'-p' " ;;
+esac
+case " $flags " in
+*" '-"[BCM]* | *" '--find-copies-harder' "*)
+       ;; # something like -M50.
+*)
+       flags="$flags'-M' " ;;
+esac
+
 case "$rev" in
 ?*' '?*' '?*)
        echo >&2 "I don't understand"
index 9b4088045a5d53ceb1b893e5f6bda575518d36c1..1eebe857c021495b92d9e39ec1193b85ab4e980e 100755 (executable)
@@ -5,6 +5,10 @@
 
 . git-sh-setup
 
+# Force diff to run in C locale.
+LANG=C LC_ALL=C
+export LANG LC_ALL
+
 usage () {
     echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
     [--check] [--signoff] [-<diff options>...]
@@ -202,7 +206,7 @@ process_one () {
            ;;
        esac
 
-       eval "$(LANG=C LC_ALL=C sed -ne "$whosepatchScript" $commsg)"
+       eval "$(sed -ne "$whosepatchScript" $commsg)"
        test "$author,$au" = ",$me" || {
                mailScript="$mailScript"'
        a\
@@ -238,9 +242,8 @@ Date: '"$ad"
        echo
        git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
        echo
-       git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
        git-diff-tree -p $diff_opts "$commit"
-       echo "---"
+       echo "-- "
        echo "@@GIT_VERSION@@"
 
        case "$mbox" in
index c3eca8b3321df8dbf632fb687003737d8989d6f6..739a07292afad6baf5b0a34ff1405eb2c90f5825 100755 (executable)
@@ -79,11 +79,7 @@ case "${1:-.}${2:-.}${3:-.}" in
                ;;
        esac
 
-       # We reset the index to the first branch, making
-       # git-diff-file useful
-       git-update-index --add --cacheinfo "$6" "$2" "$4"
-               git-checkout-index -u -f -- "$4" &&
-               merge "$4" "$orig" "$src2"
+       merge "$4" "$orig" "$src2"
        ret=$?
        rm -f -- "$orig" "$src2"
 
index 01292335509bfd1460e12e0e1d86c4fcd1f265a4..e599b11cc57ecd0219d39fbfc8141fa5455755bf 100755 (executable)
@@ -828,8 +828,6 @@ def processEntry(entry, branch1Name, branch2Name):
             if cacheOnly:
                 updateFile(False, sha, mode, path)
             else:
-                updateFileExt(aSha, aMode, path,
-                              updateCache=True, updateWd=False)
                 updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
     else:
         die("ERROR: Fatal merge failure, shouldn't happen.")
index 53046bafd66ebc4c3a7ef5c65a6363ef5201dcdd..b6c0b4881845bf6a8d9681817fc540a2003b889e 100755 (executable)
@@ -19,15 +19,9 @@ EOT
        exit(1);
 }
 
-# Sanity checks:
-my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
-
-unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" && 
-       -d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
-    print "Error: git repository not found.";
-    exit(1);
-}
-
+my $GIT_DIR = `git rev-parse --git-dir`;
+exit 1 if $?; # rev-parse would have given "not a git dir" message.
+chomp($GIT_DIR);
 
 our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
 getopts("hnfkv") || usage;
index 45d77c5bae9c055641c416676c1d783c73fc28bb..65868a91e5f88c41942da89b84f169ed4264615d 100755 (executable)
@@ -35,7 +35,7 @@ our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b
 sub usage() {
        print STDERR <<END;
 Usage: ${\basename $0}     # fetch/update GIT from SVN
-       [-o branch-for-HEAD] [-h] [-v] [-l max_num_changes]
+       [-o branch-for-HEAD] [-h] [-v] [-l max_rev]
        [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
        [-d|-D] [-i] [-u] [-s start_chg] [-m] [-M regex] [SVN_URL]
 END
@@ -126,8 +126,9 @@ sub file {
 package main;
 use URI;
 
-my $svn = $svn_url;
+our $svn = $svn_url;
 $svn .= "/$svn_dir" if defined $svn_dir;
+my $svn2 = SVNconn->new($svn);
 $svn = SVNconn->new($svn);
 
 my $lwp_ua;
@@ -198,7 +199,7 @@ $ENV{GIT_INDEX_FILE} = $git_index;
 my $maxnum = 0;
 my $last_rev = "";
 my $last_branch;
-my $current_rev = $opt_s-1;
+my $current_rev = $opt_s || 1;
 unless(-d $git_dir) {
        system("git-init-db");
        die "Cannot init the GIT db at $git_tree: $?\n" if $?;
@@ -254,7 +255,7 @@ EOM
                my($num,$branch,$ref) = split;
                $branches{$branch}{$num} = $ref;
                $branches{$branch}{"LAST"} = $ref;
-               $current_rev = $num if $current_rev < $num;
+               $current_rev = $num+1 if $current_rev <= $num;
        }
        close($B);
 }
@@ -708,17 +709,17 @@ sub commit {
        print "DONE: $revision $dest $cid\n" if $opt_v;
 }
 
-my ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
-sub _commit_all {
-       ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
+sub commit_all {
+       # Recursive use of the SVN connection does not work
+       local $svn = $svn2;
+
+       my ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
        my %p;
        while(my($path,$action) = each %$changed_paths) {
                $p{$path} = [ $action->action,$action->copyfrom_path, $action->copyfrom_rev, $path ];
        }
        $changed_paths = \%p;
-}
 
-sub commit_all {
        my %done;
        my @col;
        my $pref;
@@ -734,18 +735,12 @@ sub commit_all {
        }
 }
 
-while(++$current_rev <= $svn->{'maxrev'}) {
-       if (defined $opt_l) {
-               $opt_l--;
-               if ($opt_l < 0) {
-                       last;
-               }
-       }
-       my $pool=SVN::Pool->new;
-       $svn->{'svn'}->get_log("/",$current_rev,$current_rev,1,1,1,\&_commit_all,$pool);
-       $pool->clear;
-       commit_all();
-}
+$opt_l = $svn->{'maxrev'} if not defined $opt_l or $opt_l > $svn->{'maxrev'};
+print "Fetching from $current_rev to $opt_l ...\n" if $opt_v;
+
+my $pool=SVN::Pool->new;
+$svn->{'svn'}->get_log("/",$current_rev,$opt_l,0,1,1,\&commit_all,$pool);
+$pool->clear;
 
 
 unlink($git_index);
diff --git a/gitk b/gitk
index 730ffd9202cdced9e7fbe3e466a547f402694ac0..a847ef69c7ae87c9035aff23af359e1832abceea 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -297,13 +297,16 @@ proc makewindow {} {
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
-    global rowctxmenu gaudydiff mergemax
+    global rowctxmenu mergemax
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
+    menu .bar.edit
+    .bar add cascade -label "Edit" -menu .bar.edit
+    .bar.edit add command -label "Preferences" -command doprefs
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.help add command -label "About gitk" -command about
@@ -414,25 +417,19 @@ proc makewindow {} {
     .ctop.cdet add .ctop.cdet.left
 
     $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
-    if {$gaudydiff} {
-       $ctext tag conf hunksep -back blue -fore white
-       $ctext tag conf d0 -back "#ff8080"
-       $ctext tag conf d1 -back green
-    } else {
-       $ctext tag conf hunksep -fore blue
-       $ctext tag conf d0 -fore red
-       $ctext tag conf d1 -fore "#00a000"
-       $ctext tag conf m0 -fore red
-       $ctext tag conf m1 -fore blue
-       $ctext tag conf m2 -fore green
-       $ctext tag conf m3 -fore purple
-       $ctext tag conf m4 -fore brown
-       $ctext tag conf mmax -fore darkgrey
-       set mergemax 5
-       $ctext tag conf mresult -font [concat $textfont bold]
-       $ctext tag conf msep -font [concat $textfont bold]
-       $ctext tag conf found -back yellow
-    }
+    $ctext tag conf hunksep -fore blue
+    $ctext tag conf d0 -fore red
+    $ctext tag conf d1 -fore "#00a000"
+    $ctext tag conf m0 -fore red
+    $ctext tag conf m1 -fore blue
+    $ctext tag conf m2 -fore green
+    $ctext tag conf m3 -fore purple
+    $ctext tag conf m4 -fore brown
+    $ctext tag conf mmax -fore darkgrey
+    set mergemax 5
+    $ctext tag conf mresult -font [concat $textfont bold]
+    $ctext tag conf msep -font [concat $textfont bold]
+    $ctext tag conf found -back yellow
 
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
@@ -533,7 +530,7 @@ proc click {w} {
 
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
-    global stuffsaved findmergefiles gaudydiff maxgraphpct
+    global stuffsaved findmergefiles maxgraphpct
     global maxwidth
 
     if {$stuffsaved} return
@@ -543,7 +540,6 @@ proc savestuff {w} {
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
        puts $f [list set findmergefiles $findmergefiles]
-       puts $f [list set gaudydiff $gaudydiff]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
        puts $f "set geometry(width) [winfo width .ctop]"
@@ -2841,7 +2837,6 @@ proc getblobdiffline {bdf ids} {
     global diffids blobdifffd ctext curdifftag curtagstart
     global diffnexthead diffnextnote difffilestart
     global nextupdate diffinhdr treediffs
-    global gaudydiff
 
     set n [gets $bdf line]
     if {$n < 0} {
@@ -2890,26 +2885,14 @@ proc getblobdiffline {bdf ids} {
        set diffinhdr 0
     } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
                   $line match f1l f1c f2l f2c rest]} {
-       if {$gaudydiff} {
-           $ctext insert end "\t" hunksep
-           $ctext insert end "    $f1l    " d0 "    $f2l    " d1
-           $ctext insert end "    $rest \n" hunksep
-       } else {
-           $ctext insert end "$line\n" hunksep
-       }
+       $ctext insert end "$line\n" hunksep
        set diffinhdr 0
     } else {
        set x [string range $line 0 0]
        if {$x == "-" || $x == "+"} {
            set tag [expr {$x == "+"}]
-           if {$gaudydiff} {
-               set line [string range $line 1 end]
-           }
            $ctext insert end "$line\n" d$tag
        } elseif {$x == " "} {
-           if {$gaudydiff} {
-               set line [string range $line 1 end]
-           }
            $ctext insert end "$line\n"
        } elseif {$diffinhdr || $x == "\\"} {
            # e.g. "\ No newline at end of file"
@@ -3634,26 +3617,80 @@ proc doquit {} {
     destroy .
 }
 
-proc formatdate {d} {
-    global hours nhours tfd fastdate
+proc doprefs {} {
+    global maxwidth maxgraphpct diffopts findmergefiles
+    global oldprefs prefstop
 
-    if {!$fastdate} {
-       return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+    set top .gitkprefs
+    set prefstop $top
+    if {[winfo exists $top]} {
+       raise $top
+       return
     }
-    set hr [expr {$d / 3600}]
-    set ms [expr {$d % 3600}]
-    if {![info exists hours($hr)]} {
-       set hours($hr) [clock format $d -format "%Y-%m-%d %H"]
-       set nhours($hr) 0
+    foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+       set oldprefs($v) [set $v]
     }
-    incr nhours($hr)
-    set minsec [format "%.2d:%.2d" [expr {$ms/60}] [expr {$ms%60}]]
-    return "$hours($hr):$minsec"
+    toplevel $top
+    wm title $top "Gitk preferences"
+    label $top.ldisp -text "Commit list display options"
+    grid $top.ldisp - -sticky w -pady 10
+    label $top.spacer -text " "
+    label $top.maxwidthl -text "Maximum graph width (lines)" \
+       -font optionfont
+    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
+    label $top.maxpctl -text "Maximum graph width (% of pane)" \
+       -font optionfont
+    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $top.maxpctl $top.maxpct -sticky w
+    checkbutton $top.findm -variable findmergefiles
+    label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
+       -font optionfont
+    grid $top.findm $top.findml - -sticky w
+    label $top.ddisp -text "Diff display options"
+    grid $top.ddisp - -sticky w -pady 10
+    label $top.diffoptl -text "Options for diff program" \
+       -font optionfont
+    entry $top.diffopt -width 20 -textvariable diffopts
+    grid x $top.diffoptl $top.diffopt -sticky w
+    frame $top.buts
+    button $top.buts.ok -text "OK" -command prefsok
+    button $top.buts.can -text "Cancel" -command prefscan
+    grid $top.buts.ok $top.buts.can
+    grid columnconfigure $top.buts 0 -weight 1 -uniform a
+    grid columnconfigure $top.buts 1 -weight 1 -uniform a
+    grid $top.buts - - -pady 10 -sticky ew
+}
+
+proc prefscan {} {
+    global maxwidth maxgraphpct diffopts findmergefiles
+    global oldprefs prefstop
+
+    foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+       set $v $oldprefs($v)
+    }
+    catch {destroy $prefstop}
+    unset prefstop
+}
+
+proc prefsok {} {
+    global maxwidth maxgraphpct
+    global oldprefs prefstop
+
+    catch {destroy $prefstop}
+    unset prefstop
+    if {$maxwidth != $oldprefs(maxwidth)
+       || $maxgraphpct != $oldprefs(maxgraphpct)} {
+       redisplay
+    }
+}
+
+proc formatdate {d} {
+    return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
 }
 
 # defaults...
 set datemode 0
-set boldnames 0
 set diffopts "-U 5 -p"
 set wrcomcmd "git-diff-tree --stdin -p --pretty"
 
@@ -3668,7 +3705,6 @@ if {$gitencoding == ""} {
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
 set findmergefiles 0
-set gaudydiff 0
 set maxgraphpct 50
 set maxwidth 16
 set revlistorder 0
@@ -3679,15 +3715,13 @@ set colors {green red blue magenta darkgrey brown orange}
 catch {source ~/.gitk}
 
 set namefont $mainfont
-if {$boldnames} {
-    lappend namefont bold
-}
+
+font create optionfont -family sans-serif -size -12
 
 set revtreeargs {}
 foreach arg $argv {
     switch -regexp -- $arg {
        "^$" { }
-       "^-b" { set boldnames 1 }
        "^-d" { set datemode 1 }
        "^-r" { set revlistorder 1 }
        default {
index ad789829c1c33e00cbcc9e1e1564e645755d49ab..fc013ec139bd066a4d32357d7508d10c82b6f873 100644 (file)
@@ -1008,9 +1008,7 @@ static int unlock_remote(struct active_lock *lock)
        if (lock->owner != NULL)
                free(lock->owner);
        free(lock->url);
-/* Freeing the token causes a segfault...
        free(lock->token);
-*/
        free(lock);
 
        return rc;
@@ -1273,6 +1271,9 @@ int main(int argc, char **argv)
                break;
        }
 
+       if (!remote->url)
+               usage(http_push_usage);
+
        memset(remote_dir_exists, 0, 256);
 
        http_init();
index d7c7e750fbf08363731e7bafdc6b2b1b058ccc38..d4b62198a0774409fff4acdbc8b35a7e052f498d 100644 (file)
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -12,218 +12,56 @@ static int line_termination = '\n';
 #define LS_RECURSIVE 1
 #define LS_TREE_ONLY 2
 static int ls_options = 0;
+const char **pathspec;
 
-static struct tree_entry_list root_entry;
-
-static void prepare_root(unsigned char *sha1)
-{
-       unsigned char rsha[20];
-       unsigned long size;
-       void *buf;
-       struct tree *root_tree;
-
-       buf = read_object_with_reference(sha1, "tree", &size, rsha);
-       free(buf);
-       if (!buf)
-               die("Could not read %s", sha1_to_hex(sha1));
-
-       root_tree = lookup_tree(rsha);
-       if (!root_tree)
-               die("Could not read %s", sha1_to_hex(sha1));
-
-       /* Prepare a fake entry */
-       root_entry.directory = 1;
-       root_entry.executable = root_entry.symlink = 0;
-       root_entry.mode = S_IFDIR;
-       root_entry.name = "";
-       root_entry.item.tree = root_tree;
-       root_entry.parent = NULL;
-}
-
-static int prepare_children(struct tree_entry_list *elem)
-{
-       if (!elem->directory)
-               return -1;
-       if (!elem->item.tree->object.parsed) {
-               struct tree_entry_list *e;
-               if (parse_tree(elem->item.tree))
-                       return -1;
-               /* Set up the parent link */
-               for (e = elem->item.tree->entries; e; e = e->next)
-                       e->parent = elem;
-       }
-       return 0;
-}
+static const char ls_tree_usage[] =
+       "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
 
-static struct tree_entry_list *find_entry(const char *path, char *pathbuf)
+static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
 {
-       const char *next, *slash;
-       int len;
-       struct tree_entry_list *elem = &root_entry, *oldelem = NULL;
-
-       *(pathbuf) = '\0';
-
-       /* Find tree element, descending from root, that
-        * corresponds to the named path, lazily expanding
-        * the tree if possible.
-        */
-
-       while (path) {
-               /* The fact we still have path means that the caller
-                * wants us to make sure that elem at this point is a
-                * directory, and possibly descend into it.  Even what
-                * is left is just trailing slashes, we loop back to
-                * here, and this call to prepare_children() will
-                * catch elem not being a tree.  Nice.
-                */
-               if (prepare_children(elem))
-                       return NULL;
-
-               slash = strchr(path, '/');
-               if (!slash) {
-                       len = strlen(path);
-                       next = NULL;
-               }
-               else {
-                       next = slash + 1;
-                       len = slash - path;
-               }
-               if (len) {
-                       if (oldelem) {
-                               pathbuf += sprintf(pathbuf, "%s/", oldelem->name);
-                       }
-
-                       /* (len == 0) if the original path was "drivers/char/"
-                        * and we have run already two rounds, having elem
-                        * pointing at the drivers/char directory.
-                        */
-                       elem = elem->item.tree->entries;
-                       while (elem) {
-                               if ((strlen(elem->name) == len) &&
-                                   !strncmp(elem->name, path, len)) {
-                                       /* found */
+       const char *type = "blob";
+
+       if (S_ISDIR(mode)) {
+               const char **s;
+               if (ls_options & LS_RECURSIVE)
+                       return READ_TREE_RECURSIVE;
+               s = pathspec;
+               if (s) {
+                       for (;;) {
+                               const char *spec = *s++;
+                               int len, speclen;
+
+                               if (!spec)
                                        break;
-                               }
-                               elem = elem->next;
+                               if (strncmp(base, spec, baselen))
+                                       continue;
+                               len = strlen(pathname);
+                               spec += baselen;
+                               speclen = strlen(spec);
+                               if (speclen <= len)
+                                       continue;
+                               if (memcmp(pathname, spec, len))
+                                       continue;
+                               return READ_TREE_RECURSIVE;
                        }
-                       if (!elem)
-                               return NULL;
-
-                       oldelem = elem;
                }
-               path = next;
+               type = "tree";
        }
 
-       return elem;
-}
-
-static const char *entry_type(struct tree_entry_list *e)
-{
-       return (e->directory ? "tree" : "blob");
-}
-
-static const char *entry_hex(struct tree_entry_list *e)
-{
-       return sha1_to_hex(e->directory
-                          ? e->item.tree->object.sha1
-                          : e->item.blob->object.sha1);
-}
-
-/* forward declaration for mutually recursive routines */
-static int show_entry(struct tree_entry_list *, int, char *pathbuf);
-
-static int show_children(struct tree_entry_list *e, int level, char *pathbuf)
-{
-       int oldlen = strlen(pathbuf);
-
-       if (e != &root_entry)
-               sprintf(pathbuf + oldlen, "%s/", e->name);
-
-       if (prepare_children(e))
-               die("internal error: ls-tree show_children called with non tree");
-       e = e->item.tree->entries;
-       while (e) {
-               show_entry(e, level, pathbuf);
-               e = e->next;
-       }
-
-       pathbuf[oldlen] = '\0';
-
+       printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
+       write_name_quoted(base, baselen, pathname, line_termination, stdout);
+       putchar(line_termination);
        return 0;
 }
 
-static int show_entry(struct tree_entry_list *e, int level, char *pathbuf)
+int main(int argc, const char **argv)
 {
-       int err = 0; 
-
-       if (e != &root_entry) {
-               int pathlen = strlen(pathbuf);
-               printf("%06o %s %s      ",
-                      e->mode, entry_type(e), entry_hex(e));
-               write_name_quoted(pathbuf, pathlen, e->name,
-                                 line_termination, stdout);
-               putchar(line_termination);
-       }
-
-       if (e->directory) {
-               /* If this is a directory, we have the following cases:
-                * (1) This is the top-level request (explicit path from the
-                *     command line, or "root" if there is no command line).
-                *  a. Without any flag.  We show direct children.  We do not 
-                *     recurse into them.
-                *  b. With -r.  We do recurse into children.
-                *  c. With -d.  We do not recurse into children.
-                * (2) We came here because our caller is either (1-a) or
-                *     (1-b).
-                *  a. Without any flag.  We do not show our children (which
-                *     are grandchildren for the original request).
-                *  b. With -r.  We continue to recurse into our children.
-                *  c. With -d.  We should not have come here to begin with.
-                */
-               if (level == 0 && !(ls_options & LS_TREE_ONLY))
-                       /* case (1)-a and (1)-b */
-                       err = err | show_children(e, level+1, pathbuf);
-               else if (level && ls_options & LS_RECURSIVE)
-                       /* case (2)-b */
-                       err = err | show_children(e, level+1, pathbuf);
-       }
-       return err;
-}
-
-static int list_one(const char *path)
-{
-       int err = 0;
-       char pathbuf[MAXPATHLEN + 1];
-       struct tree_entry_list *e = find_entry(path, pathbuf);
-       if (!e) {
-               /* traditionally ls-tree does not complain about
-                * missing path.  We may change this later to match
-                * what "/bin/ls -a" does, which is to complain.
-                */
-               return err;
-       }
-       err = err | show_entry(e, 0, pathbuf);
-       return err;
-}
-
-static int list(char **path)
-{
-       int i;
-       int err = 0;
-       for (i = 0; path[i]; i++)
-               err = err | list_one(path[i]);
-       return err;
-}
-
-static const char ls_tree_usage[] =
-       "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
-
-int main(int argc, char **argv)
-{
-       static char *path0[] = { "", NULL };
-       char **path;
+       const char *prefix;
        unsigned char sha1[20];
+       char *buf;
+       unsigned long size;
 
+       prefix = setup_git_directory();
        while (1 < argc && argv[1][0] == '-') {
                switch (argv[1][1]) {
                case 'z':
@@ -246,9 +84,11 @@ int main(int argc, char **argv)
        if (get_sha1(argv[1], sha1) < 0)
                usage(ls_tree_usage);
 
-       path = (argc == 2) ? path0 : (argv + 2);
-       prepare_root(sha1);
-       if (list(path) < 0)
-               die("list failed");
+       pathspec = get_pathspec(prefix, argv + 2);
+       buf = read_object_with_reference(sha1, "tree", &size, NULL);
+       if (!buf)
+               die("not a tree object");
+       read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
+
        return 0;
 }
diff --git a/setup.c b/setup.c
index cc44a724bf3220de1cb8a3ef818e581905d7265c..3286a568ed4c7d4c82bb18d779f05518fe05c9b3 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -116,7 +116,7 @@ static const char *setup_git_directory_1(void)
                if (validate_symref(path))
                        goto bad_dir_environ;
                if (getenv(DB_ENVIRONMENT)) {
-                       if (access(DB_ENVIRONMENT, X_OK))
+                       if (access(getenv(DB_ENVIRONMENT), X_OK))
                                goto bad_dir_environ;
                }
                else {
index dff7d6916374d6f1c9302970cef7d0ab7e0c75ad..22bdacaf7861d15bb5fd383e9b17c22f082d72b7 100755 (executable)
@@ -126,19 +126,18 @@ test_expect_success \
     'git-ls-tree output for a known tree.' \
     'diff current expected'
 
+# This changed in ls-tree pathspec change -- recursive does
+# not show tree nodes anymore.
 test_expect_success \
     'showing tree with git-ls-tree -r' \
     'git-ls-tree -r $tree >current'
 cat >expected <<\EOF
 100644 blob f87290f8eb2cbbea7857214459a0739927eab154   path0
 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01   path0sym
-040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe   path2
 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7   path2/file2
 120000 blob d8ce161addc5173867a3c3c730924388daedbc38   path2/file2sym
-040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3   path3
 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376   path3/file3
 120000 blob 8599103969b43aff7e430efea79ca4636466794f   path3/file3sym
-040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2   path3/subp3
 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f   path3/subp3/file3
 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c   path3/subp3/file3sym
 EOF
index c6ce56c86b95ae778b5e044999f8c5d8c0c70816..ae086755ea7b727b29811c8ce8cd32a7e2bd6e0f 100755 (executable)
@@ -54,8 +54,6 @@ test_expect_success \
      cat >expected <<\EOF &&
 100644 blob X  path0
 120000 blob X  path1
-040000 tree X  path2
-040000 tree X  path2/baz
 100644 blob X  path2/baz/b
 120000 blob X  path2/bazbo
 100644 blob X  path2/foo
@@ -70,12 +68,14 @@ EOF
      test_output'
 
 
+# it used to be path1 and then path0, but with pathspec semantics
+# they are shown in canonical order.
 test_expect_success \
     'ls-tree filtered with path1 path0' \
     'git-ls-tree $tree path1 path0 >current &&
      cat >expected <<\EOF &&
-120000 blob X  path1
 100644 blob X  path0
+120000 blob X  path1
 EOF
      test_output'
 
@@ -86,45 +86,34 @@ test_expect_success \
 EOF
      test_output'
 
+# It used to show path2 and its immediate children but
+# with pathspec semantics it shows only path2
 test_expect_success \
     'ls-tree filtered with path2' \
     'git-ls-tree $tree path2 >current &&
      cat >expected <<\EOF &&
 040000 tree X  path2
-040000 tree X  path2/baz
-120000 blob X  path2/bazbo
-100644 blob X  path2/foo
-EOF
-     test_output'
-
-test_expect_success \
-    'ls-tree filtered with path2/baz' \
-    'git-ls-tree $tree path2/baz >current &&
-     cat >expected <<\EOF &&
-040000 tree X  path2/baz
-100644 blob X  path2/baz/b
 EOF
      test_output'
 
+# ... and path2/ shows the children.
 test_expect_success \
-    'ls-tree filtered with path2' \
-    'git-ls-tree $tree path2 >current &&
+    'ls-tree filtered with path2/' \
+    'git-ls-tree $tree path2/ >current &&
      cat >expected <<\EOF &&
-040000 tree X  path2
 040000 tree X  path2/baz
 120000 blob X  path2/bazbo
 100644 blob X  path2/foo
 EOF
      test_output'
 
+# The same change -- exact match does not show children of
+# path2/baz
 test_expect_success \
-    'ls-tree filtered with path2/' \
-    'git-ls-tree $tree path2/ >current &&
+    'ls-tree filtered with path2/baz' \
+    'git-ls-tree $tree path2/baz >current &&
      cat >expected <<\EOF &&
-040000 tree X  path2
 040000 tree X  path2/baz
-120000 blob X  path2/bazbo
-100644 blob X  path2/foo
 EOF
      test_output'
 
index 54103683480eb5f2a18ceac3f1018769ea31b18f..d78deb1e710056e236ba61f4b8ceb55e11c44cbf 100644 (file)
@@ -59,24 +59,16 @@ test_expect_success \
 EOF
      test_output'
 
+# Recursive does not show tree nodes anymore...
 test_expect_success \
     'ls-tree recursive' \
     'git-ls-tree -r $tree >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
 100644 blob X  2.txt
-040000 tree X  path0
-040000 tree X  path0/a
-040000 tree X  path0/a/b
-040000 tree X  path0/a/b/c
 100644 blob X  path0/a/b/c/1.txt
-040000 tree X  path1
-040000 tree X  path1/b
-040000 tree X  path1/b/c
 100644 blob X  path1/b/c/1.txt
-040000 tree X  path2
 100644 blob X  path2/1.txt
-040000 tree X  path3
 100644 blob X  path3/1.txt
 100644 blob X  path3/2.txt
 EOF
@@ -110,41 +102,27 @@ test_expect_success \
 EOF
      test_output'
 
+# I am not so sure about this one after ls-tree doing pathspec match.
+# Having both path0/a and path0/a/b/c makes path0/a redundant, and
+# it behaves as if path0/a/b/c, path1/b/c, path2 and path3 are specified.
 test_expect_success \
     'ls-tree filter directories' \
     'git-ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
      cat >expected <<\EOF &&
-040000 tree X  path3
-100644 blob X  path3/1.txt
-100644 blob X  path3/2.txt
-040000 tree X  path2
-100644 blob X  path2/1.txt
 040000 tree X  path0/a/b/c
-100644 blob X  path0/a/b/c/1.txt
 040000 tree X  path1/b/c
-100644 blob X  path1/b/c/1.txt
-040000 tree X  path0/a
-040000 tree X  path0/a/b
+040000 tree X  path2
+040000 tree X  path3
 EOF
      test_output'
 
+# Again, duplicates are filtered away so this is equivalent to
+# having 1.txt and path3
 test_expect_success \
     'ls-tree filter odd names' \
     'git-ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
-100644 blob X  1.txt
-100644 blob X  1.txt
-100644 blob X  path3/1.txt
-100644 blob X  path3/1.txt
-100644 blob X  path3/1.txt
-040000 tree X  path3
-100644 blob X  path3/1.txt
-100644 blob X  path3/2.txt
-040000 tree X  path3
-100644 blob X  path3/1.txt
-100644 blob X  path3/2.txt
-040000 tree X  path3
 100644 blob X  path3/1.txt
 100644 blob X  path3/2.txt
 EOF
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
new file mode 100755 (executable)
index 0000000..43d74c5
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='git-mv in subdirs'
+. ./test-lib.sh
+
+test_expect_success \
+    'prepare reference tree' \
+    'mkdir path0 path1 &&
+     cp ../../COPYING path0/COPYING &&
+     git-add path0/COPYING &&
+     git-commit -m add -a'
+
+test_expect_success \
+    'moving the file' \
+    'cd path0 && git-mv COPYING ../path1/COPYING'
+
+# in path0 currently
+test_expect_success \
+    'commiting the change' \
+    'cd .. && git-commit -m move -a'
+
+test_expect_success \
+    'checking the commit' \
+    'git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+    grep -E "^R100.+path0/COPYING.+path1/COPYING"'
+
+test_done
diff --git a/tree.c b/tree.c
index 8b42a07b208aceeaa4900c034eea8a5b6b7ac323..043f032151cbca16dc144f9128b6327c755bcedd 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -9,9 +9,16 @@ const char *tree_type = "tree";
 
 static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
 {
-       int len = strlen(pathname);
-       unsigned int size = cache_entry_size(baselen + len);
-       struct cache_entry *ce = xmalloc(size);
+       int len;
+       unsigned int size;
+       struct cache_entry *ce;
+
+       if (S_ISDIR(mode))
+               return READ_TREE_RECURSIVE;
+
+       len = strlen(pathname);
+       size = cache_entry_size(baselen + len);
+       ce = xmalloc(size);
 
        memset(ce, 0, size);
 
@@ -67,9 +74,10 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns
        return 0;
 }
 
-static int read_tree_recursive(void *buffer, unsigned long size,
-                              const char *base, int baselen,
-                              int stage, const char **match)
+int read_tree_recursive(void *buffer, unsigned long size,
+                       const char *base, int baselen,
+                       int stage, const char **match,
+                       read_tree_fn_t fn)
 {
        while (size) {
                int len = strlen(buffer)+1;
@@ -86,6 +94,14 @@ static int read_tree_recursive(void *buffer, unsigned long size,
                if (!match_tree_entry(base, baselen, path, mode, match))
                        continue;
 
+               switch (fn(sha1, base, baselen, path, mode, stage)) {
+               case 0:
+                       continue;
+               case READ_TREE_RECURSIVE:
+                       break;;
+               default:
+                       return -1;
+               }
                if (S_ISDIR(mode)) {
                        int retval;
                        int pathlen = strlen(path);
@@ -106,22 +122,20 @@ static int read_tree_recursive(void *buffer, unsigned long size,
                        retval = read_tree_recursive(eltbuf, eltsize,
                                                     newbase,
                                                     baselen + pathlen + 1,
-                                                    stage, match);
+                                                    stage, match, fn);
                        free(eltbuf);
                        free(newbase);
                        if (retval)
                                return -1;
                        continue;
                }
-               if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
-                       return -1;
        }
        return 0;
 }
 
 int read_tree(void *buffer, unsigned long size, int stage, const char **match)
 {
-       return read_tree_recursive(buffer, size, "", 0, stage, match);
+       return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
 }
 
 struct tree *lookup_tree(const unsigned char *sha1)
diff --git a/tree.h b/tree.h
index 9975e88216dc6924c1d6e9ec3c7ae6d90c2df1dd..768e5e9eb894d37c0dca452bc7d96a1271035b55 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -35,4 +35,13 @@ int parse_tree(struct tree *tree);
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const unsigned char *sha1);
 
+#define READ_TREE_RECURSIVE 1
+typedef int (*read_tree_fn_t)(unsigned char *, const char *, int, const char *, unsigned int, int);
+
+extern int read_tree_recursive(void *buffer, unsigned long size,
+                       const char *base, int baselen,
+                       int stage, const char **match,
+                       read_tree_fn_t fn);
+
+
 #endif /* TREE_H */