Skip to content

Commit 2532d89

Browse files
committed
Merge branch 'nd/fetch-depth-is-broken'
"git fetch --depth" was broken in at least three ways. The resulting history was deeper than specified by one commit, it was unclear how to wipe the shallowness of the repository with the command, and documentation was misleading. * nd/fetch-depth-is-broken: fetch: elaborate --depth action upload-pack: fix off-by-one depth calculation in shallow clone fetch: add --unshallow for turning shallow repo into complete one
2 parents 9a6c84e + cfb70e1 commit 2532d89

File tree

8 files changed

+85
-12
lines changed

8 files changed

+85
-12
lines changed

Documentation/fetch-options.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
option old data in `.git/FETCH_HEAD` will be overwritten.
99

1010
--depth=<depth>::
11-
Deepen the history of a 'shallow' repository created by
11+
Deepen or shorten the history of a 'shallow' repository created by
1212
`git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
1313
to the specified number of commits from the tip of each remote
1414
branch history. Tags for the deepened commits are not fetched.
1515

16+
--unshallow::
17+
Convert a shallow repository to a complete one, removing all
18+
the limitations imposed by shallow repositories.
19+
1620
ifndef::git-pull[]
1721
--dry-run::
1822
Show what would be done, without making any changes.

Documentation/git-fetch-pack.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ be in a separate packet, and the list must end with a flush packet.
8484

8585
--depth=<n>::
8686
Limit fetching to ancestor-chains not longer than n.
87+
'git-upload-pack' treats the special depth 2147483647 as
88+
infinite even if there is an ancestor-chain that long.
8789

8890
--no-progress::
8991
Do not show the progress.

Documentation/technical/shallow.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ It also writes an appropriate $GIT_DIR/shallow.
5353
You can deepen a shallow repository with "git-fetch --depth 20
5454
repo branch", which will fetch branch from repo, but stop at depth
5555
20, updating $GIT_DIR/shallow.
56+
57+
The special depth 2147483647 (or 0x7fffffff, the largest positive
58+
number a signed 32-bit integer can contain) means infinite depth.

builtin/fetch.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ enum {
3232

3333
static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
3434
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
35-
static int tags = TAGS_DEFAULT;
35+
static int tags = TAGS_DEFAULT, unshallow;
3636
static const char *depth;
3737
static const char *upload_pack;
3838
static struct strbuf default_rla = STRBUF_INIT;
@@ -82,6 +82,9 @@ static struct option builtin_fetch_options[] = {
8282
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
8383
OPT_STRING(0, "depth", &depth, N_("depth"),
8484
N_("deepen history of shallow clone")),
85+
{ OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
86+
N_("convert to a complete repository"),
87+
PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
8588
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
8689
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
8790
{ OPTION_STRING, 0, "recurse-submodules-default",
@@ -970,6 +973,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
970973
argc = parse_options(argc, argv, prefix,
971974
builtin_fetch_options, builtin_fetch_usage, 0);
972975

976+
if (unshallow) {
977+
if (depth)
978+
die(_("--depth and --unshallow cannot be used together"));
979+
else if (!is_repository_shallow())
980+
die(_("--unshallow on a complete repository does not make sense"));
981+
else {
982+
static char inf_depth[12];
983+
sprintf(inf_depth, "%d", INFINITE_DEPTH);
984+
depth = inf_depth;
985+
}
986+
}
987+
973988
if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
974989
if (recurse_submodules_default) {
975990
int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);

commit.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *r
163163
extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
164164
extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
165165

166+
/* largest postive number a signed 32-bit integer can contain */
167+
#define INFINITE_DEPTH 0x7fffffff
168+
166169
extern int register_shallow(const unsigned char *sha1);
167170
extern int unregister_shallow(const unsigned char *sha1);
168171
extern int for_each_commit_graft(each_commit_graft_fn, void *);

shallow.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,14 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
7272
}
7373
if (parse_commit(commit))
7474
die("invalid commit");
75-
commit->object.flags |= not_shallow_flag;
7675
cur_depth++;
76+
if (cur_depth >= depth) {
77+
commit_list_insert(commit, &result);
78+
commit->object.flags |= shallow_flag;
79+
commit = NULL;
80+
continue;
81+
}
82+
commit->object.flags |= not_shallow_flag;
7783
for (p = commit->parents, commit = NULL; p; p = p->next) {
7884
if (!p->item->util) {
7985
int *pointer = xmalloc(sizeof(int));

t/t5500-fetch-pack.sh

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,25 @@ test_expect_success 'single given branch clone' '
130130
test_must_fail git --git-dir=branch-a/.git rev-parse origin/B
131131
'
132132

133+
test_expect_success 'clone shallow depth 1' '
134+
git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 &&
135+
test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1
136+
'
137+
133138
test_expect_success 'clone shallow' '
134139
git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow
135140
'
136141

142+
test_expect_success 'clone shallow depth count' '
143+
test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 2
144+
'
145+
137146
test_expect_success 'clone shallow object count' '
138147
(
139148
cd shallow &&
140149
git count-objects -v
141150
) > count.shallow &&
142-
grep "^in-pack: 18" count.shallow
151+
grep "^in-pack: 12" count.shallow
143152
'
144153

145154
test_expect_success 'clone shallow object count (part 2)' '
@@ -256,12 +265,36 @@ test_expect_success 'additional simple shallow deepenings' '
256265
)
257266
'
258267

268+
test_expect_success 'clone shallow depth count' '
269+
test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 11
270+
'
271+
259272
test_expect_success 'clone shallow object count' '
260273
(
261274
cd shallow &&
262275
git count-objects -v
263276
) > count.shallow &&
264-
grep "^count: 52" count.shallow
277+
grep "^count: 55" count.shallow
278+
'
279+
280+
test_expect_success 'fetch --no-shallow on full repo' '
281+
test_must_fail git fetch --noshallow
282+
'
283+
284+
test_expect_success 'fetch --depth --no-shallow' '
285+
(
286+
cd shallow &&
287+
test_must_fail git fetch --depth=1 --noshallow
288+
)
289+
'
290+
291+
test_expect_success 'turn shallow to complete repository' '
292+
(
293+
cd shallow &&
294+
git fetch --unshallow &&
295+
! test -f .git/shallow &&
296+
git fsck --full
297+
)
265298
'
266299

267300
test_expect_success 'clone shallow without --no-single-branch' '
@@ -273,15 +306,15 @@ test_expect_success 'clone shallow object count' '
273306
cd shallow2 &&
274307
git count-objects -v
275308
) > count.shallow2 &&
276-
grep "^in-pack: 6" count.shallow2
309+
grep "^in-pack: 3" count.shallow2
277310
'
278311

279312
test_expect_success 'clone shallow with --branch' '
280313
git clone --depth 1 --branch A "file://$(pwd)/." shallow3
281314
'
282315

283316
test_expect_success 'clone shallow object count' '
284-
echo "in-pack: 6" > count3.expected &&
317+
echo "in-pack: 3" > count3.expected &&
285318
GIT_DIR=shallow3/.git git count-objects -v |
286319
grep "^in-pack" > count3.actual &&
287320
test_cmp count3.expected count3.actual
@@ -310,7 +343,7 @@ EOF
310343
GIT_DIR=shallow6/.git git tag -l >taglist.actual &&
311344
test_cmp taglist.expected taglist.actual &&
312345
313-
echo "in-pack: 7" > count6.expected &&
346+
echo "in-pack: 4" > count6.expected &&
314347
GIT_DIR=shallow6/.git git count-objects -v |
315348
grep "^in-pack" > count6.actual &&
316349
test_cmp count6.expected count6.actual
@@ -325,7 +358,7 @@ EOF
325358
GIT_DIR=shallow7/.git git tag -l >taglist.actual &&
326359
test_cmp taglist.expected taglist.actual &&
327360
328-
echo "in-pack: 7" > count7.expected &&
361+
echo "in-pack: 4" > count7.expected &&
329362
GIT_DIR=shallow7/.git git count-objects -v |
330363
grep "^in-pack" > count7.actual &&
331364
test_cmp count7.expected count7.actual

upload-pack.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -672,10 +672,17 @@ static void receive_needs(void)
672672
if (depth == 0 && shallows.nr == 0)
673673
return;
674674
if (depth > 0) {
675-
struct commit_list *result, *backup;
675+
struct commit_list *result = NULL, *backup = NULL;
676676
int i;
677-
backup = result = get_shallow_commits(&want_obj, depth,
678-
SHALLOW, NOT_SHALLOW);
677+
if (depth == INFINITE_DEPTH)
678+
for (i = 0; i < shallows.nr; i++) {
679+
struct object *object = shallows.objects[i].item;
680+
object->flags |= NOT_SHALLOW;
681+
}
682+
else
683+
backup = result =
684+
get_shallow_commits(&want_obj, depth,
685+
SHALLOW, NOT_SHALLOW);
679686
while (result) {
680687
struct object *object = &result->item->object;
681688
if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {

0 commit comments

Comments
 (0)