From 680955702990c1d4bfb3c6feed6ae9c6cb5c3c07 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 23 Jan 2009 10:06:53 +0100 Subject: replace_object: add mechanism to replace objects found in "refs/replace/" The code implementing this mechanism has been copied more-or-less from the commit graft code. This mechanism is used in "read_sha1_file". sha1 passed to this function that match a ref name in "refs/replace/" are replaced by the sha1 that has been read in the ref. We "die" if the replacement recursion depth is too high or if we can't read the replacement object. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- replace_object.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 replace_object.c (limited to 'replace_object.c') diff --git a/replace_object.c b/replace_object.c new file mode 100644 index 0000000000..b23e1cd52a --- /dev/null +++ b/replace_object.c @@ -0,0 +1,111 @@ +#include "cache.h" +#include "sha1-lookup.h" +#include "refs.h" + +static struct replace_object { + unsigned char sha1[2][20]; +} **replace_object; + +static int replace_object_alloc, replace_object_nr; + +static const unsigned char *replace_sha1_access(size_t index, void *table) +{ + struct replace_object **replace = table; + return replace[index]->sha1[0]; +} + +static int replace_object_pos(const unsigned char *sha1) +{ + return sha1_pos(sha1, replace_object, replace_object_nr, + replace_sha1_access); +} + +static int register_replace_object(struct replace_object *replace, + int ignore_dups) +{ + int pos = replace_object_pos(replace->sha1[0]); + + if (0 <= pos) { + if (ignore_dups) + free(replace); + else { + free(replace_object[pos]); + replace_object[pos] = replace; + } + return 1; + } + pos = -pos - 1; + if (replace_object_alloc <= ++replace_object_nr) { + replace_object_alloc = alloc_nr(replace_object_alloc); + replace_object = xrealloc(replace_object, + sizeof(*replace_object) * + replace_object_alloc); + } + if (pos < replace_object_nr) + memmove(replace_object + pos + 1, + replace_object + pos, + (replace_object_nr - pos - 1) * + sizeof(*replace_object)); + replace_object[pos] = replace; + return 0; +} + +static int register_replace_ref(const char *refname, + const unsigned char *sha1, + int flag, void *cb_data) +{ + /* Get sha1 from refname */ + const char *slash = strrchr(refname, '/'); + const char *hash = slash ? slash + 1 : refname; + struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj)); + + if (strlen(hash) != 40 || get_sha1_hex(hash, repl_obj->sha1[0])) { + free(repl_obj); + warning("bad replace ref name: %s", refname); + return 0; + } + + /* Copy sha1 from the read ref */ + hashcpy(repl_obj->sha1[1], sha1); + + /* Register new object */ + if (register_replace_object(repl_obj, 1)) + die("duplicate replace ref: %s", refname); + + return 0; +} + +static void prepare_replace_object(void) +{ + static int replace_object_prepared; + + if (replace_object_prepared) + return; + + for_each_replace_ref(register_replace_ref, NULL); + replace_object_prepared = 1; +} + +/* We allow "recursive" replacement. Only within reason, though */ +#define MAXREPLACEDEPTH 5 + +const unsigned char *lookup_replace_object(const unsigned char *sha1) +{ + int pos, depth = MAXREPLACEDEPTH; + const unsigned char *cur = sha1; + + prepare_replace_object(); + + /* Try to recursively replace the object */ + do { + if (--depth < 0) + die("replace depth too high for object %s", + sha1_to_hex(sha1)); + + pos = replace_object_pos(cur); + if (0 <= pos) + cur = replace_object[pos]->sha1[1]; + } while (0 <= pos); + + return cur; +} -- cgit v1.3 From dae556bdb1e2ad6fb5eafe82e975bde01029fca9 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 23 Jan 2009 10:07:46 +0100 Subject: environment: add global variable to disable replacement This new "read_replace_refs" global variable is set to 1 by default, so that replace refs are used by default. But reachability traversal and packing commands ("cmd_fsck", "cmd_prune", "cmd_pack_objects", "upload_pack", "cmd_unpack_objects") set it to 0, as they must work with the original DAG. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- builtin-fsck.c | 1 + builtin-pack-objects.c | 2 ++ builtin-prune.c | 1 + builtin-unpack-objects.c | 2 ++ cache.h | 1 + environment.c | 1 + replace_object.c | 3 +++ t/t6050-replace.sh | 23 +++++++++++++++++++++++ upload-pack.c | 1 + 9 files changed, 35 insertions(+) (limited to 'replace_object.c') diff --git a/builtin-fsck.c b/builtin-fsck.c index 7da706cac3..bc05de6800 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -589,6 +589,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) struct alternate_object_database *alt; errors_found = 0; + read_replace_refs = 0; argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0); if (write_lost_and_found) { diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 9742b45c4d..b2c93d3d21 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -2103,6 +2103,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) int rp_ac_alloc = 64; int rp_ac; + read_replace_refs = 0; + rp_av = xcalloc(rp_ac_alloc, sizeof(*rp_av)); rp_av[0] = "pack-objects"; diff --git a/builtin-prune.c b/builtin-prune.c index 0ed9cce4a2..8459aec8e8 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -140,6 +140,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) char *s; save_commit_buffer = 0; + read_replace_refs = 0; init_revisions(&revs, prefix); argc = parse_options(argc, argv, prefix, options, prune_usage, 0); diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 9a773239ca..c9f5ac0c34 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -495,6 +495,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) int i; unsigned char sha1[20]; + read_replace_refs = 0; + git_config(git_default_config, NULL); quiet = !isatty(2); diff --git a/cache.h b/cache.h index 94b12284a2..91ef34071e 100644 --- a/cache.h +++ b/cache.h @@ -516,6 +516,7 @@ extern size_t packed_git_window_size; extern size_t packed_git_limit; extern size_t delta_base_cache_limit; extern int auto_crlf; +extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; diff --git a/environment.c b/environment.c index 801a005ef1..6d90074648 100644 --- a/environment.c +++ b/environment.c @@ -38,6 +38,7 @@ int pager_use_color = 1; const char *editor_program; const char *excludes_file; int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */ +int read_replace_refs = 1; enum safe_crlf safe_crlf = SAFE_CRLF_WARN; unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; diff --git a/replace_object.c b/replace_object.c index b23e1cd52a..eb59604fd3 100644 --- a/replace_object.c +++ b/replace_object.c @@ -94,6 +94,9 @@ const unsigned char *lookup_replace_object(const unsigned char *sha1) int pos, depth = MAXREPLACEDEPTH; const unsigned char *cur = sha1; + if (!read_replace_refs) + return sha1; + prepare_replace_object(); /* Try to recursively replace the object */ diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 334aed6216..17f6063207 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -82,6 +82,29 @@ test_expect_success 'tag replaced commit' ' git mktag .git/refs/tags/mytag 2>message ' +test_expect_success '"git fsck" works' ' + git fsck master > fsck_master.out && + grep "dangling commit $R" fsck_master.out && + grep "dangling tag $(cat .git/refs/tags/mytag)" fsck_master.out && + test -z "$(git fsck)" +' + +test_expect_success 'repack, clone and fetch work' ' + git repack -a -d && + git clone --no-hardlinks . clone_dir && + cd clone_dir && + git show HEAD~5 | grep "A U Thor" && + git show $HASH2 | grep "A U Thor" && + git cat-file commit $R && + git repack -a -d && + test_must_fail git cat-file commit $R && + git fetch ../ "refs/replace/*:refs/replace/*" && + git show HEAD~5 | grep "O Thor" && + git show $HASH2 | grep "O Thor" && + git cat-file commit $R && + cd .. +' + # # test_done diff --git a/upload-pack.c b/upload-pack.c index edc7861228..e6c4f347eb 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -618,6 +618,7 @@ int main(int argc, char **argv) int strict = 0; git_extract_argv0_path(argv[0]); + read_replace_refs = 0; for (i = 1; i < argc; i++) { char *arg = argv[i]; -- cgit v1.3