Merge branch 'jc/fsck' into next
authorJunio C Hamano <junkio@cox.net>
Thu, 9 Mar 2006 21:10:50 +0000 (13:10 -0800)
committerJunio C Hamano <junkio@cox.net>
Thu, 9 Mar 2006 21:10:50 +0000 (13:10 -0800)
* jc/fsck:
  fsck-objects: Remove --standalone
  refs.c::do_for_each_ref(): Finish error message lines with "\n"
  Nicer output from 'git'
  Use #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
  Remove trailing dot after short description
  Fix some inconsistencies in the docs
  contrib/git-svn: fix a harmless warning on rebuild (with old repos)
  contrib/git-svn: remove the --no-stop-on-copy flag
  contrib/git-svn: fix svn compat and fetch args
  Don't recurse into parents marked uninteresting.
  diff-delta: bound hash list length to avoid O(m*n) behavior
  test-delta needs zlib to compile
  git-fmt-merge-msg cleanup

72 files changed:
.gitignore
Documentation/git-add.txt
Documentation/git-applypatch.txt
Documentation/git-branch.txt
Documentation/git-check-ref-format.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-cherry.txt
Documentation/git-clone-pack.txt
Documentation/git-clone.txt
Documentation/git-count-objects.txt
Documentation/git-daemon.txt
Documentation/git-describe.txt
Documentation/git-diff-stages.txt
Documentation/git-diff.txt
Documentation/git-fetch-pack.txt
Documentation/git-fetch.txt
Documentation/git-format-patch.txt
Documentation/git-fsck-objects.txt
Documentation/git-get-tar-commit-id.txt
Documentation/git-grep.txt
Documentation/git-hash-object.txt
Documentation/git-http-push.txt
Documentation/git-lost-found.txt
Documentation/git-ls-remote.txt
Documentation/git-ls-tree.txt
Documentation/git-mailinfo.txt
Documentation/git-mailsplit.txt
Documentation/git-mv.txt
Documentation/git-name-rev.txt
Documentation/git-pack-objects.txt
Documentation/git-pack-redundant.txt
Documentation/git-patch-id.txt
Documentation/git-peek-remote.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-relink.txt
Documentation/git-repo-config.txt
Documentation/git-request-pull.txt
Documentation/git-reset.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-rm.txt
Documentation/git-send-pack.txt
Documentation/git-sh-setup.txt
Documentation/git-shortlog.txt
Documentation/git-show-branch.txt
Documentation/git-show.txt
Documentation/git-status.txt
Documentation/git-stripspace.txt
Documentation/git-tag.txt
Documentation/git-unpack-objects.txt
Documentation/git-upload-pack.txt
Documentation/git-verify-pack.txt
Documentation/git-verify-tag.txt
Documentation/git-whatchanged.txt
Documentation/git.txt
Makefile
apply.c
contrib/git-svn/git-svn.perl
contrib/git-svn/git-svn.txt
date.c
diff-delta.c
exec_cmd.c
fsck-objects.c
generate-cmdlist.sh [new file with mode: 0755]
git-compat-util.h
git-fmt-merge-msg.perl
git.c
refs.c
revision.c

index abbc509..8e94cbd 100644 (file)
@@ -121,6 +121,7 @@ git-write-tree
 git-core-*/?*
 test-date
 test-delta
+common-cmds.h
 *.tar.gz
 *.dsc
 *.deb
index 5b7c354..ae24547 100644 (file)
@@ -3,7 +3,7 @@ git-add(1)
 
 NAME
 ----
-git-add - Add files to the index file.
+git-add - Add files to the index file
 
 SYNOPSIS
 --------
index 5b9037d..2b1ff14 100644 (file)
@@ -3,7 +3,7 @@ git-applypatch(1)
 
 NAME
 ----
-git-applypatch - Apply one patch extracted from an e-mail.
+git-applypatch - Apply one patch extracted from an e-mail
 
 
 SYNOPSIS
index b1bc827..4cd0cb9 100644 (file)
@@ -3,7 +3,7 @@ git-branch(1)
 
 NAME
 ----
-git-branch - Create a new branch, or remove an old one.
+git-branch - Create a new branch, or remove an old one
 
 SYNOPSIS
 --------
index f7f84c6..7dc1bdb 100644 (file)
@@ -3,7 +3,7 @@ git-check-ref-format(1)
 
 NAME
 ----
-git-check-ref-format - Make sure ref name is well formed.
+git-check-ref-format - Make sure ref name is well formed
 
 SYNOPSIS
 --------
index df9a618..556e733 100644 (file)
@@ -3,7 +3,7 @@ git-checkout(1)
 
 NAME
 ----
-git-checkout - Checkout and switch to a branch.
+git-checkout - Checkout and switch to a branch
 
 SYNOPSIS
 --------
index 4f323fa..bfa950c 100644 (file)
@@ -3,7 +3,7 @@ git-cherry-pick(1)
 
 NAME
 ----
-git-cherry-pick - Apply the change introduced by an existing commit.
+git-cherry-pick - Apply the change introduced by an existing commit
 
 SYNOPSIS
 --------
index af87966..9a5e371 100644 (file)
@@ -3,7 +3,7 @@ git-cherry(1)
 
 NAME
 ----
-git-cherry - Find commits not merged upstream.
+git-cherry - Find commits not merged upstream
 
 SYNOPSIS
 --------
index 39906fc..09f43ee 100644 (file)
@@ -3,7 +3,7 @@ git-clone-pack(1)
 
 NAME
 ----
-git-clone-pack - Clones a repository by receiving packed objects.
+git-clone-pack - Clones a repository by receiving packed objects
 
 
 SYNOPSIS
index 684e4bd..9ac54c2 100644 (file)
@@ -3,7 +3,7 @@ git-clone(1)
 
 NAME
 ----
-git-clone - Clones a repository.
+git-clone - Clones a repository
 
 
 SYNOPSIS
index 36888d9..47216f4 100644 (file)
@@ -3,7 +3,7 @@ git-count-objects(1)
 
 NAME
 ----
