Skip to content

Commit 02322e1

Browse files
committed
send-pack: do not send unknown object name from ".have" to pack-objects
v1.6.1 introduced ".have" extension to the protocol to allow the receiving side to advertise objects that are reachable from refs in the repositories it borrows from. This was meant to be used by the sending side to avoid sending such objects; they are already available through the alternates mechanism. The client side implementation in v1.6.1, which was introduced with 40c155f (push: prepare sender to receive extended ref information from the receiver, 2008-09-09) aka v1.6.1-rc1~203^2~1, were faulty in that it did not consider the possiblity that the repository receiver borrows from might have objects it does not know about. This fixes it by refraining from passing missing commits to underlying pack-objects. Revision machinery may need to be tightened further to treat missing uninteresting objects as non-error events, but this is an obvious and safe fix for a maintenance release that is almost good enough. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 899d8dc commit 02322e1

File tree

2 files changed

+127
-22
lines changed

2 files changed

+127
-22
lines changed

builtin-send-pack.c

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ static struct send_pack_args args = {
1515
/* .receivepack = */ "git-receive-pack",
1616
};
1717

18+
static int feed_object(const unsigned char *sha1, int fd, int negative)
19+
{
20+
char buf[42];
21+
22+
if (negative && !has_sha1_file(sha1))
23+
return 1;
24+
25+
memcpy(buf + negative, sha1_to_hex(sha1), 40);
26+
if (negative)
27+
buf[0] = '^';
28+
buf[40 + negative] = '\n';
29+
return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
30+
}
31+
1832
/*
1933
* Make a pack stream and spit it out into file descriptor fd
2034
*/
@@ -35,7 +49,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
3549
};
3650
struct child_process po;
3751
int i;
38-
char buf[42];
3952

4053
if (args.use_thin_pack)
4154
argv[4] = "--thin";
@@ -51,31 +64,17 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
5164
* We feed the pack-objects we just spawned with revision
5265
* parameters by writing to the pipe.
5366
*/
54-
for (i = 0; i < extra->nr; i++) {
55-
memcpy(buf + 1, sha1_to_hex(&extra->array[i][0]), 40);
56-
buf[0] = '^';
57-
buf[41] = '\n';
58-
if (!write_or_whine(po.in, buf, 42, "send-pack: send refs"))
67+
for (i = 0; i < extra->nr; i++)
68+
if (!feed_object(extra->array[i], po.in, 1))
5969
break;
60-
}
6170

6271
while (refs) {
6372
if (!is_null_sha1(refs->old_sha1) &&
64-
has_sha1_file(refs->old_sha1)) {
65-
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
66-
buf[0] = '^';
67-
buf[41] = '\n';
68-
if (!write_or_whine(po.in, buf, 42,
69-
"send-pack: send refs"))
70-
break;
71-
}
72-
if (!is_null_sha1(refs->new_sha1)) {
73-
memcpy(buf, sha1_to_hex(refs->new_sha1), 40);
74-
buf[40] = '\n';
75-
if (!write_or_whine(po.in, buf, 41,
76-
"send-pack: send refs"))
77-
break;
78-
}
73+
!feed_object(refs->old_sha1, po.in, 1))
74+
break;
75+
if (!is_null_sha1(refs->new_sha1) &&
76+
!feed_object(refs->new_sha1, po.in, 0))
77+
break;
7978
refs = refs->next;
8079
}
8180

t/t5519-push-alternates.sh

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/bin/sh
2+
3+
test_description='push to a repository that borrows from elsewhere'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success setup '
8+
mkdir alice-pub &&
9+
(
10+
cd alice-pub &&
11+
GIT_DIR=. git init
12+
) &&
13+
mkdir alice-work &&
14+
(
15+
cd alice-work &&
16+
git init &&
17+
>file &&
18+
git add . &&
19+
git commit -m initial &&
20+
git push ../alice-pub master
21+
) &&
22+
23+
# Project Bob is a fork of project Alice
24+
mkdir bob-pub &&
25+
(
26+
cd bob-pub &&
27+
GIT_DIR=. git init &&
28+
mkdir -p objects/info &&
29+
echo ../../alice-pub/objects >objects/info/alternates
30+
) &&
31+
git clone alice-pub bob-work &&
32+
(
33+
cd bob-work &&
34+
git push ../bob-pub master
35+
)
36+
'
37+
38+
test_expect_success 'alice works and pushes' '
39+
(
40+
cd alice-work &&
41+
echo more >file &&
42+
git commit -a -m second &&
43+
git push ../alice-pub
44+
)
45+
'
46+
47+
test_expect_success 'bob fetches from alice, works and pushes' '
48+
(
49+
# Bob acquires what Alice did in his work tree first.
50+
# Even though these objects are not directly in
51+
# the public repository of Bob, this push does not
52+
# need to send the commit Bob received from Alice
53+
# to his public repository, as all the object Alice
54+
# has at her public repository are available to it
55+
# via its alternates.
56+
cd bob-work &&
57+
git pull ../alice-pub master &&
58+
echo more bob >file &&
59+
git commit -a -m third &&
60+
git push ../bob-pub
61+
) &&
62+
63+
# Check that the second commit by Alice is not sent
64+
# to ../bob-pub
65+
(
66+
cd bob-pub &&
67+
second=$(git rev-parse HEAD^) &&
68+
rm -f objects/info/alternates &&
69+
test_must_fail git cat-file -t $second &&
70+
echo ../../alice-pub/objects >objects/info/alternates
71+
)
72+
'
73+
74+
test_expect_success 'clean-up in case the previous failed' '
75+
(
76+
cd bob-pub &&
77+
echo ../../alice-pub/objects >objects/info/alternates
78+
)
79+
'
80+
81+
test_expect_success 'alice works and pushes again' '
82+
(
83+
# Alice does not care what Bob does. She does not
84+
# even have to be aware of his existence. She just
85+
# keeps working and pushing
86+
cd alice-work &&
87+
echo more alice >file &&
88+
git commit -a -m fourth &&
89+
git push ../alice-pub
90+
)
91+
'
92+
93+
test_expect_success 'bob works and pushes' '
94+
(
95+
# This time Bob does not pull from Alice, and
96+
# the master branch at her public repository points
97+
# at a commit Bob does not know about. This should
98+
# not prevent the push by Bob from succeeding.
99+
cd bob-work &&
100+
echo yet more bob >file &&
101+
git commit -a -m fifth &&
102+
git push ../bob-pub
103+
)
104+
'
105+
106+
test_done

0 commit comments

Comments
 (0)