cerrado @ e1664fcbc4685906d3dabc66bf947a17bce7efc0

feat: Add archive capability
diff --git a/pkg/ext/mime.go b/pkg/ext/mime.go
index 6da66e3db03709439e1a8731116081dd5fe738bb..c42d4de563775a21af2511f6b2dc18562f62626a 100644
--- a/pkg/ext/mime.go
+++ b/pkg/ext/mime.go
@@ -5,7 +5,8 @@
 type ContentType = string
 
 const (
-	TextHTML ContentType = "text/html"
+	TextHTML        ContentType = "text/html"
+	ApplicationGZip ContentType = "application/gzip"
 )
 
 func Html(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
@@ -14,9 +15,17 @@ 		next(w, r)
 	}
 }
 
+func SetFileName(w http.ResponseWriter, name string) {
+	h := "inline; filename=\"" + name + "\""
+	w.Header().Add("Content-Disposition", h)
+}
+
 func SetHTML(w http.ResponseWriter) {
 	SetMIME(w, TextHTML)
+}
 
+func SetGZip(w http.ResponseWriter) {
+	SetMIME(w, ApplicationGZip)
 }
 
 func SetMIME(w http.ResponseWriter, mime ContentType) {
diff --git a/pkg/git/git.go b/pkg/git/git.go
index b725cd875a2615e043e4b15cad5b6bfc98860a85..591fafb069b141c9e7089f6b6982349b396feef4 100644
--- a/pkg/git/git.go
+++ b/pkg/git/git.go
@@ -1,9 +1,13 @@
 package git
 
 import (
+	"archive/tar"
 	"errors"
 	"fmt"
 	"io"
+	"io/fs"
+	"path"
+	"time"
 
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
@@ -25,6 +29,13 @@
 		ref plumbing.Hash
 		// this is setRef when ref is setRef
 		setRef bool
+	}
+	infoWrapper struct {
+		name    string
+		size    int64
+		mode    fs.FileMode
+		modTime time.Time
+		isDir   bool
 	}
 )
 
@@ -213,3 +224,110 @@ 	} else {
 		return "Binary file", nil
 	}
 }
