1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.http.test;
45
46 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
47 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_LENGTH;
48 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotNull;
52 import static org.junit.Assert.assertNull;
53 import static org.junit.Assert.assertTrue;
54 import static org.junit.Assert.fail;
55
56 import java.io.IOException;
57 import java.io.PrintWriter;
58 import java.net.URISyntaxException;
59 import java.util.Arrays;
60 import java.util.Collection;
61 import java.util.Collections;
62 import java.util.EnumSet;
63 import java.util.List;
64 import java.util.Map;
65
66 import javax.servlet.DispatcherType;
67 import javax.servlet.Filter;
68 import javax.servlet.FilterChain;
69 import javax.servlet.FilterConfig;
70 import javax.servlet.ServletException;
71 import javax.servlet.ServletRequest;
72 import javax.servlet.ServletResponse;
73 import javax.servlet.http.HttpServletRequest;
74 import javax.servlet.http.HttpServletResponse;
75
76 import org.eclipse.jetty.servlet.FilterHolder;
77 import org.eclipse.jetty.servlet.ServletContextHandler;
78 import org.eclipse.jetty.servlet.ServletHolder;
79 import org.eclipse.jgit.errors.RemoteRepositoryException;
80 import org.eclipse.jgit.errors.RepositoryNotFoundException;
81 import org.eclipse.jgit.errors.TransportException;
82 import org.eclipse.jgit.http.server.GitServlet;
83 import org.eclipse.jgit.internal.JGitText;
84 import org.eclipse.jgit.junit.TestRepository;
85 import org.eclipse.jgit.junit.TestRng;
86 import org.eclipse.jgit.junit.http.AccessEvent;
87 import org.eclipse.jgit.junit.http.HttpTestCase;
88 import org.eclipse.jgit.lib.ConfigConstants;
89 import org.eclipse.jgit.lib.Constants;
90 import org.eclipse.jgit.lib.NullProgressMonitor;
91 import org.eclipse.jgit.lib.ObjectId;
92 import org.eclipse.jgit.lib.Ref;
93 import org.eclipse.jgit.lib.ReflogEntry;
94 import org.eclipse.jgit.lib.ReflogReader;
95 import org.eclipse.jgit.lib.Repository;
96 import org.eclipse.jgit.lib.StoredConfig;
97 import org.eclipse.jgit.revwalk.RevBlob;
98 import org.eclipse.jgit.revwalk.RevCommit;
99 import org.eclipse.jgit.transport.FetchConnection;
100 import org.eclipse.jgit.transport.HttpTransport;
101 import org.eclipse.jgit.transport.RemoteRefUpdate;
102 import org.eclipse.jgit.transport.Transport;
103 import org.eclipse.jgit.transport.TransportHttp;
104 import org.eclipse.jgit.transport.URIish;
105 import org.eclipse.jgit.transport.http.HttpConnectionFactory;
106 import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory;
107 import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
108 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
109 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
110 import org.junit.Before;
111 import org.junit.Test;
112 import org.junit.runner.RunWith;
113 import org.junit.runners.Parameterized;
114 import org.junit.runners.Parameterized.Parameters;
115
116 @RunWith(Parameterized.class)
117 public class SmartClientSmartServerTest extends HttpTestCase {
118 private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";
119
120 private Repository remoteRepository;
121
122 private URIish remoteURI;
123
124 private URIish brokenURI;
125
126 private RevBlob A_txt;
127
128 private RevCommit A, B;
129
130 @Parameters
131 public static Collection<Object[]> data() {
132
133 return Arrays.asList(new Object[][] {
134 { new JDKHttpConnectionFactory() },
135 { new HttpClientConnectionFactory() } });
136 }
137
138 public SmartClientSmartServerTest(HttpConnectionFactory cf) {
139 HttpTransport.setConnectionFactory(cf);
140 }
141
142 @Before
143 public void setUp() throws Exception {
144 super.setUp();
145
146 final TestRepository<Repository> src = createTestRepository();
147 final String srcName = src.getRepository().getDirectory().getName();
148 src.getRepository()
149 .getConfig()
150 .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
151 ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
152
153 ServletContextHandler app = server.addContext("/git");
154 GitServlet gs = new GitServlet();
155 gs.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() {
156 public Repository open(HttpServletRequest req, String name)
157 throws RepositoryNotFoundException,
158 ServiceNotEnabledException {
159 if (!name.equals(srcName))
160 throw new RepositoryNotFoundException(name);
161
162 final Repository db = src.getRepository();
163 db.incrementOpen();
164 return db;
165 }
166 });
167 app.addServlet(new ServletHolder(gs), "/*");
168
169 ServletContextHandler broken = server.addContext("/bad");
170 broken.addFilter(new FilterHolder(new Filter() {
171 public void doFilter(ServletRequest request,
172 ServletResponse response, FilterChain chain)
173 throws IOException, ServletException {
174 final HttpServletResponse r = (HttpServletResponse) response;
175 r.setContentType("text/plain");
176 r.setCharacterEncoding("UTF-8");
177 PrintWriter w = r.getWriter();
178 w.print("OK");
179 w.close();
180 }
181
182 public void init(FilterConfig filterConfig) throws ServletException {
183
184 }
185
186 public void destroy() {
187
188 }
189 }), "/" + srcName + "/git-upload-pack",
190 EnumSet.of(DispatcherType.REQUEST));
191 broken.addServlet(new ServletHolder(gs), "/*");
192
193 server.setUp();
194
195 remoteRepository = src.getRepository();
196 remoteURI = toURIish(app, srcName);
197 brokenURI = toURIish(broken, srcName);
198
199 A_txt = src.blob("A");
200 A = src.commit().add("A_txt", A_txt).create();
201 B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
202 src.update(master, B);
203
204 src.update("refs/garbage/a/very/long/ref/name/to/compress", B);
205 }
206
207 @Test
208 public void testListRemote() throws IOException {
209 Repository dst = createBareRepository();
210
211 assertEquals("http", remoteURI.getScheme());
212
213 Map<String, Ref> map;
214 try (Transport t = Transport.open(dst, remoteURI)) {
215
216
217
218
219 assertTrue("isa TransportHttp", t instanceof TransportHttp);
220 assertTrue("isa HttpTransport", t instanceof HttpTransport);
221
222 FetchConnection c = t.openFetch();
223 try {
224 map = c.getRefsMap();
225 } finally {
226 c.close();
227 }
228 }
229
230 assertNotNull("have map of refs", map);
231 assertEquals(3, map.size());
232
233 assertNotNull("has " + master, map.get(master));
234 assertEquals(B, map.get(master).getObjectId());
235
236 assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
237 assertEquals(B, map.get(Constants.HEAD).getObjectId());
238
239 List<AccessEvent> requests = getRequests();
240 assertEquals(1, requests.size());
241
242 AccessEvent info = requests.get(0);
243 assertEquals("GET", info.getMethod());
244 assertEquals(join(remoteURI, "info/refs"), info.getPath());
245 assertEquals(1, info.getParameters().size());
246 assertEquals("git-upload-pack", info.getParameter("service"));
247 assertEquals(200, info.getStatus());
248 assertEquals("application/x-git-upload-pack-advertisement", info
249 .getResponseHeader(HDR_CONTENT_TYPE));
250 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
251 }
252
253 @Test
254 public void testListRemote_BadName() throws IOException, URISyntaxException {
255 Repository dst = createBareRepository();
256 URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
257 try (Transport t = Transport.open(dst, uri)) {
258 try {
259 t.openFetch();
260 fail("fetch connection opened");
261 } catch (RemoteRepositoryException notFound) {
262 assertEquals(uri + ": Git repository not found",
263 notFound.getMessage());
264 }
265 }
266
267 List<AccessEvent> requests = getRequests();
268 assertEquals(1, requests.size());
269
270 AccessEvent info = requests.get(0);
271 assertEquals("GET", info.getMethod());
272 assertEquals(join(uri, "info/refs"), info.getPath());
273 assertEquals(1, info.getParameters().size());
274 assertEquals("git-upload-pack", info.getParameter("service"));
275 assertEquals(200, info.getStatus());
276 assertEquals("application/x-git-upload-pack-advertisement",
277 info.getResponseHeader(HDR_CONTENT_TYPE));
278 }
279
280 @Test
281 public void testInitialClone_Small() throws Exception {
282 Repository dst = createBareRepository();
283 assertFalse(dst.hasObject(A_txt));
284
285 try (Transport t = Transport.open(dst, remoteURI)) {
286 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
287 }
288
289 assertTrue(dst.hasObject(A_txt));
290 assertEquals(B, dst.exactRef(master).getObjectId());
291 fsck(dst, B);
292
293 List<AccessEvent> requests = getRequests();
294 assertEquals(2, requests.size());
295
296 AccessEvent info = requests.get(0);
297 assertEquals("GET", info.getMethod());
298 assertEquals(join(remoteURI, "info/refs"), info.getPath());
299 assertEquals(1, info.getParameters().size());
300 assertEquals("git-upload-pack", info.getParameter("service"));
301 assertEquals(200, info.getStatus());
302 assertEquals("application/x-git-upload-pack-advertisement", info
303 .getResponseHeader(HDR_CONTENT_TYPE));
304 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
305
306 AccessEvent service = requests.get(1);
307 assertEquals("POST", service.getMethod());
308 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
309 assertEquals(0, service.getParameters().size());
310 assertNotNull("has content-length", service
311 .getRequestHeader(HDR_CONTENT_LENGTH));
312 assertNull("not chunked", service
313 .getRequestHeader(HDR_TRANSFER_ENCODING));
314
315 assertEquals(200, service.getStatus());
316 assertEquals("application/x-git-upload-pack-result", service
317 .getResponseHeader(HDR_CONTENT_TYPE));
318 }
319
320 @Test
321 public void testFetch_FewLocalCommits() throws Exception {
322
323
324 TestRepository dst = createTestRepository();
325 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
326 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
327 }
328 assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
329 List<AccessEvent> cloneRequests = getRequests();
330
331
332 TestRepository.BranchBuilder b = dst.branch(master);
333 for (int i = 0; i < 4; i++)
334 b.commit().tick(3600 ).message("c" + i).create();
335
336
337
338 b = new TestRepository<Repository>(remoteRepository).branch(master);
339 RevCommit Z = b.commit().message("Z").create();
340
341
342
343 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
344 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
345 }
346 assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
347
348 List<AccessEvent> requests = getRequests();
349 requests.removeAll(cloneRequests);
350 assertEquals(2, requests.size());
351
352 AccessEvent info = requests.get(0);
353 assertEquals("GET", info.getMethod());
354 assertEquals(join(remoteURI, "info/refs"), info.getPath());
355 assertEquals(1, info.getParameters().size());
356 assertEquals("git-upload-pack", info.getParameter("service"));
357 assertEquals(200, info.getStatus());
358 assertEquals("application/x-git-upload-pack-advertisement",
359 info.getResponseHeader(HDR_CONTENT_TYPE));
360
361
362
363 AccessEvent service = requests.get(1);
364 assertEquals("POST", service.getMethod());
365 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
366 assertEquals(0, service.getParameters().size());
367 assertNotNull("has content-length",
368 service.getRequestHeader(HDR_CONTENT_LENGTH));
369 assertNull("not chunked",
370 service.getRequestHeader(HDR_TRANSFER_ENCODING));
371
372 assertEquals(200, service.getStatus());
373 assertEquals("application/x-git-upload-pack-result",
374 service.getResponseHeader(HDR_CONTENT_TYPE));
375 }
376
377 @Test
378 public void testFetch_TooManyLocalCommits() throws Exception {
379
380
381 TestRepository dst = createTestRepository();
382 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
383 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
384 }
385 assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
386 List<AccessEvent> cloneRequests = getRequests();
387
388
389
390
391
392 TestRepository.BranchBuilder b = dst.branch(master);
393 for (int i = 0; i < 32 - 1; i++)
394 b.commit().tick(3600 ).message("c" + i).create();
395
396
397
398 b = new TestRepository<Repository>(remoteRepository).branch(master);
399 RevCommit Z = b.commit().message("Z").create();
400
401
402
403 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
404 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
405 }
406 assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
407
408 List<AccessEvent> requests = getRequests();
409 requests.removeAll(cloneRequests);
410 assertEquals(3, requests.size());
411
412 AccessEvent info = requests.get(0);
413 assertEquals("GET", info.getMethod());
414 assertEquals(join(remoteURI, "info/refs"), info.getPath());
415 assertEquals(1, info.getParameters().size());
416 assertEquals("git-upload-pack", info.getParameter("service"));
417 assertEquals(200, info.getStatus());
418 assertEquals("application/x-git-upload-pack-advertisement", info
419 .getResponseHeader(HDR_CONTENT_TYPE));
420
421
422
423
424 AccessEvent service = requests.get(1);
425 assertEquals("POST", service.getMethod());
426 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
427 assertEquals(0, service.getParameters().size());
428 assertNotNull("has content-length", service
429 .getRequestHeader(HDR_CONTENT_LENGTH));
430 assertNull("not chunked", service
431 .getRequestHeader(HDR_TRANSFER_ENCODING));
432
433 assertEquals(200, service.getStatus());
434 assertEquals("application/x-git-upload-pack-result", service
435 .getResponseHeader(HDR_CONTENT_TYPE));
436
437 service = requests.get(2);
438 assertEquals("POST", service.getMethod());
439 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
440 assertEquals(0, service.getParameters().size());
441 assertNotNull("has content-length", service
442 .getRequestHeader(HDR_CONTENT_LENGTH));
443 assertNull("not chunked", service
444 .getRequestHeader(HDR_TRANSFER_ENCODING));
445
446 assertEquals(200, service.getStatus());
447 assertEquals("application/x-git-upload-pack-result", service
448 .getResponseHeader(HDR_CONTENT_TYPE));
449 }
450
451 @Test
452 public void testInitialClone_BrokenServer() throws Exception {
453 Repository dst = createBareRepository();
454 assertFalse(dst.hasObject(A_txt));
455
456 try (Transport t = Transport.open(dst, brokenURI)) {
457 try {
458 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
459 fail("fetch completed despite upload-pack being broken");
460 } catch (TransportException err) {
461 String exp = brokenURI + ": expected"
462 + " Content-Type application/x-git-upload-pack-result;"
463 + " received Content-Type text/plain; charset=UTF-8";
464 assertEquals(exp, err.getMessage());
465 }
466 }
467
468 List<AccessEvent> requests = getRequests();
469 assertEquals(2, requests.size());
470
471 AccessEvent info = requests.get(0);
472 assertEquals("GET", info.getMethod());
473 assertEquals(join(brokenURI, "info/refs"), info.getPath());
474 assertEquals(1, info.getParameters().size());
475 assertEquals("git-upload-pack", info.getParameter("service"));
476 assertEquals(200, info.getStatus());
477 assertEquals("application/x-git-upload-pack-advertisement", info
478 .getResponseHeader(HDR_CONTENT_TYPE));
479
480 AccessEvent service = requests.get(1);
481 assertEquals("POST", service.getMethod());
482 assertEquals(join(brokenURI, "git-upload-pack"), service.getPath());
483 assertEquals(0, service.getParameters().size());
484 assertEquals(200, service.getStatus());
485 assertEquals("text/plain; charset=UTF-8",
486 service.getResponseHeader(HDR_CONTENT_TYPE));
487 }
488
489 @Test
490 public void testPush_NotAuthorized() throws Exception {
491 final TestRepository src = createTestRepository();
492 final RevBlob Q_txt = src.blob("new text");
493 final RevCommit Q = src.commit().add("Q", Q_txt).create();
494 final Repository db = src.getRepository();
495 final String dstName = Constants.R_HEADS + "new.branch";
496
497
498
499 try (Transport t = Transport.open(db, remoteURI)) {
500 final String srcExpr = Q.name();
501 final boolean forceUpdate = false;
502 final String localName = null;
503 final ObjectId oldId = null;
504
505 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
506 srcExpr, dstName, forceUpdate, localName, oldId);
507 try {
508 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
509 fail("anonymous push incorrectly accepted without error");
510 } catch (TransportException e) {
511 final String exp = remoteURI + ": "
512 + JGitText.get().authenticationNotSupported;
513 assertEquals(exp, e.getMessage());
514 }
515 }
516
517 List<AccessEvent> requests = getRequests();
518 assertEquals(1, requests.size());
519
520 AccessEvent info = requests.get(0);
521 assertEquals("GET", info.getMethod());
522 assertEquals(join(remoteURI, "info/refs"), info.getPath());
523 assertEquals(1, info.getParameters().size());
524 assertEquals("git-receive-pack", info.getParameter("service"));
525 assertEquals(401, info.getStatus());
526 }
527
528 @Test
529 public void testPush_CreateBranch() throws Exception {
530 final TestRepository src = createTestRepository();
531 final RevBlob Q_txt = src.blob("new text");
532 final RevCommit Q = src.commit().add("Q", Q_txt).create();
533 final Repository db = src.getRepository();
534 final String dstName = Constants.R_HEADS + "new.branch";
535
536 enableReceivePack();
537
538 try (Transport t = Transport.open(db, remoteURI)) {
539 final String srcExpr = Q.name();
540 final boolean forceUpdate = false;
541 final String localName = null;
542 final ObjectId oldId = null;
543
544 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
545 srcExpr, dstName, forceUpdate, localName, oldId);
546 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
547 }
548
549 assertTrue(remoteRepository.hasObject(Q_txt));
550 assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
551 assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
552 fsck(remoteRepository, Q);
553
554 final ReflogReader log = remoteRepository.getReflogReader(dstName);
555 assertNotNull("has log for " + dstName);
556
557 final ReflogEntry last = log.getLastEntry();
558 assertNotNull("has last entry", last);
559 assertEquals(ObjectId.zeroId(), last.getOldId());
560 assertEquals(Q, last.getNewId());
561 assertEquals("anonymous", last.getWho().getName());
562
563
564
565
566
567 final String clientHost = remoteURI.getHost();
568 assertEquals("anonymous@" + clientHost, last.getWho().getEmailAddress());
569 assertEquals("push: created", last.getComment());
570
571 List<AccessEvent> requests = getRequests();
572 assertEquals(2, requests.size());
573
574 AccessEvent info = requests.get(0);
575 assertEquals("GET", info.getMethod());
576 assertEquals(join(remoteURI, "info/refs"), info.getPath());
577 assertEquals(1, info.getParameters().size());
578 assertEquals("git-receive-pack", info.getParameter("service"));
579 assertEquals(200, info.getStatus());
580 assertEquals("application/x-git-receive-pack-advertisement", info
581 .getResponseHeader(HDR_CONTENT_TYPE));
582
583 AccessEvent service = requests.get(1);
584 assertEquals("POST", service.getMethod());
585 assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
586 assertEquals(0, service.getParameters().size());
587 assertNotNull("has content-length", service
588 .getRequestHeader(HDR_CONTENT_LENGTH));
589 assertNull("not chunked", service
590 .getRequestHeader(HDR_TRANSFER_ENCODING));
591
592 assertEquals(200, service.getStatus());
593 assertEquals("application/x-git-receive-pack-result", service
594 .getResponseHeader(HDR_CONTENT_TYPE));
595 }
596
597 @Test
598 public void testPush_ChunkedEncoding() throws Exception {
599 final TestRepository<Repository> src = createTestRepository();
600 final RevBlob Q_bin = src.blob(new TestRng("Q").nextBytes(128 * 1024));
601 final RevCommit Q = src.commit().add("Q", Q_bin).create();
602 final Repository db = src.getRepository();
603 final String dstName = Constants.R_HEADS + "new.branch";
604
605 enableReceivePack();
606
607 final StoredConfig cfg = db.getConfig();
608 cfg.setInt("core", null, "compression", 0);
609 cfg.setInt("http", null, "postbuffer", 8 * 1024);
610 cfg.save();
611
612 try (Transport t = Transport.open(db, remoteURI)) {
613 final String srcExpr = Q.name();
614 final boolean forceUpdate = false;
615 final String localName = null;
616 final ObjectId oldId = null;
617
618 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
619 srcExpr, dstName, forceUpdate, localName, oldId);
620 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
621 }
622
623 assertTrue(remoteRepository.hasObject(Q_bin));
624 assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
625 assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
626 fsck(remoteRepository, Q);
627
628 List<AccessEvent> requests = getRequests();
629 assertEquals(2, requests.size());
630
631 AccessEvent info = requests.get(0);
632 assertEquals("GET", info.getMethod());
633 assertEquals(join(remoteURI, "info/refs"), info.getPath());
634 assertEquals(1, info.getParameters().size());
635 assertEquals("git-receive-pack", info.getParameter("service"));
636 assertEquals(200, info.getStatus());
637 assertEquals("application/x-git-receive-pack-advertisement", info
638 .getResponseHeader(HDR_CONTENT_TYPE));
639
640 AccessEvent service = requests.get(1);
641 assertEquals("POST", service.getMethod());
642 assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
643 assertEquals(0, service.getParameters().size());
644 assertNull("no content-length", service
645 .getRequestHeader(HDR_CONTENT_LENGTH));
646 assertEquals("chunked", service.getRequestHeader(HDR_TRANSFER_ENCODING));
647
648 assertEquals(200, service.getStatus());
649 assertEquals("application/x-git-receive-pack-result", service
650 .getResponseHeader(HDR_CONTENT_TYPE));
651 }
652
653 private void enableReceivePack() throws IOException {
654 final StoredConfig cfg = remoteRepository.getConfig();
655 cfg.setBoolean("http", null, "receivepack", true);
656 cfg.save();
657 }
658 }