-git-count-objects - Reports on unpacked objects.
+git-count-objects - Reports on unpacked objects
 
 SYNOPSIS
 --------
index 2cc6075..924a676 100644 (file)
@@ -3,7 +3,7 @@ git-daemon(1)
 
 NAME
 ----
-git-daemon - A really simple server for git repositories.
+git-daemon - A really simple server for git repositories
 
 SYNOPSIS
 --------
index 0efe82a..7a253ea 100644 (file)
@@ -3,7 +3,7 @@ git-describe(1)
 
 NAME
 ----
-git-describe - Show the most recent tag that is reachable from a commit.
+git-describe - Show the most recent tag that is reachable from a commit
 
 
 SYNOPSIS
index 28c60fc..3273918 100644 (file)
@@ -3,7 +3,7 @@ git-diff-stages(1)
 
 NAME
 ----
-git-diff-stages - Compares content and mode of blobs between stages in an unmerged index file.
+git-diff-stages - Compares content and mode of blobs between stages in an unmerged index file
 
 
 SYNOPSIS
index ca41634..890931c 100644 (file)
@@ -3,7 +3,7 @@ git-diff(1)
 
 NAME
 ----
-git-diff - Show changes between commits, commit and working tree, etc.
+git-diff - Show changes between commits, commit and working tree, etc
 
 
 SYNOPSIS
index 913b75b..bff9aa6 100644 (file)
@@ -3,7 +3,7 @@ git-fetch-pack(1)
 
 NAME
 ----
-git-fetch-pack - Receive missing objects from another repository.
+git-fetch-pack - Receive missing objects from another repository
 
 
 SYNOPSIS
index a67dc34..a9e86fd 100644 (file)
@@ -3,7 +3,7 @@ git-fetch(1)
 
 NAME
 ----
-git-fetch - Download objects and a head from another repository.
+git-fetch - Download objects and a head from another repository
 
 
 SYNOPSIS
index 9ac0636..7c467c5 100644 (file)
@@ -3,7 +3,7 @@ git-format-patch(1)
 
 NAME
 ----
-git-format-patch - Prepare patches for e-mail submission.
+git-format-patch - Prepare patches for e-mail submission
 
 
 SYNOPSIS
index 387b435..93ce9dc 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git-fsck-objects' [--tags] [--root] [--unreachable] [--cache]
-                [--standalone | --full] [--strict] [<object>*]
+                [--full] [--strict] [<object>*]
 
 DESCRIPTION
 -----------