+
+func (g *GitRepository) WriteTar(w io.Writer, prefix string) error {
+	tw := tar.NewWriter(w)
+	defer tw.Close()
+
+	tree, err := g.Tree("")
+	if err != nil {
+		return err
+	}
+
+	walker := object.NewTreeWalker(tree, true, nil)
+	defer walker.Close()
+
+	name, entry, err := walker.Next()
+	for ; err == nil; name, entry, err = walker.Next() {
+		info, err := newInfoWrapper(name, prefix, &entry, tree)
+		if err != nil {
+			return err
+		}
+
+		header, err := tar.FileInfoHeader(info, "")
+		if err != nil {
+			return err
+		}
+
+		err = tw.WriteHeader(header)
+		if err != nil {
+			return err
+		}
+
+		if !info.IsDir() {
+			c, err := g.FileContent(name)
+			if err != nil {
+				return err
+			}
+
+			_, err = tw.Write([]byte(c))
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+func newInfoWrapper(
+	filename string,
+	prefix string,
+	entry *object.TreeEntry,
+	tree *object.Tree,
+) (*infoWrapper, error) {
+	var (
+		size  int64
+		mode  fs.FileMode
+		isDir bool
+	)
+
+	if entry.Mode.IsFile() {
+		file, err := tree.TreeEntryFile(entry)
+		if err != nil {
+			return nil, err
+		}
+		mode = fs.FileMode(file.Mode)
+
+		size, err = tree.Size(filename)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		isDir = true
+		mode = fs.ModeDir | fs.ModePerm
+	}
+
+	fullname := path.Join(prefix, filename)
+	return &infoWrapper{
+		name:    fullname,
+		size:    size,
+		mode:    mode,
+		modTime: time.Unix(0, 0),
+		isDir:   isDir,
+	}, nil
+}
+
+func (i *infoWrapper) Name() string {
+	return i.name
+}
+
+func (i *infoWrapper) Size() int64 {
+	return i.size
+}
+
+func (i *infoWrapper) Mode() fs.FileMode {
+	return i.mode
+}
+
+func (i *infoWrapper) ModTime() time.Time {
+	return i.modTime
+}
+
+func (i *infoWrapper) IsDir() bool {
+	return i.isDir
+}
+
+func (i *infoWrapper) Sys() any {
+	return nil
+}
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
index 25505ba4c8ebfc520f69f9e21b87eef41752cd66..aed991747bb2e3d5054d2a0921321de6388f48d9 100644
--- a/pkg/handler/git/handler.go
+++ b/pkg/handler/git/handler.go
@@ -2,10 +2,13 @@ package git
 
 import (
 	"bytes"
+	"fmt"
 	"io"
+	"log/slog"
 	"net/http"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"git.gabrielgio.me/cerrado/pkg/ext"
 	"git.gabrielgio.me/cerrado/pkg/service"
@@ -36,6 +39,7 @@ 		GetFileContent(name, ref, path string) (string, error)
 		GetAbout(name string) (string, error)
 		ListTags(name string) ([]*plumbing.Reference, error)
 		ListBranches(name string) ([]*plumbing.Reference, error)
+		WriteTarGZip(w io.Writer, name, ref, filename string) error
 	}
 
 	configurationRepository interface {
@@ -81,6 +85,38 @@ 		Respositories: repos,
 		About:         bs,
 	}
 	templates.WritePageTemplate(w, gitList)
+	return nil
+}
+
+func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
+	ext.SetGZip(w)
+	name := r.PathValue("name")
+	refs := r.PathValue("refs")
+	ref := strings.TrimSuffix(refs, ".tar.gz")
+
+	// TODO: remove it once we can support more than gzip
+	if !strings.HasSuffix(refs, ".tar.gz") {
+		ext.NotFound(w)
+		return nil
+	}
+
+	filenameWithExt := fmt.Sprintf("%s-%s.tar.gz", name, ref)
+	ext.SetFileName(w, filenameWithExt)
+	filename := fmt.Sprintf("%s-%s", name, ref)
+
+	// writing to a buffer so we can run all the process before writing error
+	var buf bytes.Buffer
+	err := g.gitService.WriteTarGZip(&buf, name, ref, filename)
+	if err != nil {
+		return err
+	}
+
+	// since that has write to w it cannot return a error.
+	_, err = io.Copy(w, &buf)
+	if err != nil {
+		slog.Error("Error copying buffer", "error", err)
+	}
+
 	return nil
 }
 
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
index c8f89840effc9263911f7afc73b02722436b36f9..2293ab662f2e92a23bc3d3c953413ad00489cd58 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -41,6 +41,7 @@ 	mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
 	mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
 	mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
 	mux.HandleFunc("/{name}/log/{ref}/", gitHandler.Log)
+	mux.HandleFunc("/{name}/archive/{refs...}", gitHandler.Archive)
 	mux.HandleFunc("/config", configHandler)
 	mux.HandleFunc("/about", aboutHandler.About)
 	mux.HandleFunc("/", gitHandler.List)
diff --git a/pkg/service/git.go b/pkg/service/git.go
index 6bb6e9ebb7739ae025c124766ac402d19c429aad..cbee90a375721e07a0efea8b2653aa9a711d87ed 100644
--- a/pkg/service/git.go
+++ b/pkg/service/git.go
@@ -1,7 +1,9 @@
 package service
 
 import (
+	"compress/gzip"
 	"errors"
+	"io"
 	"log/slog"
 
 	"git.gabrielgio.me/cerrado/pkg/config"
@@ -90,6 +92,29 @@ 	if err != nil {
 		return nil, err
 	}
 	return repo.Commits(count)
+}
+
+func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, filename string) error {
+	r := g.configRepo.GetByName(name)
+	if r == nil {
+		return RepositoryNotFoundErr
+	}
+
+	repo, err := git.OpenRepository(r.Path)
+	if err != nil {
+		return err
+	}
+
+	err = repo.SetRef(ref)
+	if err != nil {
+		return err
+	}
+
+	gw := gzip.NewWriter(w)
+	defer gw.Close()
+
+	return repo.WriteTar(gw, filename)
+
 }
 
 func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
diff --git a/templates/gititemrefs.qtpl b/templates/gititemrefs.qtpl
index ff1561b7626970689ef318510c4610dbf20d5623..624408297c9680822ebf314fd7fb955e823ab606 100644
--- a/templates/gititemrefs.qtpl
+++ b/templates/gititemrefs.qtpl
@@ -21,6 +21,7 @@            {%s t.Name().Short() %}
           </div>
           <div class="col-8">
             <div class="float-end">
+              <a href="/{%s name %}/archive/{%s t.Name().Short() %}.tar.gz">tar.gz</a>
               <a href="/{%s name %}/tree/{%s t.Name().Short() %}/">tree</a>
               <a href="/{%s name %}/log/{%s t.Name().Short() %}/">log</a>
             </div>
