git repack: keep commits hidden by a graft
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Thu, 23 Jul 2009 15:33:49 +0000 (17:33 +0200)
committerJunio C Hamano <gitster@pobox.com>
Fri, 24 Jul 2009 16:10:16 +0000 (09:10 -0700)
When you have grafts that pretend that a given commit has different
parents than the ones recorded in the commit object, it is dangerous
to let 'git repack' remove those hidden parents, as you can easily
remove the graft and end up with a broken repository.

So let's play it safe and keep those parent objects and everything
that is reachable by them, in addition to the grafted parents.

As this behavior can only be triggered by git pack-objects, and as that
command handles duplicate parents gracefully, we do not bother to cull
duplicated parents that may result by using both true and grafted
parents.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-pack-objects.txt
builtin-pack-objects.c
cache.h
commit.c
environment.c
git-repack.sh
t/t7700-repack.sh
index 7d4c1a75562de80aa80dfbfa665330b14ec948c6..2e4992970e84a1789cb97d35969976d12e5a30e1 100644 (file)
@@ -11,7 +11,8 @@ SYNOPSIS
 [verse]
 'git pack-objects' [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty]
        [--local] [--incremental] [--window=N] [--depth=N] [--all-progress]
-       [--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
+       [--revs [--unpacked | --all]*] [--stdout | base-name]
+       [--keep-true-parents] < object-list
 
 
 DESCRIPTION
@@ -197,6 +198,10 @@ base-name::
        to force the version for the generated pack index, and to force
        64-bit index entries on objects located above the given offset.
 
+--keep-true-parents::
+       With this option, parents that are hidden by grafts are packed
+       nevertheless.
+
 
 Author
 ------
index 941cc2d73cf5ee6791a0cee8c409dcdb9756b448..527638168bec1a25bf89ab13771b9541b1504713 100644 (file)
@@ -2259,6 +2259,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                                die("bad %s", arg);
                        continue;
                }
+               if (!strcmp(arg, "--keep-true-parents")) {
+                       grafts_replace_parents = 0;
+                       continue;
+               }
                usage(pack_usage);
        }
 
diff --git a/cache.h b/cache.h
index b8503ad91c3b13ccaf87a6f596d13918f7ae114b..e902008297007f1f212af8773be1fbda2bb25156 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -561,6 +561,8 @@ enum object_creation_mode {
 
 extern enum object_creation_mode object_creation_mode;
 
+extern int grafts_replace_parents;
+
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
 extern int check_repository_format(void);
index aa3b35b6a86891ac9d0628e20a6a46d506bf7700..f69525a089de906f76046952824f5ba5c73f3537 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -266,7 +266,11 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
                    bufptr[47] != '\n')
                        return error("bad parents in commit %s", sha1_to_hex(item->object.sha1));
                bufptr += 48;
-               if (graft)
+               /*
+                * The clone is shallow if nr_parent < 0, and we must
+                * not traverse its real parents even when we unhide them.
+                */
+               if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
                        continue;
                new_parent = lookup_commit(parent);
                if (new_parent)
index 801a005ef1b23ef13cfa9ece676c550fe35dedc0..477d2e4da852356df21dadc47a82f106f8320a52 100644 (file)
@@ -47,6 +47,7 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
 #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
 #endif
 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
+int grafts_replace_parents = 1;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
index 0868734723b3c96144bfa9360a9e19ebae1995f7..be0c8435dccabd686ec07808c67f5cf569209ee2 100755 (executable)
@@ -81,7 +81,7 @@ case ",$all_into_one," in
 esac
 
 args="$args $local $quiet $no_reuse$extra"
-names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
+names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
        exit 1
 if [ -z "$names" ]; then
        if test -z "$quiet"; then
index a4dddb728f1a580f31df67eafa759d8bddf939e2..f4aa0547501a19fe570304e830504ff984f5a9a9 100755 (executable)
@@ -149,7 +149,7 @@ test_expect_success 'local packed unreachable obs that exist in alternate ODB ar
        test_must_fail git show $csha1
 '
 
-test_expect_failure 'objects made unreachable by grafts only are kept' '
+test_expect_success 'objects made unreachable by grafts only are kept' '
        test_tick &&
        git commit --allow-empty -m "commit 4" &&
        H0=$(git rev-parse HEAD) &&