@@ -38,21 +38,14 @@ index file and all SHA1 references in .git/refs/* as heads.
        Consider any object recorded in the index also as a head node for
        an unreachability trace.
 
---standalone::
-       Limit checks to the contents of GIT_OBJECT_DIRECTORY
-       ($GIT_DIR/objects), making sure that it is consistent and
-       complete without referring to objects found in alternate
-       object pools listed in GIT_ALTERNATE_OBJECT_DIRECTORIES,
-       nor packed git archives found in $GIT_DIR/objects/pack;
-       cannot be used with --full.
-
 --full::
        Check not just objects in GIT_OBJECT_DIRECTORY
        ($GIT_DIR/objects), but also the ones found in alternate
-       object pools listed in GIT_ALTERNATE_OBJECT_DIRECTORIES,
+       object pools listed in GIT_ALTERNATE_OBJECT_DIRECTORIES
+       or $GIT_DIR/objects/info/alternates,
        and in packed git archives found in $GIT_DIR/objects/pack
        and corresponding pack subdirectories in alternate
-       object pools; cannot be used with --standalone.
+       object pools.
 
 --strict::
        Enable more strict checking, namely to catch a file mode
index 30b1fbf..48805b6 100644 (file)
@@ -3,7 +3,7 @@ git-get-tar-commit-id(1)
 
 NAME
 ----
-git-get-tar-commit-id - Extract commit ID from an archive created using git-tar-tree.
+git-get-tar-commit-id - Extract commit ID from an archive created using git-tar-tree
 
 
 SYNOPSIS
index bf4b592..fbd2394 100644 (file)
@@ -3,7 +3,7 @@ git-grep(1)
 
 NAME
 ----
-git-grep - print lines matching a pattern
+git-grep - Print lines matching a pattern
 
 
 SYNOPSIS
index 0924931..04e8d00 100644 (file)
@@ -3,7 +3,7 @@ git-hash-object(1)
 
 NAME
 ----
-git-hash-object - Computes object ID and optionally creates a blob from a file.
+git-hash-object - Computes object ID and optionally creates a blob from a file
 
 
 SYNOPSIS
index c7066d6..7e1f894 100644 (file)
@@ -3,7 +3,7 @@ git-http-push(1)
 
 NAME
 ----
-git-http-push - Push missing objects using HTTP/DAV.
+git-http-push - Push missing objects using HTTP/DAV
 
 
 SYNOPSIS
index 03156f2..f52a9d7 100644 (file)
@@ -3,7 +3,7 @@ git-lost-found(1)
 
 NAME
 ----
-git-lost-found - Recover lost refs that luckily have not yet been pruned.
+git-lost-found - Recover lost refs that luckily have not yet been pruned
 
 SYNOPSIS
 --------
index 66fe60f..ae4c1a2 100644 (file)
@@ -3,7 +3,7 @@ git-ls-remote(1)
 
 NAME
 ----
-git-ls-remote - Look at references other repository has.
+git-ls-remote - Look at references other repository has
 
 
 SYNOPSIS
index b92a8b2..5bf6d8b 100644 (file)
@@ -3,7 +3,7 @@ git-ls-tree(1)
 
 NAME
 ----
-git-ls-tree - Lists the contents of a tree object.
+git-ls-tree - Lists the contents of a tree object
 
 
 SYNOPSIS
index 8890754..ea0a065 100644 (file)
@@ -3,7 +3,7 @@ git-mailinfo(1)
 
 NAME
 ----
-git-mailinfo - Extracts patch from a single e-mail message.
+git-mailinfo - Extracts patch from a single e-mail message
 
 
 SYNOPSIS
index e0703e9..209e36b 100644 (file)
@@ -3,7 +3,7 @@ git-mailsplit(1)
 
 NAME
 ----
-git-mailsplit - Totally braindamaged mbox splitter program.
+git-mailsplit - Totally braindamaged mbox splitter program
 
 SYNOPSIS
 --------
index d242b39..207c43a 100644 (file)
@@ -3,7 +3,7 @@ git-mv(1)
 
 NAME
 ----
-git-mv - Script used to move or rename a file, directory or symlink.
+git-mv - Move or rename a file, directory or symlink
 
 
 SYNOPSIS
index e37b0b8..6870708 100644 (file)
@@ -3,7 +3,7 @@ git-name-rev(1)
 
 NAME
 ----
-git-name-rev - Find symbolic names for given revs.
+git-name-rev - Find symbolic names for given revs
 
 
 SYNOPSIS
index 567dabf..4991f88 100644 (file)
@@ -3,7 +3,7 @@ git-pack-objects(1)
 
 NAME
 ----
-git-pack-objects - Create a packed archive of objects.
+git-pack-objects - Create a packed archive of objects
 
 
 SYNOPSIS
index a81cb97..8fb0659 100644 (file)
@@ -3,7 +3,7 @@ git-pack-redundant(1)
 
 NAME
 ----
-git-pack-redundant - Program used to find redundant pack files.
+git-pack-redundant - Program used to find redundant pack files
 
 
 SYNOPSIS
index c8bd197..723b8cc 100644 (file)
@@ -3,7 +3,7 @@ git-patch-id(1)
 
 NAME
 ----
-git-patch-id - Generate a patch ID.
+git-patch-id - Generate a patch ID
 
 SYNOPSIS
 --------
index 915d3f8..a00060c 100644 (file)
@@ -3,7 +3,7 @@ git-peek-remote(1)
 
 NAME
 ----
-git-peek-remote - Lists the references in a remote repository.
+git-peek-remote - Lists the references in a remote repository
 
 
 SYNOPSIS
index 20175f4..51577fc 100644 (file)
@@ -3,7 +3,7 @@ git-pull(1)
 
 NAME
 ----
-git-pull - Pull and merge from another repository.
+git-pull - Pull and merge from another repository
 
 
 SYNOPSIS
index 6f4a48a..d5b5ca1 100644 (file)
@@ -3,7 +3,7 @@ git-push(1)
 
 NAME
 ----
-git-push - Update remote refs along with associated objects.
+git-push - Update remote refs along with associated objects
 
 
 SYNOPSIS
index f037d12..4d5b546 100644 (file)
@@ -3,7 +3,7 @@ git-rebase(1)
 
 NAME
 ----
-git-rebase - Rebase local commits to new upstream head.
+git-rebase - Rebase local commits to new upstream head
 
 SYNOPSIS
 --------
index 6240535..aca6012 100644 (file)
@@ -3,7 +3,7 @@ git-relink(1)
 
 NAME
 ----
-git-relink - Hardlink common objects in local repositories.
+git-relink - Hardlink common objects in local repositories
 
 SYNOPSIS
 --------
index 00efde5..26759a8 100644 (file)
@@ -3,7 +3,7 @@ git-repo-config(1)
 
 NAME
 ----
-git-repo-config - Get and set options in .git/config.
+git-repo-config - Get and set options in .git/config
 
 
 SYNOPSIS
index 2463ec9..478a5fd 100644 (file)
@@ -3,7 +3,7 @@ git-request-pull(1)
 
 NAME
 ----
-git-request-pull - Generates a summary of pending changes.
+git-request-pull - Generates a summary of pending changes
 
 SYNOPSIS
 --------
index b4e737e..b7b9798 100644 (file)
@@ -3,7 +3,7 @@ git-reset(1)
 
 NAME
 ----
-git-reset - Reset current HEAD to the specified state.
+git-reset - Reset current HEAD to the specified state
 
 SYNOPSIS
 --------
index 29b5789..8b95df0 100644 (file)
@@ -3,7 +3,7 @@ git-rev-parse(1)
 
 NAME
 ----
-git-rev-parse - Pick out and massage parameters.
+git-rev-parse - Pick out and massage parameters
 
 
 SYNOPSIS
index e27c680..71f7815 100644 (file)
@@ -3,7 +3,7 @@ git-revert(1)
 
 NAME
 ----
-git-revert - Revert an existing commit.
+git-revert - Revert an existing commit
 
 SYNOPSIS
 --------
index d8a5afa..c9c3088 100644 (file)
@@ -3,7 +3,7 @@ git-rm(1)
 
 NAME
 ----
-git-rm - Remove files from the working tree and from the index.
+git-rm - Remove files from the working tree and from the index
 
 SYNOPSIS
 --------
index 577f06a..08e0705 100644 (file)
@@ -3,7 +3,7 @@ git-send-pack(1)
 
 NAME
 ----
-git-send-pack - Push missing objects packed.
+git-send-pack - Push missing objects packed
 
 
 SYNOPSIS
index 6ef59ac..6742c9b 100644 (file)
@@ -3,7 +3,7 @@ git-sh-setup(1)
 
 NAME
 ----
-git-sh-setup - Common git shell script setup code.
+git-sh-setup - Common git shell script setup code
 
 SYNOPSIS
 --------
index bf8db8b..54fb922 100644 (file)
@@ -3,7 +3,7 @@ git-shortlog(1)
 
 NAME
 ----
-git-shortlog - Summarize 'git log' output.
+git-shortlog - Summarize 'git log' output
 
 
 SYNOPSIS
index e474cd0..d3b6e62 100644 (file)
@@ -3,7 +3,7 @@ git-show-branch(1)
 
 NAME
 ----
-git-show-branch - Show branches and their commits.
+git-show-branch - Show branches and their commits
 
 SYNOPSIS
 --------
index 9c359a4..2b4df3f 100644 (file)
@@ -3,7 +3,7 @@ git-show(1)
 
 NAME
 ----
-git-show - Show one commit with difference it introduces.
+git-show - Show one commit with difference it introduces
 
 
 SYNOPSIS
index 753fc08..e446f48 100644 (file)
@@ -3,7 +3,7 @@ git-status(1)
 
 NAME
 ----
-git-status - Show working tree status.
+git-status - Show working tree status
 
 
 SYNOPSIS
index 528a1b6..3a03dd0 100644 (file)
@@ -3,7 +3,7 @@ git-stripspace(1)
 
 NAME
 ----
-git-stripspace - Filter out empty lines.
+git-stripspace - Filter out empty lines
 
 
 SYNOPSIS
index e1c76c6..45476c2 100644 (file)
@@ -3,7 +3,7 @@ git-tag(1)
 
 NAME
 ----
-git-tag -  Create a tag object signed with GPG
+git-tag - Create a tag object signed with GPG
 
 
 SYNOPSIS
index 31ea34d..1828062 100644 (file)
@@ -3,7 +3,7 @@ git-unpack-objects(1)
 
 NAME
 ----
-git-unpack-objects - Unpack objects from a packed archive.
+git-unpack-objects - Unpack objects from a packed archive
 
 
 SYNOPSIS
index 3d8f8ef..4795e98 100644 (file)
@@ -3,7 +3,7 @@ git-upload-pack(1)
 
 NAME
 ----
-git-upload-pack - Send missing objects packed.
+git-upload-pack - Send missing objects packed
 
 
 SYNOPSIS
index d032280..4962d69 100644 (file)
@@ -3,7 +3,7 @@ git-verify-pack(1)
 
 NAME
 ----
-git-verify-pack - Validate packed git archive files.
+git-verify-pack - Validate packed git archive files
 
 
 SYNOPSIS
index b8a73c4..0f9bdb5 100644 (file)
@@ -3,7 +3,7 @@ git-verify-tag(1)
 
 NAME
 ----
-git-verify-tag - Check the GPG signature of tag.
+git-verify-tag - Check the GPG signature of tag
 
 SYNOPSIS
 --------
index 6c150b0..f02f939 100644 (file)
@@ -3,7 +3,7 @@ git-whatchanged(1)
 
 NAME
 ----
-git-whatchanged - Show logs with difference each commit introduces.
+git-whatchanged - Show logs with difference each commit introduces
 
 
 SYNOPSIS
index 2d0ca9d..8610d36 100644 (file)
@@ -20,15 +20,16 @@ brings your stuff to the plumbing).
 OPTIONS
 -------
 --version::
-       prints the git suite version that the 'git' program came from.
+       Prints the git suite version that the 'git' program came from.
 
 --help::
-       prints the synopsis and a list of available commands.
-       If a git command is named this option will bring up the
-       man-page for that command.
+       Prints the synopsis and a list of the most commonly used
+       commands.  If a git command is named this option will bring up
+       the man-page for that command. If the option '--all' or '-a' is
+       given then all available commands are printed.
 
 --exec-path::
-       path to wherever your core git programs are installed.
+       Path to wherever your core git programs are installed.
        This can also be controlled by setting the GIT_EXEC_PATH
        environment variable. If no path is given 'git' will print
        the current setting and then exit.
index 8e2a496..006b212 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -452,10 +452,13 @@ all:
 strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
 
-git$X: git.c $(LIB_FILE)
+git$X: git.c common-cmds.h $(LIB_FILE)
        $(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
                $(ALL_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE) $(LIBS)
 
+common-cmds.h: Documentation/git-*.txt
+       ./generate-cmdlist.sh > $@
+
 $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
        rm -f $@
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
@@ -564,7 +567,7 @@ test-date$X: test-date.c date.o ctype.o
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
 
 test-delta$X: test-delta.c diff-delta.o patch-delta.o
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
+       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^ -lz
 
 check:
        for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
@@ -612,7 +615,7 @@ rpm: dist
 clean:
        rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
        rm -f $(ALL_PROGRAMS) git$X
-       rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo
+       rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h
        rm -rf $(GIT_TARNAME)
        rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        $(MAKE) -C Documentation/ clean
diff --git a/apply.c b/apply.c
index 849a8b4..179b3bb 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -651,7 +651,7 @@ static int parse_git_header(char *line, int len, unsigned int size, struct patch
                len = linelen(line, size);
                if (!len || line[len-1] != '\n')
                        break;
-               for (i = 0; i < sizeof(optable) / sizeof(optable[0]); i++) {
+               for (i = 0; i < ARRAY_SIZE(optable); i++) {
                        const struct opentry *p = optable + i;
                        int oplen = strlen(p->str);
                        if (len < oplen || memcmp(p->str, line, oplen))
index 3c860e4..cf233ef 100755 (executable)
@@ -30,6 +30,7 @@ my $sha1_short = qr/[a-f\d]{4,40}/;
 my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
        $_find_copies_harder, $_l, $_version, $_upgrade, $_authors);
 my (@_branch_from, %tree_map, %users);
+my $_svn_co_url_revs;
 
 my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
                'branch|b=s' => \@_branch_from,
@@ -77,7 +78,7 @@ usage(0) if $_help;
 version() if $_version;
 usage(1) unless defined $cmd;
 load_authors() if $_authors;
-svn_check_ignore_externals();
+svn_compat_check();
 $cmd{$cmd}->[0]->(@ARGV);
 exit 0;
 
@@ -154,7 +155,7 @@ sub rebuild {
                # if we merged or otherwise started elsewhere, this is
                # how we break out of it
                next if (defined $SVN_UUID && ($uuid ne $SVN_UUID));
-               next if (defined $SVN_URL && ($url ne $SVN_URL));
+               next if (defined $SVN_URL && defined $url && ($url ne $SVN_URL));
 
                print "r$rev = $c\n";
                unless (defined $latest) {
@@ -162,7 +163,8 @@ sub rebuild {
                                croak "SVN repository location required: $url\n";
                        }
                        $SVN_URL ||= $url;
-                       $SVN_UUID ||= setup_git_svn();
+                       $SVN_UUID ||= $uuid;
+                       setup_git_svn();
                        $latest = $rev;
                }
                assert_revision_eq_or_unknown($rev, $c);
@@ -171,9 +173,7 @@ sub rebuild {
        }
        close $rev_list or croak $?;
        if (!chdir $SVN_WC) {
-               my @svn_co = ('svn','co',"-r$latest");
-               push @svn_co, '--ignore-externals' unless $_no_ignore_ext;
-               sys(@svn_co, $SVN_URL, $SVN_WC);
+               svn_cmd_checkout($SVN_URL, $latest, $SVN_WC);
                chdir $SVN_WC or croak $!;
        }
 
@@ -222,14 +222,14 @@ sub fetch {
        my $base = shift @$svn_log or croak "No base revision!\n";
        my $last_commit = undef;
        unless (-d $SVN_WC) {
-               my @svn_co = ('svn','co',"-r$base->{revision}");
-               push @svn_co,'--ignore-externals' unless $_no_ignore_ext;
-               sys(@svn_co, $SVN_URL, $SVN_WC);
+               svn_cmd_checkout($SVN_URL,$base->{revision},$SVN_WC);
                chdir $SVN_WC or croak $!;
+               read_uuid();
                $last_commit = git_commit($base, @parents);
                assert_svn_wc_clean($base->{revision}, $last_commit);
        } else {
                chdir $SVN_WC or croak $!;
+               read_uuid();
                $last_commit = file_to_s("$REV_DIR/$base->{revision}");
        }
        my @svn_up = qw(svn up);
@@ -275,7 +275,9 @@ sub commit {
 
        fetch();
        chdir $SVN_WC or croak $!;
-       my $svn_current_rev =  svn_info('.')->{'Last Changed Rev'};
+       my $info = svn_info('.');
+       read_uuid($info);
+       my $svn_current_rev =  $info->{'Last Changed Rev'};
        foreach my $c (@revs) {
                my $mods = svn_checkout_tree($svn_current_rev, $c);
                if (scalar @$mods == 0) {
@@ -314,6 +316,14 @@ sub show_ignore {
 
 ########################### utility functions #########################
 
+sub read_uuid {
+       return if $SVN_UUID;
+       my $info = shift || svn_info('.');
+       $SVN_UUID = $info->{'Repository UUID'} or
+                                       croak "Repository UUID unreadable\n";
+       s_to_file($SVN_UUID,"$GIT_DIR/$GIT_SVN/info/uuid");
+}
+
 sub setup_git_svn {
        defined $SVN_URL or croak "SVN repository location required\n";
        unless (-d $GIT_DIR) {
@@ -323,14 +333,10 @@ sub setup_git_svn {
        mkpath(["$GIT_DIR/$GIT_SVN/info"]);
        mkpath([$REV_DIR]);
        s_to_file($SVN_URL,"$GIT_DIR/$GIT_SVN/info/url");
-       $SVN_UUID = svn_info($SVN_URL)->{'Repository UUID'} or
-                                       croak "Repository UUID unreadable\n";
-       s_to_file($SVN_UUID,"$GIT_DIR/$GIT_SVN/info/uuid");
 
        open my $fd, '>>', "$GIT_DIR/$GIT_SVN/info/exclude" or croak $!;
        print $fd '.svn',"\n";
        close $fd or croak $!;
-       return $SVN_UUID;
 }
 
 sub assert_svn_wc_clean {
@@ -860,7 +866,6 @@ sub git_commit {
        my ($log_msg, @parents) = @_;
        assert_revision_unknown($log_msg->{revision});
        my $out_fh = IO::File->new_tmpfile or croak $!;
-       $SVN_UUID ||= svn_info('.')->{'Repository UUID'};
 
        map_tree_joins() if (@_branch_from && !%tree_map);
 
@@ -922,7 +927,16 @@ sub git_commit {
        }
        my @update_ref = ('git-update-ref',"refs/remotes/$GIT_SVN",$commit);
        if (my $primary_parent = shift @exec_parents) {
-               push @update_ref, $primary_parent;
+               $pid = fork;
+               defined $pid or croak $!;
+               if (!$pid) {
+                       close STDERR;
+                       close STDOUT;
+                       exec 'git-rev-parse','--verify',
+                                               "refs/remotes/$GIT_SVN^0";
+               }
+               waitpid $pid, 0;
+               push @update_ref, $primary_parent unless $?;
        }
        sys(@update_ref);
        sys('git-update-ref',"$GIT_SVN/revs/$log_msg->{revision}",$commit);
@@ -995,13 +1009,37 @@ sub safe_qx {
        return wantarray ? @ret : join('',@ret);
 }
 
-sub svn_check_ignore_externals {
-       return if $_no_ignore_ext;
-       unless (grep /ignore-externals/,(safe_qx(qw(svn co -h)))) {
+sub svn_compat_check {
+       my @co_help = safe_qx(qw(svn co -h));
+       unless (grep /ignore-externals/,@co_help) {
                print STDERR "W: Installed svn version does not support ",
                                "--ignore-externals\n";
                $_no_ignore_ext = 1;
        }
+       if (grep /usage: checkout URL\[\@REV\]/,@co_help) {
+               $_svn_co_url_revs = 1;
+       }
+
+       # I really, really hope nobody hits this...
+       unless (grep /stop-on-copy/, (safe_qx(qw(svn log -h)))) {
+               print STDERR <<'';
+W: The installed svn version does not support the --stop-on-copy flag in
+   the log command.
+   Lets hope the directory you're tracking is not a branch or tag
+   and was never moved within the repository...
+
+               $_no_stop_copy = 1;
+       }
+}
+
+# *sigh*, new versions of svn won't honor -r<rev> without URL@<rev>,
+# (and they won't honor URL@<rev> without -r<rev>, too!)
+sub svn_cmd_checkout {
+       my ($url, $rev, $dir) = @_;
+       my @cmd = ('svn','co', "-r$rev");
+       push @cmd, '--ignore-externals' unless $_no_ignore_ext;
+       $url .= "\@$rev" if $_svn_co_url_revs;
+       sys(@cmd, $url, $dir);
 }
 
 sub check_upgrade_needed {
index 8e9a971..7a6e0c4 100644 (file)
@@ -162,21 +162,8 @@ COMPATIBILITY OPTIONS
        Otherwise, do not enable this flag unless you know what you're
        doing.
 
---no-stop-on-copy::
-       Only used with the 'fetch' command.
-
-       By default, git-svn passes --stop-on-copy to avoid dealing with
-       the copied/renamed branch directory problem entirely.  A
-       copied/renamed branch is the result of a <SVN_URL> being created
-       in the past from a different source.  These are problematic to
-       deal with even when working purely with svn if you work inside
-       subdirectories.
-
-       Do not use this flag unless you know exactly what you're getting
-       yourself into.  You have been warned.
-
-Examples
-~~~~~~~~
+Basic Examples
+~~~~~~~~~~~~~~
 
 Tracking and contributing to an Subversion managed-project:
 
@@ -234,6 +221,34 @@ This allows you to tie unfetched SVN revision 375 to your current HEAD::
 
        git-svn fetch 375=$(git-rev-parse HEAD)
 
+Advanced Example: Tracking a Reorganized Repository
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you're tracking a directory that has moved, or otherwise been
+branched or tagged off of another directory in the repository and you
+care about the full history of the project, then you can read this
+section.
+
+This is how Yann Dirson tracked the trunk of the ufoai directory when
+the /trunk directory of his repository was moved to /ufoai/trunk and
+he needed to continue tracking /ufoai/trunk where /trunk left off.
+
+       # This log message shows when the repository was reorganized::
+       r166 | ydirson | 2006-03-02 01:36:55 +0100 (Thu, 02 Mar 2006) | 1 line
+       Changed paths:
+          D /trunk
+          A /ufoai/trunk (from /trunk:165)
+
+       # First we start tracking the old revisions::
+       GIT_SVN_ID=git-oldsvn git-svn init \
+             https://svn.sourceforge.net/svnroot/ufoai/trunk
+       GIT_SVN_ID=git-oldsvn git-svn fetch -r1:165
+
+       # And now, we continue tracking the new revisions::
+       GIT_SVN_ID=git-newsvn git-svn init \
+             https://svn.sourceforge.net/svnroot/ufoai/ufoai/trunk
+       GIT_SVN_ID=git-newsvn git-svn fetch \
+             166=`git-rev-parse refs/remotes/git-oldsvn`
+
 BUGS
 ----
 If somebody commits a conflicting changeset to SVN at a bad moment
diff --git a/date.c b/date.c
index 416ea57..1c1917b 100644 (file)
--- a/date.c
+++ b/date.c
@@ -123,8 +123,6 @@ static const struct {
        { "IDLE", +12, 0, },    /* International Date Line East */
 };
 
