Skip to content

Commit 6035d6a

Browse files
pcloudsgitster
authored andcommitted
fetch-pack: prepare updated shallow file before fetching the pack
index-pack --strict looks up and follows parent commits. If shallow information is not ready by the time index-pack is run, index-pack may be led to non-existent objects. Make fetch-pack save shallow file to disk before invoking index-pack. git learns new global option --shallow-file to pass on the alternate shallow file path. Undocumented (and not even support --shallow-file= syntax) because it's unlikely to be used again elsewhere. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 0781aa4 commit 6035d6a

File tree

5 files changed

+93
-38
lines changed

5 files changed

+93
-38
lines changed

commit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);
176176
extern int is_repository_shallow(void);
177177
extern struct commit_list *get_shallow_commits(struct object_array *heads,
178178
int depth, int shallow_flag, int not_shallow_flag);
179+
extern void check_shallow_file_for_update(void);
180+
extern void set_alternate_shallow_file(const char *path);
179181

180182
int is_descendant_of(struct commit *, struct commit_list *);
181183
int in_merge_bases(struct commit *, struct commit *);

fetch-pack.c

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ static int no_done;
2020
static int fetch_fsck_objects = -1;
2121
static int transfer_fsck_objects = -1;
2222
static int agent_supported;
23+
static struct lock_file shallow_lock;
24+
static const char *alternate_shallow_file;
2325

2426
#define COMPLETE (1U << 0)
2527
#define COMMON (1U << 1)
@@ -683,7 +685,7 @@ static int get_pack(struct fetch_pack_args *args,
683685
int xd[2], char **pack_lockfile)
684686
{
685687
struct async demux;
686-
const char *argv[20];
688+
const char *argv[22];
687689
char keep_arg[256];
688690
char hdr_arg[256];
689691
const char **av;
@@ -724,6 +726,11 @@ static int get_pack(struct fetch_pack_args *args,
724726
do_keep = 1;
725727
}
726728

729+
if (alternate_shallow_file) {
730+
*av++ = "--shallow-file";
731+
*av++ = alternate_shallow_file;
732+
}
733+
727734
if (do_keep) {
728735
if (pack_lockfile)
729736
cmd.out = -1;
@@ -779,6 +786,27 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
779786
return strcmp(a->name, b->name);
780787
}
781788

789+
static void setup_alternate_shallow(void)
790+
{
791+
struct strbuf sb = STRBUF_INIT;
792+
int fd;
793+
794+
check_shallow_file_for_update();
795+
fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
796+
LOCK_DIE_ON_ERROR);
797+
if (write_shallow_commits(&sb, 0)) {
798+
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
799+
die_errno("failed to write to %s", shallow_lock.filename);
800+
alternate_shallow_file = shallow_lock.filename;
801+
} else
802+
/*
803+
* is_repository_shallow() sees empty string as "no
804+
* shallow file".
805+
*/
806+
alternate_shallow_file = "";
807+
strbuf_release(&sb);
808+
}
809+
782810
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
783811
int fd[2],
784812
const struct ref *orig_ref,
@@ -858,6 +886,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
858886

859887
if (args->stateless_rpc)
860888
packet_flush(fd[1]);
889+
if (args->depth > 0)
890+
setup_alternate_shallow();
861891
if (get_pack(args, fd, pack_lockfile))
862892
die("git fetch-pack: fetch failed.");
863893

@@ -936,15 +966,9 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
936966
struct ref **sought, int nr_sought,
937967
char **pack_lockfile)
938968
{
939-
struct stat st;
940969
struct ref *ref_cpy;
941970

942971
fetch_pack_setup();
943-
if (args->depth > 0) {
944-
if (stat(git_path("shallow"), &st))
945-
st.st_mtime = 0;
946-
}
947-
948972
if (nr_sought)
949973
nr_sought = remove_duplicates_in_refs(sought, nr_sought);
950974

@@ -954,35 +978,12 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
954978
}
955979
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
956980

