From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Cc: Hui Wang <jason77.wang@gmail.com>
Subject: [PATCH 2/2] clone: clone from a repository with relative alternates
Date: Mon, 22 Aug 2011 18:05:16 -0700 [thread overview]
Message-ID: <1314061516-24964-3-git-send-email-gitster@pobox.com> (raw)
In-Reply-To: <1314061516-24964-1-git-send-email-gitster@pobox.com>
Cloning from a local repository blindly copies or hardlinks all the files
under objects/ hierarchy. This results in two issues:
- If the repository cloned has an "objects/info/alternates" file, and the
command line of clone specifies --reference, the ones specified on the
command line get overwritten by the copy from the original repository.
- An entry in a "objects/info/alternates" file can specify the object
stores it borrows objects from as a path relative to the "objects/"
directory. When cloning a repository with such an alternates file, if
the new repository is not sitting next to the original repository, such
relative paths needs to be adjusted so that they can be used in the new
repository.
This updates add_to_alternates_file() to take the path to the alternate
object store, including the "/objects" part at the end (earlier, it was
taking the path to $GIT_DIR and was adding "/objects" itself), as it is
technically possible to specify in objects/info/alternates file the path
of a directory whose name does not end with "/objects".
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/clone.c | 52 ++++++++++++++++++++++++++++++++++++++++------------
sha1_file.c | 2 +-
t/t5601-clone.sh | 10 +++++++++-
3 files changed, 50 insertions(+), 14 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index ee5d651..2842707 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -210,8 +210,7 @@ static void strip_trailing_slashes(char *dir)
static int add_one_reference(struct string_list_item *item, void *cb_data)
{
const char *ref_git;
- char *ref_git_copy;
-
+ struct strbuf alternate = STRBUF_INIT;
struct remote *remote;
struct transport *transport;
const struct ref *extra;
@@ -224,19 +223,17 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
die(_("reference repository '%s' is not a local directory."),
item->string);
- ref_git_copy = xstrdup(ref_git);
-
- add_to_alternates_file(ref_git_copy);
+ strbuf_addf(&alternate, "%s/objects", ref_git);
+ add_to_alternates_file(alternate.buf);
+ strbuf_release(&alternate);
- remote = remote_get(ref_git_copy);
- transport = transport_get(remote, ref_git_copy);
+ remote = remote_get(ref_git);
+ transport = transport_get(remote, ref_git);
for (extra = transport_get_remote_refs(transport); extra;
extra = extra->next)
add_extra_ref(extra->name, extra->old_sha1, 0);
transport_disconnect(transport);
-
- free(ref_git_copy);
return 0;
}
@@ -245,7 +242,32 @@ static void setup_reference(void)
for_each_string_list(&option_reference, add_one_reference, NULL);
}
-static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
+static void copy_alternates(struct strbuf *src, struct strbuf *dst,
+ const char *src_repo)
+{
+ /*
+ * Read from the source objects/info/alternates file
+ * and copy the entries to corresponding file in the
+ * destination repository with add_to_alternates_file().
+ * Both src and dst have "$path/objects/info/alternates".
+ */
+ FILE *in = fopen(src->buf, "r");
+ struct strbuf line = STRBUF_INIT;
+
+ while (strbuf_getline(&line, in, '\n') != EOF) {
+ char *abs_path, abs_buf[PATH_MAX];
+ if (!line.len || line.buf[0] == '#')
+ continue;
+ abs_path = mkpath("%s/objects/%s", src_repo, line.buf);
+ normalize_path_copy(abs_buf, abs_path);
+ add_to_alternates_file(abs_buf);
+ }
+ strbuf_release(&line);
+ fclose(in);
+}
+
+static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+ const char *src_repo, int src_baselen)
{
struct dirent *de;
struct stat buf;
@@ -281,7 +303,13 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
}
if (S_ISDIR(buf.st_mode)) {
if (de->d_name[0] != '.')
- copy_or_link_directory(src, dest);
+ copy_or_link_directory(src, dest,
+ src_repo, src_baselen);
+ continue;
+ }
+
+ if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
+ copy_alternates(src, dest, src_repo);
continue;
}
@@ -314,7 +342,7 @@ static const struct ref *clone_local(const char *src_repo,
else {
strbuf_addf(&src, "%s/objects", src_repo);
strbuf_addf(&dest, "%s/objects", dest_repo);
- copy_or_link_directory(&src, &dest);
+ copy_or_link_directory(&src, &dest, src_repo, src.len);
strbuf_release(&src);
strbuf_release(&dest);
}
diff --git a/sha1_file.c b/sha1_file.c
index 064a330..f7c3408 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -380,7 +380,7 @@ void add_to_alternates_file(const char *reference)
{
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR);
- char *alt = mkpath("%s/objects\n", reference);
+ char *alt = mkpath("%s\n", reference);
write_or_die(fd, alt, strlen(alt));
if (commit_lock_file(lock))
die("could not close alternates file");
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 0163ad1..d87214c 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -207,7 +207,7 @@ test_expect_success 'clone separate gitdir where target already exists' '
test_must_fail git clone --separate-git-dir realgitdir src dst
'
-test_expect_failure 'clone --reference from original' '
+test_expect_success 'clone --reference from original' '
git clone --shared --bare src src-1 &&
git clone --bare src src-2 &&
git clone --reference=src-2 --bare src-1 target-8 &&
@@ -222,4 +222,12 @@ test_expect_success 'clone with more than one --reference' '
grep /src-4/ target-9/.git/objects/info/alternates
'
+test_expect_success 'clone from original with relative alternate' '
+ mkdir nest &&
+ git clone --bare src nest/src-5 &&
+ echo ../../../src/.git/objects >nest/src-5/objects/info/alternates &&
+ git clone --bare nest/src-5 target-10 &&
+ grep /src/\\.git/objects target-10/objects/info/alternates
+'
+
test_done
--
1.7.6.557.gcee42
next prev parent reply other threads:[~2011-08-23 1:05 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-22 9:05 [PATCH v2 0/1] git-clone: fix relative path problem in the alternates Hui Wang
2011-08-22 9:05 ` [PATCH v2 1/1] clone: replace relative paths " Hui Wang
2011-08-22 19:10 ` [PATCH v2 0/1] git-clone: fix relative path problem " Junio C Hamano
2011-08-22 20:38 ` Junio C Hamano
2011-08-22 21:57 ` Junio C Hamano
2011-08-23 1:05 ` [PATCH 0/2] clone-local fixup Junio C Hamano
2011-08-23 1:05 ` [PATCH 1/2] clone: allow more than one --reference Junio C Hamano
2011-08-23 1:05 ` Junio C Hamano [this message]
2011-08-23 3:43 ` [PATCH 0/2] clone-local fixup Hui Wang
2011-08-23 16:26 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1314061516-24964-3-git-send-email-gitster@pobox.com \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
--cc=jason77.wang@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).