-#define NR_TZ (sizeof(timezone_names) / sizeof(timezone_names[0]))
-       
 static int match_string(const char *date, const char *str)
 {
        int i = 0;
@@ -173,7 +171,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
                }
        }
 
-       for (i = 0; i < NR_TZ; i++) {
+       for (i = 0; i < ARRAY_SIZE(timezone_names); i++) {
                int match = match_string(date, timezone_names[i].name);
                if (match >= 3) {
                        int off = timezone_names[i].offset;
index 2ed5984..aaee7be 100644 (file)
@@ -40,17 +40,18 @@ struct index {
 
 static struct index ** delta_index(const unsigned char *buf,
                                   unsigned long bufsize,
+                                  unsigned long trg_bufsize,
                                   unsigned int *hash_shift)
 {
-       unsigned int hsize, hshift, entries, blksize, i;
+       unsigned int i, hsize, hshift, hlimit, entries, *hash_count;
        const unsigned char *data;
        struct index *entry, **hash;
        void *mem;
 
        /* determine index hash size */
-       entries = (bufsize + BLK_SIZE - 1) / BLK_SIZE;
+       entries = bufsize  / BLK_SIZE;
        hsize = entries / 4;
-       for (i = 4; (1 << i) < hsize && i < 16; i++);
+       for (i = 4; (1 << i) < hsize && i < 31; i++);
        hsize = 1 << i;
        hshift = 32 - i;
        *hash_shift = hshift;
@@ -63,20 +64,62 @@ static struct index ** delta_index(const unsigned char *buf,
        entry = mem + hsize * sizeof(*hash);
        memset(hash, 0, hsize * sizeof(*hash));
 
-       /* then populate it */
+       /* allocate an array to count hash entries */
+       hash_count = calloc(hsize, sizeof(*hash_count));
+       if (!hash_count) {
+               free(hash);
+               return NULL;
+       }
+
+       /* then populate the index */
        data = buf + entries * BLK_SIZE - BLK_SIZE;
-       blksize = bufsize - (data - buf);
        while (data >= buf) {
-               unsigned int val = adler32(0, data, blksize);
+               unsigned int val = adler32(0, data, BLK_SIZE);
                i = HASH(val, hshift);
                entry->ptr = data;
                entry->val = val;
                entry->next = hash[i];
                hash[i] = entry++;
-               blksize = BLK_SIZE;
+               hash_count[i]++;
                data -= BLK_SIZE;
        }
 
+       /*
+        * Determine a limit on the number of entries in the same hash
+        * bucket.  This guard us against patological data sets causing
+        * really bad hash distribution with most entries in the same hash
+        * bucket that would bring us to O(m*n) computing costs (m and n
+        * corresponding to reference and target buffer sizes).
+        *
+        * The more the target buffer is large, the more it is important to
+        * have small entry lists for each hash buckets.  With such a limit
+        * the cost is bounded to something more like O(m+n).
+        */
+       hlimit = (1 << 26) / trg_bufsize;
+       if (hlimit < 4*BLK_SIZE)
+               hlimit = 4*BLK_SIZE;
+
+       /*
+        * Now make sure none of the hash buckets has more entries than
+        * we're willing to test.  Otherwise we cull the entry list
+        * uniformly to still preserve a good repartition across
+        * the reference buffer.
+        */
+       for (i = 0; i < hsize; i++) {
+               if (hash_count[i] < hlimit)
+                       continue;
+               entry = hash[i];
+               do {
+                       struct index *keep = entry;
+                       int skip = hash_count[i] / hlimit / 2;
+                       do {
+                               entry = entry->next;
+                       } while(--skip && entry);
+                       keep->next = entry;
+               } while(entry);
+       }
+       free(hash_count);
+
        return hash;
 }
 
@@ -100,7 +143,7 @@ void *diff_delta(void *from_buf, unsigned long from_size,
 
        if (!from_size || !to_size)
                return NULL;
-       hash = delta_index(from_buf, from_size, &hash_shift);
+       hash = delta_index(from_buf, from_size, to_size, &hash_shift);
        if (!hash)
                return NULL;
 
@@ -141,29 +184,27 @@ void *diff_delta(void *from_buf, unsigned long from_size,
 
        while (data < top) {
                unsigned int moff = 0, msize = 0;
-               unsigned int blksize = MIN(top - data, BLK_SIZE);
-               unsigned int val = adler32(0, data, blksize);
-               i = HASH(val, hash_shift);
-               for (entry = hash[i]; entry; entry = entry->next) {
-                       const unsigned char *ref = entry->ptr;
-                       const unsigned char *src = data;
-                       unsigned int ref_size = ref_top - ref;
-                       if (entry->val != val)
-                               continue;
-                       if (ref_size > top - src)
-                               ref_size = top - src;
-                       while (ref_size && *src++ == *ref) {
-                               ref++;
-                               ref_size--;
-                       }
-                       ref_size = ref - entry->ptr;
-                       if (ref_size > msize) {
-                               /* this is our best match so far */
-                               moff = entry->ptr - ref_data;
-                               msize = ref_size;
-                               if (msize >= 0x10000) {
-                                       msize = 0x10000;
+               if (data + BLK_SIZE <= top) {
+                       unsigned int val = adler32(0, data, BLK_SIZE);
+                       i = HASH(val, hash_shift);
+                       for (entry = hash[i]; entry; entry = entry->next) {
+                               const unsigned char *ref = entry->ptr;
+                               const unsigned char *src = data;
+                               unsigned int ref_size = ref_top - ref;
+                               if (entry->val != val)
+                                       continue;
+                               if (ref_size > top - src)
+                                       ref_size = top - src;
+                               if (ref_size > 0x10000)
+                                       ref_size = 0x10000;
+                               if (ref_size <= msize)
                                        break;
+                               while (ref_size-- && *src++ == *ref)
+                                       ref++;
+                               if (msize < ref - entry->ptr) {
+                                       /* this is our best match so far */
+                                       msize = ref - entry->ptr;
+                                       moff = entry->ptr - ref_data;
                                }
                        }
                }
index 96cc212..590e738 100644 (file)
@@ -37,7 +37,7 @@ int execv_git_cmd(const char **argv)
                                getenv("GIT_EXEC_PATH"),
                                builtin_exec_path };
 
-       for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
+       for (i = 0; i < ARRAY_SIZE(paths); ++i) {
                const char *exec_dir = paths[i];
                const char *tmp;
 
index 4ddd676..59b2590 100644 (file)
 static int show_root = 0;
 static int show_tags = 0;
 static int show_unreachable = 0;
-static int standalone = 0;
 static int check_full = 0;
 static int check_strict = 0;
-static int keep_cache_objects = 0; 
+static int keep_cache_objects = 0;
 static unsigned char head_sha1[20];
 
 #ifdef NO_D_INO_IN_DIRENT
@@ -68,7 +67,7 @@ static void check_connectivity(void)
                        continue;
 
                if (!obj->parsed) {
-                       if (!standalone && has_sha1_file(obj->sha1))
+                       if (has_sha1_file(obj->sha1))
                                ; /* it is in pack */
                        else
                                printf("missing %s %s\n",
@@ -82,7 +81,7 @@ static void check_connectivity(void)
                        for (j = 0; j < refs->count; j++) {
                                struct object *ref = refs->ref[j];
                                if (ref->parsed ||
-                                   (!standalone && has_sha1_file(ref->sha1)))
+                                   (has_sha1_file(ref->sha1)))
                                        continue;
                                printf("broken link from %7s %s\n",
                                       obj->type, sha1_to_hex(obj->sha1));
@@ -390,7 +389,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
 
        obj = lookup_object(sha1);
        if (!obj) {
-               if (!standalone && has_sha1_file(sha1)) {
+               if (has_sha1_file(sha1)) {
                        default_refs++;
                        return 0; /* it is in a pack */
                }
@@ -464,10 +463,6 @@ int main(int argc, char **argv)
                        keep_cache_objects = 1;
                        continue;
                }
-               if (!strcmp(arg, "--standalone")) {
-                       standalone = 1;
-                       continue;
-               }
                if (!strcmp(arg, "--full")) {
                        check_full = 1;
                        continue;
@@ -477,14 +472,9 @@ int main(int argc, char **argv)
                        continue;
                }
                if (*arg == '-')
-                       usage("git-fsck-objects [--tags] [--root] [[--unreachable] [--cache] [--standalone | --full] [--strict] <head-sha1>*]");
+                       usage("git-fsck-objects [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]");
        }
 
-       if (standalone && check_full)
-               die("Only one of --standalone or --full can be used.");
-       if (standalone)
-               putenv("GIT_ALTERNATE_OBJECT_DIRECTORIES=");
-
        fsck_head_link();
        fsck_object_dir(get_object_directory());
        if (check_full) {
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
new file mode 100755 (executable)
index 0000000..6ee85d5
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+echo "/* Automatically generated by $0 */
+struct cmdname_help
+{
+    char name[16];
+    char help[64];
+};
+
+struct cmdname_help common_cmds[] = {"
+
+sort <<\EOF |
+add
+apply
+bisect
+branch
+checkout
+cherry-pick
+clone
+commit
+diff
+fetch
+grep
+init-db
+log
+merge
+mv
+prune
+pull
+push
+rebase
+reset
+revert
+rm
+show
+show-branch
+status
+tag
+verify-tag
+whatchanged
+EOF
+while read cmd
+do
+    sed -n "/NAME/,/git-$cmd/H;
+           \$ {x; s/.*git-$cmd - \\(.*\\)/  {\"$cmd\", \"\1\"},/; p}" \
+       "Documentation/git-$cmd.txt"
+done
+echo "};"
index f982b8e..5d543d2 100644 (file)
@@ -9,6 +9,8 @@
 #endif
 #endif
 
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/stat.h>
index dae383f..afe80e6 100755 (executable)
@@ -47,7 +47,7 @@ sub current_branch {
 sub shortlog {
        my ($tip) = @_;
        my @result;
-       foreach ( qx{git-log --topo-order --pretty=oneline $tip ^HEAD} ) {
+       foreach ( qx{git-log --no-merges --topo-order --pretty=oneline $tip ^HEAD} ) {
                s/^[0-9a-f]{40}\s+//;
                push @result, $_;
        }
diff --git a/git.c b/git.c
index 164d3e9..0b40e30 100644 (file)
--- a/git.c
+++ b/git.c
@@ -11,6 +11,7 @@
 #include <sys/ioctl.h>
 #include "git-compat-util.h"
 #include "exec_cmd.h"
+#include "common-cmds.h"
 
 #include "cache.h"
 #include "commit.h"
@@ -171,11 +172,29 @@ static void list_commands(const char *exec_path, const char *pattern)
        putchar('\n');
 }
 
+static void list_common_cmds_help()
+{
+       int i, longest = 0;
+
+       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+               if (longest < strlen(common_cmds[i].name))
+                       longest = strlen(common_cmds[i].name);
+       }
+
+       puts("The most commonly used git commands are:");
+       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+               printf("    %s", common_cmds[i].name);
+               mput_char(' ', longest - strlen(common_cmds[i].name) + 4);
+               puts(common_cmds[i].help);
+       }
+       puts("(use 'git help -a' to get a list of all installed git commands)");
+}
+
 #ifdef __GNUC__
-static void cmd_usage(const char *exec_path, const char *fmt, ...)
-       __attribute__((__format__(__printf__, 2, 3), __noreturn__));
+static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
+       __attribute__((__format__(__printf__, 3, 4), __noreturn__));
 #endif
-static void cmd_usage(const char *exec_path, const char *fmt, ...)
+static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
 {
        if (fmt) {
                va_list ap;
@@ -189,10 +208,13 @@ static void cmd_usage(const char *exec_path, const char *fmt, ...)
        else
                puts(git_usage);
 
-       putchar('\n');
-
-       if(exec_path)
-               list_commands(exec_path, "git-*");
+       if (exec_path) {
+               putchar('\n');
+               if (show_all)
+                       list_commands(exec_path, "git-*");
+               else
+                       list_common_cmds_help();
+        }
 
        exit(1);
 }
@@ -244,8 +266,11 @@ static int cmd_help(int argc, const char **argv, char **envp)
 {
        const char *help_cmd = argv[1];
        if (!help_cmd)
-               cmd_usage(git_exec_path(), NULL);
-       show_man_page(help_cmd);
+               cmd_usage(0, git_exec_path(), NULL);
+       else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a"))
+               cmd_usage(1, git_exec_path(), NULL);
+       else
+               show_man_page(help_cmd);
        return 0;
 }
 
@@ -323,8 +348,6 @@ static int cmd_log(int argc, const char **argv, char **envp)
        return 0;
 }
 
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
 static void handle_internal_command(int argc, const char **argv, char **envp)
 {
        const char *cmd = argv[0];
@@ -420,7 +443,7 @@ int main(int argc, const char **argv, char **envp)
                        puts(git_exec_path());
                        exit(0);
                }
-               cmd_usage(NULL, NULL);
+               cmd_usage(0, NULL, NULL);
        }
        argv[0] = cmd;
 
@@ -443,7 +466,7 @@ int main(int argc, const char **argv, char **envp)
        execv_git_cmd(argv);
 
        if (errno == ENOENT)
-               cmd_usage(exec_path, "'%s' is not a git-command", cmd);
+               cmd_usage(0, exec_path, "'%s' is not a git-command", cmd);
 
        fprintf(stderr, "Failed to run command '%s': %s\n",
                git_command, strerror(errno));
diff --git a/refs.c b/refs.c
index 982ebf8..03398cc 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -152,12 +152,12 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
                                continue;
                        }
                        if (read_ref(git_path("%s", path), sha1) < 0) {
-                               fprintf(stderr, "%s points nowhere!", path);
+                               error("%s points nowhere!", path);
                                continue;
                        }
                        if (!has_sha1_file(sha1)) {
-                               fprintf(stderr, "%s does not point to a valid "
-                                               "commit object!", path);
+                               error("%s does not point to a valid "
+                                     "commit object!", path);
                                continue;
                        }
                        retval = fn(path, sha1);
index 2a33637..713f27e 100644 (file)
@@ -82,18 +82,20 @@ void mark_parents_uninteresting(struct commit *commit)
 
        while (parents) {
                struct commit *commit = parents->item;
-               commit->object.flags |= UNINTERESTING;
-
-               /*
-                * Normally we haven't parsed the parent
-                * yet, so we won't have a parent of a parent
-                * here. However, it may turn out that we've
-                * reached this commit some other way (where it
-                * wasn't uninteresting), in which case we need
-                * to mark its parents recursively too..
-                */
-               if (commit->parents)
-                       mark_parents_uninteresting(commit);
+               if (!(commit->object.flags & UNINTERESTING)) {
+                       commit->object.flags |= UNINTERESTING;
+
+                       /*
+                        * Normally we haven't parsed the parent
+                        * yet, so we won't have a parent of a parent
+                        * here. However, it may turn out that we've
+                        * reached this commit some other way (where it
+                        * wasn't uninteresting), in which case we need
+                        * to mark its parents recursively too..
+                        */
+                       if (commit->parents)
+                               mark_parents_uninteresting(commit);
+               }
 
                /*
                 * A missing commit is ok iff its parent is marked