@@ -41,6 +42,7 @@            {%s b.Name().Short() %}
           </div>
           <div class="col-8">
             <div class="float-end">
+              <a href="/{%s name %}/archive/{%s b.Name().Short() %}.tar.gz">tar.gz</a>
               <a href="/{%s name %}/tree/{%s b.Name().Short() %}/">tree</a>
               <a href="/{%s name %}/log/{%s b.Name().Short() %}/">log</a>
             </div>
diff --git a/templates/gititemrefs.qtpl.go b/templates/gititemrefs.qtpl.go
index b00736ecb57ca6d0fca34676cb9e455591c92d7a..da9bfe757f4d6bc91fb3d53c65dc2cd0faa36074 100644
--- a/templates/gititemrefs.qtpl.go
+++ b/templates/gititemrefs.qtpl.go
@@ -90,113 +90,131 @@               <a href="/`)
 //line gititemrefs.qtpl:24
 			qw422016.E().S(name)
 //line gititemrefs.qtpl:24
-			qw422016.N().S(`/tree/`)
+			qw422016.N().S(`/archive/`)
 //line gititemrefs.qtpl:24
 			qw422016.E().S(t.Name().Short())
 //line gititemrefs.qtpl:24
-			qw422016.N().S(`/">tree</a>
+			qw422016.N().S(`.tar.gz">tar.gz</a>
               <a href="/`)
 //line gititemrefs.qtpl:25
 			qw422016.E().S(name)
 //line gititemrefs.qtpl:25
-			qw422016.N().S(`/log/`)
+			qw422016.N().S(`/tree/`)
 //line gititemrefs.qtpl:25
 			qw422016.E().S(t.Name().Short())
 //line gititemrefs.qtpl:25
+			qw422016.N().S(`/">tree</a>
+              <a href="/`)
+//line gititemrefs.qtpl:26
+			qw422016.E().S(name)
+//line gititemrefs.qtpl:26
+			qw422016.N().S(`/log/`)
+//line gititemrefs.qtpl:26
+			qw422016.E().S(t.Name().Short())
+//line gititemrefs.qtpl:26
 			qw422016.N().S(`/">log</a>
             </div>
           </div>
       </div>
       `)
-//line gititemrefs.qtpl:29
+//line gititemrefs.qtpl:30
 		}
-//line gititemrefs.qtpl:29
+//line gititemrefs.qtpl:30
 		qw422016.N().S(`
     </div>
     `)
-//line gititemrefs.qtpl:31
+//line gititemrefs.qtpl:32
 	} else {
-//line gititemrefs.qtpl:31
+//line gititemrefs.qtpl:32
 		qw422016.N().S(`
         <p> No tags </p>
     `)
-//line gititemrefs.qtpl:33
+//line gititemrefs.qtpl:34
 	}
-//line gititemrefs.qtpl:33
+//line gititemrefs.qtpl:34
 	qw422016.N().S(`
   </div>
   <div class="col-md-4">
     <div class="event-list">
       `)
-//line gititemrefs.qtpl:37
+//line gititemrefs.qtpl:38
 	for _, b := range g.Branches {
-//line gititemrefs.qtpl:37
+//line gititemrefs.qtpl:38
 		qw422016.N().S(`
       <div class="row event">
           <div class="col-4">
            `)
-//line gititemrefs.qtpl:40
+//line gititemrefs.qtpl:41
 		qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:40
+//line gititemrefs.qtpl:41
 		qw422016.N().S(`
           </div>
           <div class="col-8">
             <div class="float-end">
               <a href="/`)
-//line gititemrefs.qtpl:44
+//line gititemrefs.qtpl:45
 		qw422016.E().S(name)
-//line gititemrefs.qtpl:44
+//line gititemrefs.qtpl:45
+		qw422016.N().S(`/archive/`)
+//line gititemrefs.qtpl:45
+		qw422016.E().S(b.Name().Short())
+//line gititemrefs.qtpl:45
+		qw422016.N().S(`.tar.gz">tar.gz</a>
+              <a href="/`)
+//line gititemrefs.qtpl:46
+		qw422016.E().S(name)
+//line gititemrefs.qtpl:46
 		qw422016.N().S(`/tree/`)
-//line gititemrefs.qtpl:44
+//line gititemrefs.qtpl:46
 		qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:44
+//line gititemrefs.qtpl:46
 		qw422016.N().S(`/">tree</a>
               <a href="/`)
-//line gititemrefs.qtpl:45
+//line gititemrefs.qtpl:47
 		qw422016.E().S(name)
-//line gititemrefs.qtpl:45
+//line gititemrefs.qtpl:47
 		qw422016.N().S(`/log/`)
-//line gititemrefs.qtpl:45
+//line gititemrefs.qtpl:47
 		qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:45
+//line gititemrefs.qtpl:47
 		qw422016.N().S(`/">log</a>
             </div>
           </div>
       </div>
       `)
-//line gititemrefs.qtpl:49
+//line gititemrefs.qtpl:51
 	}
