209
210
static int add_one_reference(struct string_list_item *item, void *cb_data)
211
{
212
- const char *ref_git;
213
- char *ref_git_copy;
214
-
212
+ char *ref_git;
213
+ struct strbuf alternate = STRBUF_INIT;
214
struct remote *remote;
215
struct transport *transport;
216
const struct ref *extra;
217
219
- ref_git = real_path(item->string);
220
-
221
- if (is_directory(mkpath("%s/.git/objects", ref_git)))
222
- ref_git = mkpath("%s/.git", ref_git);
223
- else if (!is_directory(mkpath("%s/objects", ref_git)))
218
+ /* Beware: real_path() and mkpath() return static buffer */
219
+ ref_git = xstrdup(real_path(item->string));
220
+ if (is_directory(mkpath("%s/.git/objects", ref_git))) {
221
+ char *ref_git_git = xstrdup(mkpath("%s/.git", ref_git));
222
+ free(ref_git);
223
+ ref_git = ref_git_git;
224
+ } else if (!is_directory(mkpath("%s/objects", ref_git)))
225
die(_("reference repository '%s' is not a local directory."),
226
item->string);
227
227
- ref_git_copy = xstrdup(ref_git);
228
-
229
- add_to_alternates_file(ref_git_copy);
228
+ strbuf_addf(&alternate, "%s/objects", ref_git);
229
+ add_to_alternates_file(alternate.buf);
230
+ strbuf_release(&alternate);
231
231
- remote = remote_get(ref_git_copy);
232
- transport = transport_get(remote, ref_git_copy);
232
+ remote = remote_get(ref_git);
233
+ transport = transport_get(remote, ref_git);
234
for (extra = transport_get_remote_refs(transport); extra;
235
extra = extra->next)
236
add_extra_ref(extra->name, extra->old_sha1, 0);
237
238
transport_disconnect(transport);
238
-
239
- free(ref_git_copy);
239
+ free(ref_git);
240
return 0;
241
}
242
245
for_each_string_list(&option_reference, add_one_reference, NULL);
246
}
247
248
-static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
248
+static void copy_alternates(struct strbuf *src, struct strbuf *dst,
249
+ const char *src_repo)
250
+{
251
+ /*
252
+ * Read from the source objects/info/alternates file
253
+ * and copy the entries to corresponding file in the
254
+ * destination repository with add_to_alternates_file().
255
+ * Both src and dst have "$path/objects/info/alternates".
256
+ *
257
+ * Instead of copying bit-for-bit from the original,
258
+ * we need to append to existing one so that the already
259
+ * created entry via "clone -s" is not lost, and also
260
+ * to turn entries with paths relative to the original
261
+ * absolute, so that they can be used in the new repository.
262
+ */
263
+ FILE *in = fopen(src->buf, "r");
264
+ struct strbuf line = STRBUF_INIT;
265
+
266
+ while (strbuf_getline(&line, in, '\n') != EOF) {
267
+ char *abs_path, abs_buf[PATH_MAX];
268
+ if (!line.len || line.buf[0] == '#')
269
+ continue;
270
+ if (is_absolute_path(line.buf)) {
271
+ add_to_alternates_file(line.buf);
272
+ continue;
273
+ }
274
+ abs_path = mkpath("%s/objects/%s", src_repo, line.buf);
275
+ normalize_path_copy(abs_buf, abs_path);
276
+ add_to_alternates_file(abs_buf);
277
+ }
278
+ strbuf_release(&line);
279
+ fclose(in);
280
+}
281
+
282
+static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
283
+ const char *src_repo, int src_baselen)
284
{
285
struct dirent *de;
286
struct stat buf;
316
}
317
if (S_ISDIR(buf.st_mode)) {
318
if (de->d_name[0] != '.')
284
- copy_or_link_directory(src, dest);
319
+ copy_or_link_directory(src, dest,
320
+ src_repo, src_baselen);
321
+ continue;
322
+ }
323
+
324
+ /* Files that cannot be copied bit-for-bit... */
325
+ if (!strcmp(src->buf + src_baselen, "/info/alternates")) {
326
+ copy_alternates(src, dest, src_repo);
327
continue;
328
}
329
346
const char *dest_repo)
347
{
348
const struct ref *ret;
307
- struct strbuf src = STRBUF_INIT;
308
- struct strbuf dest = STRBUF_INIT;
349
struct remote *remote;
350
struct transport *transport;
351
312
- if (option_shared)
313
- add_to_alternates_file(src_repo);
314
- else {
352
+ if (option_shared) {
353
+ struct strbuf alt = STRBUF_INIT;
354
+ strbuf_addf(&alt, "%s/objects", src_repo);
355
+ add_to_alternates_file(alt.buf);
356
+ strbuf_release(&alt);
357
+ } else {
358
+ struct strbuf src = STRBUF_INIT;
359
+ struct strbuf dest = STRBUF_INIT;
360
strbuf_addf(&src, "%s/objects", src_repo);
361
strbuf_addf(&dest, "%s/objects", dest_repo);
317
- copy_or_link_directory(&src, &dest);
362
+ copy_or_link_directory(&src, &dest, src_repo, src.len);
363
strbuf_release(&src);
364
strbuf_release(&dest);
365
}