receive/send-pack: support pushing from a shallow clone
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Dec 5, 2013 at 20:02 UTC
5dbd767601812209273ae007a97b7c9305dc6cfd
5 files changed
+146
-11
Documentation/technical/pack-protocol.txt
+3
-1
@@ -464,7 +464,9 @@ contain all the objects that the server will need to complete the new
464
references.
465
466
----
467
- update-request = command-list [pack-file]
467
+ update-request = *shallow command-list [pack-file]
468
+
469
+ shallow = PKT-LINE("shallow" SP obj-id)
470
471
command-list = PKT-LINE(command NUL capability-list LF)
472
*PKT-LINE(command LF)
builtin/receive-pack.c
+69
-9
@@ -44,6 +44,7 @@ static int fix_thin = 1;
44
static const char *head_name;
45
static void *head_name_to_free;
46
static int sent_capabilities;
47
+static const char *alt_shallow_file;
48
49
static enum deny_action parse_deny_action(const char *var, const char *value)
50
{
@@ -190,6 +191,7 @@ struct command {
191
const char *error_string;
192
unsigned int skip_update:1,
193
did_not_exist:1;
194
+ int index;
195
unsigned char old_sha1[20];
196
unsigned char new_sha1[20];
197
char ref_name[FLEX_ARRAY]; /* more */
@@ -688,7 +690,7 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
690
struct command *cmd = *cmd_list;
691
692
while (cmd) {
691
- if (!is_null_sha1(cmd->new_sha1)) {
693
+ if (!is_null_sha1(cmd->new_sha1) && !cmd->skip_update) {
694
hashcpy(sha1, cmd->new_sha1);
695
*cmd_list = cmd->next;
696
return 0;
@@ -755,7 +757,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
757
}
758
}
759
758
-static struct command *read_head_info(void)
760
+static struct command *read_head_info(struct sha1_array *shallow)
761
{
762
struct command *commands = NULL;
763
struct command **p = &commands;
@@ -769,6 +771,14 @@ static struct command *read_head_info(void)
771
line = packet_read_line(0, &len);
772
if (!line)
773
break;
774
+
775
+ if (len == 48 && !prefixcmp(line, "shallow ")) {
776
+ if (get_sha1_hex(line + 8, old_sha1))
777
+ die("protocol error: expected shallow sha, got '%s'", line + 8);
778
+ sha1_array_append(shallow, old_sha1);
779
+ continue;
780
+ }
781
+
782
if (len < 83 ||
783
line[40] != ' ' ||
784
line[81] != ' ' ||
@@ -820,7 +830,7 @@ static const char *parse_pack_header(struct pack_header *hdr)
830
831
static const char *pack_lockfile;
832
823
-static const char *unpack(int err_fd)
833
+static const char *unpack(int err_fd, struct shallow_info *si)
834
{
835
struct pack_header hdr;
836
struct argv_array av = ARGV_ARRAY_INIT;
@@ -844,6 +854,11 @@ static const char *unpack(int err_fd)
854
"--pack_header=%"PRIu32",%"PRIu32,
855
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
856
857
+ if (si->nr_ours || si->nr_theirs) {
858
+ alt_shallow_file = setup_temporary_shallow(si->shallow);
859
+ argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL);
860
+ }
861
+
862
memset(&child, 0, sizeof(child));
863
if (ntohl(hdr.hdr_entries) < unpack_limit) {
864
argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL);
@@ -889,13 +904,13 @@ static const char *unpack(int err_fd)
904
return NULL;
905
}
906
892
-static const char *unpack_with_sideband(void)
907
+static const char *unpack_with_sideband(struct shallow_info *si)
908
{
909
struct async muxer;
910
const char *ret;
911
912
if (!use_sideband)
898
- return unpack(0);
913
+ return unpack(0, si);
914
915
memset(&muxer, 0, sizeof(muxer));
916
muxer.proc = copy_to_sideband;
@@ -903,12 +918,48 @@ static const char *unpack_with_sideband(void)
918
if (start_async(&muxer))
919
return NULL;
920
906
- ret = unpack(muxer.in);
921
+ ret = unpack(muxer.in, si);
922
923
finish_async(&muxer);
924
return ret;
925
}
926
927
+static void update_shallow_info(struct command *commands,
928
+ struct shallow_info *si,
929
+ struct sha1_array *ref)
930
+{
931
+ struct command *cmd;
932
+ int *ref_status;
933
+ remove_nonexistent_theirs_shallow(si);
934
+ /* XXX remove_nonexistent_ours_in_pack() */
935
+ if (!si->nr_ours && !si->nr_theirs)
936
+ return;
937
+
938
+ for (cmd = commands; cmd; cmd = cmd->next) {
939
+ if (is_null_sha1(cmd->new_sha1))
940
+ continue;
941
+ sha1_array_append(ref, cmd->new_sha1);
942
+ cmd->index = ref->nr - 1;
943
+ }
944
+ si->ref = ref;
945
+
946
+ ref_status = xmalloc(sizeof(*ref_status) * ref->nr);
947
+ assign_shallow_commits_to_refs(si, NULL, ref_status);
948
+ for (cmd = commands; cmd; cmd = cmd->next) {
949
+ if (is_null_sha1(cmd->new_sha1))
950
+ continue;
951
+ if (ref_status[cmd->index]) {
952
+ cmd->error_string = "shallow update not allowed";
953
+ cmd->skip_update = 1;
954
+ }
955
+ }
956
+ if (alt_shallow_file && *alt_shallow_file) {
957
+ unlink(alt_shallow_file);
958
+ alt_shallow_file = NULL;
959
+ }
960
+ free(ref_status);
961
+}
962
+
963
static void report(struct command *commands, const char *unpack_status)
964
{
965
struct command *cmd;
@@ -950,6 +1001,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
1001
int i;
1002
char *dir = NULL;
1003
struct command *commands;
1004
+ struct sha1_array shallow = SHA1_ARRAY_INIT;
1005
+ struct sha1_array ref = SHA1_ARRAY_INIT;
1006
+ struct shallow_info si;
1007
1008
packet_trace_identity("receive-pack");
1009
@@ -1006,11 +1060,14 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
1060
if (advertise_refs)
1061
return 0;
1062
1009
- if ((commands = read_head_info()) != NULL) {
1063
+ if ((commands = read_head_info(&shallow)) != NULL) {
1064
const char *unpack_status = NULL;
1065
1012
- if (!delete_only(commands))
1013
- unpack_status = unpack_with_sideband();
1066
+ prepare_shallow_info(&si, &shallow);
1067
+ if (!delete_only(commands)) {
1068
+ unpack_status = unpack_with_sideband(&si);
1069
+ update_shallow_info(commands, &si, &ref);
1070
+ }
1071
execute_commands(commands, unpack_status);
1072
if (pack_lockfile)
1073
unlink_or_warn(pack_lockfile);
@@ -1027,8 +1084,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
1084
}
1085
if (auto_update_server_info)
1086
update_server_info(0);
1087
+ clear_shallow_info(&si);
1088
}
1089
if (use_sideband)
1090
packet_flush(1);
1091
+ sha1_array_clear(&shallow);
1092
+ sha1_array_clear(&ref);
1093
return 0;
1094
}
builtin/send-pack.c
+1
-1
@@ -208,7 +208,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
208
(send_all && args.send_mirror))
209
usage(send_pack_usage);
210
211
- if (is_repository_shallow())
211
+ if (is_repository_shallow() && args.stateless_rpc)
212
die("attempt to push from a shallow repository");
213
214
if (remote_name) {
send-pack.c
+3
@@ -214,6 +214,9 @@ int send_pack(struct send_pack_args *args,
214
return 0;
215
}
216
217
+ if (!args->dry_run)
218
+ advertise_shallow_grafts(out);
219
+
220
/*
221
* Finally, tell the other end!
222
*/
t/t5538-push-shallow.sh
new
+70
@@ -0,0 +1,70 @@
1
+#!/bin/sh
2
+
3
+test_description='push from/to a shallow clone'
4
+
5
+. ./test-lib.sh
6
+
7
+commit() {
8
+ echo "$1" >tracked &&
9
+ git add tracked &&
10
+ git commit -m "$1"
11
+}
12
+
13
+test_expect_success 'setup' '
14
+ git config --global transfer.fsckObjects true &&
15
+ commit 1 &&
16
+ commit 2 &&
17
+ commit 3 &&
18
+ commit 4 &&
19
+ (
20
+ git init full-abc &&
21
+ cd full-abc &&
22
+ commit a &&
23
+ commit b &&
24
+ commit c
25
+ ) &&
26
+ git clone --no-local --depth=2 .git shallow &&
27
+ git --git-dir=shallow/.git log --format=%s >actual &&
28
+ cat <<EOF >expect &&
29
+4
30
+3
31
+EOF
32
+ test_cmp expect actual &&
33
+ git clone --no-local --depth=2 full-abc/.git shallow2 &&
34
+ git --git-dir=shallow2/.git log --format=%s >actual &&
35
+ cat <<EOF >expect &&
36
+c
37
+b
38
+EOF
39
+ test_cmp expect actual
40
+'
41
+
42
+test_expect_success 'push from shallow clone' '
43
+ (
44
+ cd shallow &&
45
+ commit 5 &&
46
+ git push ../.git +master:refs/remotes/shallow/master
47
+ ) &&
48
+ git log --format=%s shallow/master >actual &&
49
+ git fsck &&
50
+ cat <<EOF >expect &&
51
+5
52
+4
53
+3
54
+2
55
+1
56
+EOF
57
+ test_cmp expect actual
58
+'
59
+
60
+test_expect_success 'push from shallow clone, with grafted roots' '
61
+ (
62
+ cd shallow2 &&
63
+ test_must_fail git push ../.git +master:refs/remotes/shallow2/master 2>err &&
64
+ grep "shallow2/master.*shallow update not allowed" err
65
+ ) &&
66
+ test_must_fail git rev-parse shallow2/master &&
67
+ git fsck
68
+'
69
+
70
+test_done