-//line gititemrefs.qtpl:49
+//line gititemrefs.qtpl:51
 	qw422016.N().S(`
     </div>
   </div>
 </div>
 `)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 }
 
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 func (g *GitItemRefsPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	g.StreamGitContent(qw422016, name, ref)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	qt422016.ReleaseWriter(qw422016)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 }
 
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 func (g *GitItemRefsPage) GitContent(name, ref string) string {
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	qb422016 := qt422016.AcquireByteBuffer()
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	g.WriteGitContent(qb422016, name, ref)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	qs422016 := string(qb422016.B)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	qt422016.ReleaseByteBuffer(qb422016)
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 	return qs422016
-//line gititemrefs.qtpl:53
+//line gititemrefs.qtpl:55
 }
diff --git a/templates/gititemsummary.qtpl b/templates/gititemsummary.qtpl
index e3d3a0828874c51b78a70cc172d34a7fada73a1e..06a785ad74913ce89927a32daff49b18529e9159 100644
--- a/templates/gititemsummary.qtpl
+++ b/templates/gititemsummary.qtpl
@@ -23,6 +23,7 @@            {%s t.Name().Short() %}
           </div>
           <div class="col-8">
             <div class="float-end">
+              <a href="/{%s name %}/archive/{%s t.Name().Short() %}.tar.gz">tar.gz</a>
               <a href="/{%s name %}/tree/{%s t.Name().Short() %}/">tree</a>
               <a href="/{%s name %}/log/{%s t.Name().Short() %}/">log</a>
             </div>
diff --git a/templates/gititemsummary.qtpl.go b/templates/gititemsummary.qtpl.go
index ad025f7e8a8343850615d1c5e27c1f2cbf89d68c..4e48efd0da70a6301114cfd65ef9929f96804953 100644
--- a/templates/gititemsummary.qtpl.go
+++ b/templates/gititemsummary.qtpl.go
@@ -94,83 +94,92 @@               <a href="/`)
 //line gititemsummary.qtpl:26
 			qw422016.E().S(name)
 //line gititemsummary.qtpl:26
-			qw422016.N().S(`/tree/`)
+			qw422016.N().S(`/archive/`)
 //line gititemsummary.qtpl:26
 			qw422016.E().S(t.Name().Short())
 //line gititemsummary.qtpl:26
-			qw422016.N().S(`/">tree</a>
+			qw422016.N().S(`.tar.gz">tar.gz</a>
               <a href="/`)
 //line gititemsummary.qtpl:27
 			qw422016.E().S(name)
 //line gititemsummary.qtpl:27
-			qw422016.N().S(`/log/`)
+			qw422016.N().S(`/tree/`)
 //line gititemsummary.qtpl:27
 			qw422016.E().S(t.Name().Short())
 //line gititemsummary.qtpl:27
+			qw422016.N().S(`/">tree</a>
+              <a href="/`)
+//line gititemsummary.qtpl:28
+			qw422016.E().S(name)
+//line gititemsummary.qtpl:28
+			qw422016.N().S(`/log/`)
+//line gititemsummary.qtpl:28
+			qw422016.E().S(t.Name().Short())
+//line gititemsummary.qtpl:28
 			qw422016.N().S(`/">log</a>
             </div>
           </div>
       </div>
       `)
-//line gititemsummary.qtpl:31
+//line gititemsummary.qtpl:32
 		}
-//line gititemsummary.qtpl:31
+//line gititemsummary.qtpl:32
 		qw422016.N().S(`
     </div>
     `)
-//line gititemsummary.qtpl:33
+//line gititemsummary.qtpl:34
 	} else {
-//line gititemsummary.qtpl:33
+//line gititemsummary.qtpl:34
 		qw422016.N().S(`
         <p> No tags </p>
     `)
-//line gititemsummary.qtpl:35
+//line gititemsummary.qtpl:36
 	}
