in internal/gitfs/git.go [190:287]
func (r *Repo) fetch(h Hash) (fs.FS, error) {
// Fetch a shallow packfile from the remote server.
// Shallow means it only contains the tree at that one commit,
// not the entire history of the repo.
// See https://git-scm.com/docs/protocol-v2#_fetch.
opts, ok := r.caps["fetch"]
if !ok {
return nil, fmt.Errorf("fetch: server does not support fetch")
}
if !strings.Contains(" "+opts+" ", " shallow ") {
return nil, fmt.Errorf("fetch: server does not support shallow fetch")
}
// Prepare and send request for pack file.
var buf bytes.Buffer
pw := newPktLineWriter(&buf)
pw.WriteString("command=fetch")
pw.Delim()
pw.WriteString("deepen 1")
pw.WriteString("want " + h.String())
pw.WriteString("done")
pw.Close()
postbody := buf.Bytes()
req, _ := http.NewRequest("POST", r.url+"/git-upload-pack", &buf)
req.Header.Set("Content-Type", "application/x-git-upload-pack-request")
req.Header.Set("Accept", "application/x-git-upload-pack-result")
req.Header.Set("Git-Protocol", "version=2")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("fetch: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
data, _ := ioutil.ReadAll(resp.Body)
return nil, fmt.Errorf("fetch: %v\n%s\n%s", resp.Status, data, hex.Dump(postbody))
}
if ct := resp.Header.Get("Content-Type"); ct != "application/x-git-upload-pack-result" {
return nil, fmt.Errorf("fetch: invalid response Content-Type: %v", ct)
}
// Response is sequence of pkt-line packets.
// It is plain text output (printed by git) until we find "packfile".
// Then it switches to packets with a single prefix byte saying
// what kind of data is in that packet:
// 1 for pack file data, 2 for text output, 3 for errors.
var data []byte
pr := newPktLineReader(resp.Body)
sawPackfile := false
for {
line, err := pr.Next()
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("fetch: parsing response: %v", err)
}
if line == nil { // ignore delimiter
continue
}
if !sawPackfile {
// Discard response lines until we get to packfile start.
if strings.TrimSuffix(string(line), "\n") == "packfile" {
sawPackfile = true
}
continue
}
if len(line) == 0 || line[0] == 0 || line[0] > 3 {
fmt.Printf("%q\n", line)
continue
return nil, fmt.Errorf("fetch: malformed response: invalid sideband: %q", line)
}
switch line[0] {
case 1:
data = append(data, line[1:]...)
case 2:
fmt.Printf("%s\n", line[1:])
case 3:
return nil, fmt.Errorf("fetch: server error: %s", line[1:])
}
}
if !bytes.HasPrefix(data, []byte("PACK")) {
return nil, fmt.Errorf("fetch: malformed response: not packfile")
}
// Unpack pack file and return fs.FS for the commit we downloaded.
var s store
if err := unpack(&s, data); err != nil {
return nil, fmt.Errorf("fetch: %v", err)
}
tfs, err := s.commit(h)
if err != nil {
return nil, fmt.Errorf("fetch: %v", err)
}
return tfs, nil
}