957-
if (args->depth > 0) {
958-
static struct lock_file lock;
959-
struct cache_time mtime;
960-
struct strbuf sb = STRBUF_INIT;
961-
char *shallow = git_path("shallow");
962-
int fd;
963-
964-
mtime.sec = st.st_mtime;
965-
mtime.nsec = ST_MTIME_NSEC(st);
966-
if (stat(shallow, &st)) {
967-
if (mtime.sec)
968-
die("shallow file was removed during fetch");
969-
} else if (st.st_mtime != mtime.sec
970-
#ifdef USE_NSEC
971-
|| ST_MTIME_NSEC(st) != mtime.nsec
972-
#endif
973-
)
974-
die("shallow file was changed during fetch");
975-
976-
fd = hold_lock_file_for_update(&lock, shallow,
977-
LOCK_DIE_ON_ERROR);
978-
if (!write_shallow_commits(&sb, 0)
979-
|| write_in_full(fd, sb.buf, sb.len) != sb.len) {
980-
unlink_or_warn(shallow);
981-
rollback_lock_file(&lock);
982-
} else {
983-
commit_lock_file(&lock);
984-
}
985-
strbuf_release(&sb);
981+
if (alternate_shallow_file) {
982+
if (*alternate_shallow_file == '\0') { /* --unshallow */
983+
unlink_or_warn(git_path("shallow"));
984+
rollback_lock_file(&shallow_lock);
985+
} else
986+
commit_lock_file(&shallow_lock);
986987
}
987988

988989
reprepare_packed_git();

git.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "help.h"
55
#include "quote.h"
66
#include "run-command.h"
7+
#include "commit.h"
78

89
const char git_usage_string[] =
910
"git [--version] [--help] [-c name=value]\n"
@@ -146,6 +147,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
146147
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
147148
if (envchanged)
148149
*envchanged = 1;
150+
} else if (!strcmp(cmd, "--shallow-file")) {
151+
(*argv)++;
152+
(*argc)--;
153+
set_alternate_shallow_file((*argv)[0]);
154+
if (envchanged)
155+
*envchanged = 1;
149156
} else {
150157
fprintf(stderr, "Unknown option: %s\n", cmd);
151158
usage(git_usage_string);

shallow.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
#include "tag.h"
44

55
static int is_shallow = -1;
6+
static struct stat shallow_stat;
7+
static char *alternate_shallow_file;
8+
9+
void set_alternate_shallow_file(const char *path)
10+
{
11+
if (is_shallow != -1)
12+
die("BUG: is_repository_shallow must not be called before set_alternate_shallow_file");
13+
free(alternate_shallow_file);
14+
alternate_shallow_file = path ? xstrdup(path) : NULL;
15+
}
616

717
int register_shallow(const unsigned char *sha1)
818
{
@@ -21,12 +31,21 @@ int is_repository_shallow(void)
2131
{
2232
FILE *fp;
2333
char buf[1024];
34+
const char *path = alternate_shallow_file;
2435

2536
if (is_shallow >= 0)
2637
return is_shallow;
2738

28-
fp = fopen(git_path("shallow"), "r");
29-
if (!fp) {
39+
if (!path)
40+
path = git_path("shallow");
41+
/*
42+
* fetch-pack sets '--shallow-file ""' as an indicator that no
43+
* shallow file should be used. We could just open it and it
44+
* will likely fail. But let's do an explicit check instead.
45+
*/
46+
if (!*path ||
47+
stat(path, &shallow_stat) ||
48+
(fp = fopen(path, "r")) == NULL) {
3049
is_shallow = 0;
3150
return is_shallow;
3251
}
@@ -108,3 +127,22 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
108127

109128
return result;
110129
}
130+
131+
void check_shallow_file_for_update(void)
132+
{
133+
struct stat st;
134+
135+
if (!is_shallow)
136+
return;
137+
else if (is_shallow == -1)
138+
die("BUG: shallow must be initialized by now");
139+
140+
if (stat(git_path("shallow"), &st))
141+
die("shallow file was removed during fetch");
142+
else if (st.st_mtime != shallow_stat.st_mtime
143+
#ifdef USE_NSEC
144+
|| ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat)
145+
#endif
146+
)
147+
die("shallow file was changed during fetch");
148+
}

t/t5500-fetch-pack.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ test_expect_success 'clone shallow depth 1' '
135135
test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1
136136
'
137137

138+
test_expect_success 'clone shallow depth 1 with fsck' '
139+
git config --global fetch.fsckobjects true &&
140+
git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0fsck &&
141+
test "`git --git-dir=shallow0fsck/.git rev-list --count HEAD`" = 1 &&
142+
git config --global --unset fetch.fsckobjects
143+
'
144+
138145
test_expect_success 'clone shallow' '
139146
git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow
140147
'

0 commit comments

Comments
 (0)