-//line gititemsummary.qtpl:35
+//line gititemsummary.qtpl:36
 	qw422016.N().S(`
   </div>
   <div class="col-md-4">
     <div class="event-list">
       `)
-//line gititemsummary.qtpl:39
+//line gititemsummary.qtpl:40
 	for _, b := range g.Branches {
-//line gititemsummary.qtpl:39
+//line gititemsummary.qtpl:40
 		qw422016.N().S(`
       <div class="row event">
           <div class="col-4">
            `)
-//line gititemsummary.qtpl:42
+//line gititemsummary.qtpl:43
 		qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:42
+//line gititemsummary.qtpl:43
 		qw422016.N().S(`
           </div>
           <div class="col-8">
             <div class="float-end">
               <a href="/`)
-//line gititemsummary.qtpl:46
+//line gititemsummary.qtpl:47
 		qw422016.E().S(name)
-//line gititemsummary.qtpl:46
+//line gititemsummary.qtpl:47
 		qw422016.N().S(`/tree/`)
-//line gititemsummary.qtpl:46
+//line gititemsummary.qtpl:47
 		qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:46
+//line gititemsummary.qtpl:47
 		qw422016.N().S(`/">tree</a>
               <a href="/`)
-//line gititemsummary.qtpl:47
+//line gititemsummary.qtpl:48
 		qw422016.E().S(name)
-//line gititemsummary.qtpl:47
+//line gititemsummary.qtpl:48
 		qw422016.N().S(`/log/`)
-//line gititemsummary.qtpl:47
+//line gititemsummary.qtpl:48
 		qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:47
+//line gititemsummary.qtpl:48
 		qw422016.N().S(`/">log</a>
             </div>
           </div>
       </div>
       `)
-//line gititemsummary.qtpl:51
+//line gititemsummary.qtpl:52
 	}
-//line gititemsummary.qtpl:51
+//line gititemsummary.qtpl:52
 	qw422016.N().S(`
     </div>
   </div>
@@ -178,70 +187,70 @@ </div>
 <div class="row">
   <div class="event-list">
     `)
-//line gititemsummary.qtpl:57
+//line gititemsummary.qtpl:58
 	for _, c := range g.Commits {
-//line gititemsummary.qtpl:57
+//line gititemsummary.qtpl:58
 		qw422016.N().S(`
     <div class="row event">
         <div class="col-xxl-2">
          `)
-//line gititemsummary.qtpl:60
+//line gititemsummary.qtpl:61
 		qw422016.E().S(TimeFormat(c.Committer.When))
-//line gititemsummary.qtpl:60
+//line gititemsummary.qtpl:61
 		qw422016.N().S(`
         </div>
         <div class="col-xxl-7 code-view">
          <pre>`)
-//line gititemsummary.qtpl:63
+//line gititemsummary.qtpl:64
 		qw422016.E().S(c.Message)
-//line gititemsummary.qtpl:63
+//line gititemsummary.qtpl:64
 		qw422016.N().S(`</pre>
         </div>
         <div class="col-xxl-3">
          <small>`)
-//line gititemsummary.qtpl:66
+//line gititemsummary.qtpl:67
 		qw422016.E().S(c.Committer.Name)
-//line gititemsummary.qtpl:66
+//line gititemsummary.qtpl:67
 		qw422016.N().S(` &lt;`)
-//line gititemsummary.qtpl:66
+//line gititemsummary.qtpl:67
 		qw422016.E().S(c.Committer.Email)
-//line gititemsummary.qtpl:66
+//line gititemsummary.qtpl:67
 		qw422016.N().S(`&gt;</small>
         </div>
     </div>
     `)
-//line gititemsummary.qtpl:69
+//line gititemsummary.qtpl:70
 	}
-//line gititemsummary.qtpl:69
+//line gititemsummary.qtpl:70
 	qw422016.N().S(`
   </div>
 </div>
 `)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 }
 
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 func (g *GitItemSummaryPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	g.StreamGitContent(qw422016, name, ref)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	qt422016.ReleaseWriter(qw422016)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 }
 
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 func (g *GitItemSummaryPage) GitContent(name, ref string) string {
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	qb422016 := qt422016.AcquireByteBuffer()
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	g.WriteGitContent(qb422016, name, ref)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	qs422016 := string(qb422016.B)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	qt422016.ReleaseByteBuffer(qb422016)
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 	return qs422016
-//line gititemsummary.qtpl:72
+//line gititemsummary.qtpl:73
 }