introduce "preciousObjects" repository extension

If this extension is used in a repository, then no operations should run which may drop objects from the object storage. This can be useful if you are sharing that storage with other repositories whose refs you cannot see. For instance, if you do: $ git clone -s parent child $ git -C parent config extensions.preciousObjects true $ git -C parent config core.repositoryformatversion 1 you now have additional safety when running git in the parent repository. Prunes and repacks will bail with an error, and `git gc` will skip those operations (it will continue to pack refs and do other non-object operations). Older versions of git, when run in the repository, will fail on every operation. Note that we do not set the preciousObjects extension by default when doing a "clone -s", as doing so breaks backwards compatibility. It is a decision the user should make explicitly. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jun 23, 2015 at 06:54 UTC 067fbd4105c5aa8260a73cc6961854be0e93fa03
8 files changed +50 -9
Documentation/technical/repository-version.txt
+7
@@ -79,3 +79,10 @@ The defined extensions are:
79
80 This extension does not change git's behavior at all. It is useful only
81 for testing format-1 compatibility.
82 +
83 +`preciousObjects`
84 +~~~~~~~~~~~~~~~~~
85 +
86 +When the config key `extensions.preciousObjects` is set to `true`,
87 +objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
88 +`git repack -d`).
builtin/gc.c
+11 -9
@@ -352,15 +352,17 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
352 if (gc_before_repack())
353 return -1;
354
355 - if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
356 - return error(FAILED_RUN, repack.argv[0]);
357 -
358 - if (prune_expire) {
359 - argv_array_push(&prune, prune_expire);
360 - if (quiet)
361 - argv_array_push(&prune, "--no-progress");
362 - if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
363 - return error(FAILED_RUN, prune.argv[0]);
355 + if (!repository_format_precious_objects) {
356 + if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
357 + return error(FAILED_RUN, repack.argv[0]);
358 +
359 + if (prune_expire) {
360 + argv_array_push(&prune, prune_expire);
361 + if (quiet)
362 + argv_array_push(&prune, "--no-progress");
363 + if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
364 + return error(FAILED_RUN, prune.argv[0]);
365 + }
366 }
367
368 if (prune_worktrees_expire) {
builtin/prune.c
+3
@@ -218,6 +218,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
218 return 0;
219 }
220
221 + if (repository_format_precious_objects)
222 + die(_("cannot prune in a precious-objects repo"));
223 +
224 while (argc--) {
225 unsigned char sha1[20];
226 const char *name = *argv++;
builtin/repack.c
+3
@@ -193,6 +193,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
193 argc = parse_options(argc, argv, prefix, builtin_repack_options,
194 git_repack_usage, 0);
195
196 + if (delete_redundant && repository_format_precious_objects)
197 + die(_("cannot delete packs in a precious-objects repo"));
198 +
199 if (pack_kept_objects < 0)
200 pack_kept_objects = write_bitmaps;
201
cache.h
+1
@@ -694,6 +694,7 @@ extern int grafts_replace_parents;
694 #define GIT_REPO_VERSION 0
695 #define GIT_REPO_VERSION_READ 1
696 extern int repository_format_version;
697 +extern int repository_format_precious_objects;
698 extern int check_repository_format(void);
699
700 #define MTIME_CHANGED 0x0001
environment.c
+1
@@ -26,6 +26,7 @@ int warn_ambiguous_refs = 1;
26 int warn_on_object_refname_ambiguity = 1;
27 int ref_paranoia = -1;
28 int repository_format_version;
29 +int repository_format_precious_objects;
30 const char *git_commit_encoding;
31 const char *git_log_output_encoding;
32 int shared_repository = PERM_UMASK;
setup.c
+2
@@ -367,6 +367,8 @@ static int check_repo_format(const char *var, const char *value, void *cb)
367 */
368 if (!strcmp(ext, "noop"))
369 ;
370 + else if (!strcmp(ext, "preciousobjects"))
371 + repository_format_precious_objects = git_config_bool(var, value);
372 else
373 string_list_append(&unknown_extensions, ext);
374 }
t/t1302-repo-version.sh
+22
@@ -105,4 +105,26 @@ abort 1 no-such-extension
105 allow 0 no-such-extension
106 EOF
107
108 +test_expect_success 'precious-objects allowed' '
109 + mkconfig 1 preciousObjects >.git/config &&
110 + check_allow
111 +'
112 +
113 +test_expect_success 'precious-objects blocks destructive repack' '
114 + test_must_fail git repack -ad
115 +'
116 +
117 +test_expect_success 'other repacks are OK' '
118 + test_commit foo &&
119 + git repack
120 +'
121 +
122 +test_expect_success 'precious-objects blocks prune' '
123 + test_must_fail git prune
124 +'
125 +
126 +test_expect_success 'gc runs without complaint' '
127 + git gc
128 +'
129 +
130 test_done