cerrado @ e3705f35c642e578625ce4574d189fa0b0869403

feat: Add ref support

Now log and tree can be loaded using a given reference.
   1diff --git a/pkg/git/git.go b/pkg/git/git.go
   2index 7ef23f74b726b769ed7f197bd3ec25b30c2363a7..ce72465a84f2b8f0c65411b176b7a075ca031609 100644
   3--- a/pkg/git/git.go
   4+++ b/pkg/git/git.go
   5@@ -13,19 +13,50 @@
   6 var ()
   7 
   8 var (
   9-	MissingHeadErr = errors.New("Head not found")
  10+	MissingRefErr = errors.New("Reference not found")
  11 )
  12 
  13 type (
  14 	GitRepository struct {
  15-		path string
  16+		path       string
  17+		repository *git.Repository
  18+
  19+		ref plumbing.Hash
  20+		// this is setRef when ref is setRef
  21+		setRef bool
  22 	}
  23 )
  24 
  25-func NewGitRepository(dir string) *GitRepository {
  26-	return &GitRepository{
  27+func OpenRepository(dir string) (*GitRepository, error) {
  28+	g := &GitRepository{
  29 		path: dir,
  30 	}
  31+
  32+	repo, err := git.PlainOpen(dir)
  33+	if err != nil {
  34+		return nil, err
  35+	}
  36+	g.repository = repo
  37+
  38+	return g, nil
  39+}
  40+
  41+func (g *GitRepository) SetRef(ref string) error {
  42+	if ref == "" {
  43+		head, err := g.repository.Head()
  44+		if err != nil {
  45+			return errors.Join(MissingRefErr, err)
  46+		}
  47+		g.ref = head.Hash()
  48+	} else {
  49+		hash, err := g.repository.ResolveRevision(plumbing.Revision(ref))
  50+		if err != nil {
  51+			return errors.Join(MissingRefErr, err)
  52+		}
  53+		g.ref = *hash
  54+	}
  55+	g.setRef = true
  56+	return nil
  57 }
  58 
  59 func (g *GitRepository) Path() string {
  60@@ -33,17 +64,12 @@ 	return g.path
  61 }
  62 
  63 func (g *GitRepository) LastCommit() (*object.Commit, error) {
  64-	repo, err := git.PlainOpen(g.path)
  65+	err := g.validateRef()
  66 	if err != nil {
  67 		return nil, err
  68 	}
  69 
  70-	ref, err := repo.Head()
  71-	if err != nil {
  72-		return nil, errors.Join(MissingHeadErr, err)
  73-	}
  74-
  75-	c, err := repo.CommitObject(ref.Hash())
  76+	c, err := g.repository.CommitObject(g.ref)
  77 	if err != nil {
  78 		return nil, err
  79 	}
  80@@ -51,17 +77,12 @@ 	return c, nil
  81 }
  82 
  83 func (g *GitRepository) Commits() ([]*object.Commit, error) {
  84-	repo, err := git.PlainOpen(g.path)
  85+	err := g.validateRef()
  86 	if err != nil {
  87 		return nil, err
  88 	}
  89 
  90-	ref, err := repo.Head()
  91-	if err != nil {
  92-		return nil, errors.Join(MissingHeadErr, err)
  93-	}
  94-
  95-	ci, err := repo.Log(&git.LogOptions{From: ref.Hash()})
  96+	ci, err := g.repository.Log(&git.LogOptions{From: g.ref})
  97 	if err != nil {
  98 		return nil, fmt.Errorf("commits from ref: %w", err)
  99 	}
 100@@ -84,13 +105,12 @@
 101 	return commits, nil
 102 }
 103 
 104+func (g *GitRepository) Head() (*plumbing.Reference, error) {
 105+	return g.repository.Head()
 106+}
 107+
 108 func (g *GitRepository) Tags() ([]*object.Tag, error) {
 109-	repo, err := git.PlainOpen(g.path)
 110-	if err != nil {
 111-		return nil, err
 112-	}
 113-
 114-	ti, err := repo.TagObjects()
 115+	ti, err := g.repository.TagObjects()
 116 	if err != nil {
 117 		return nil, err
 118 	}
 119@@ -108,12 +128,7 @@ 	return tags, nil
 120 }
 121 
 122 func (g *GitRepository) Branches() ([]*plumbing.Reference, error) {
 123-	repo, err := git.PlainOpen(g.path)
 124-	if err != nil {
 125-		return nil, err
 126-	}
 127-
 128-	bs, err := repo.Branches()
 129+	bs, err := g.repository.Branches()
 130 	if err != nil {
 131 		return nil, err
 132 	}
 133@@ -129,3 +144,10 @@ 	}
 134 
 135 	return branches, nil
 136 }
 137+
 138+func (g *GitRepository) validateRef() error {
 139+	if !g.setRef {
 140+		return g.SetRef("")
 141+	}
 142+	return nil
 143+}
 144diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
 145index d090f2269b5c0057caf828048fe161028afcfacc..b77bcfc0e35d58f47b6fd5a08e74a23fa4d3735f 100644
 146--- a/pkg/handler/git/handler.go
 147+++ b/pkg/handler/git/handler.go
 148@@ -18,9 +18,10 @@ 	}
 149 
 150 	gitService interface {
 151 		ListRepositories() ([]*service.Repository, error)
 152-		ListCommits(string) ([]*object.Commit, error)
 153-		ListTags(string) ([]*object.Tag, error)
 154-		ListBranches(string) ([]*plumbing.Reference, error)
 155+		ListCommits(name string, ref string) ([]*object.Commit, error)
 156+		GetHead(name string) (*plumbing.Reference, error)
 157+		ListTags(name string) ([]*object.Tag, error)
 158+		ListBranches(name string) ([]*plumbing.Reference, error)
 159 	}
 160 )
 161 
 162@@ -43,8 +44,15 @@ }
 163 
 164 func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) {
 165 	name := mux.Vars(r)["name"]
 166+	ref, err := g.gitService.GetHead(name)
 167+	if err != nil {
 168+		slog.Error("Error loading head", "error", err)
 169+		return
 170+	}
 171+
 172 	gitList := &templates.GitItemPage{
 173 		Name:        name,
 174+		Ref:         ref.Name().Short(),
 175 		GitItemBase: &templates.GitItemSummaryPage{},
 176 	}
 177 	templates.WritePageTemplate(w, gitList)
 178@@ -52,8 +60,14 @@ }
 179 
 180 func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) {
 181 	name := mux.Vars(r)["name"]
 182+	ref, err := g.gitService.GetHead(name)
 183+	if err != nil {
 184+		slog.Error("Error loading head", "error", err)
 185+		return
 186+	}
 187 	gitList := &templates.GitItemPage{
 188 		Name:        name,
 189+		Ref:         ref.Name().Short(),
 190 		GitItemBase: &templates.GitItemAboutPage{},
 191 	}
 192 	templates.WritePageTemplate(w, gitList)
 193@@ -74,8 +88,15 @@ 		slog.Error("Error loading branches", "error", err)
 194 		return
 195 	}
 196 
 197+	ref, err := g.gitService.GetHead(name)
 198+	if err != nil {
 199+		slog.Error("Error loading head", "error", err)
 200+		return
 201+	}
 202+
 203 	gitList := &templates.GitItemPage{
 204 		Name: name,
 205+		Ref:  ref.Name().Short(),
 206 		GitItemBase: &templates.GitItemRefsPage{
 207 			Tags:     tags,
 208 			Branches: branches,
 209@@ -86,8 +107,10 @@ }
 210 
 211 func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
 212 	name := mux.Vars(r)["name"]
 213+	ref := mux.Vars(r)["ref"]
 214 	gitList := &templates.GitItemPage{
 215 		Name:        name,
 216+		Ref:         ref,
 217 		GitItemBase: &templates.GitItemTreePage{},
 218 	}
 219 	templates.WritePageTemplate(w, gitList)
 220@@ -95,8 +118,9 @@ }
 221 
 222 func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) {
 223 	name := mux.Vars(r)["name"]
 224+	ref := mux.Vars(r)["ref"]
 225 
 226-	commits, err := g.gitService.ListCommits(name)
 227+	commits, err := g.gitService.ListCommits(name, ref)
 228 	if err != nil {
 229 		slog.Error("Error loading commits", "error", err)
 230 		return
 231@@ -104,6 +128,7 @@ 	}
 232 
 233 	gitList := &templates.GitItemPage{
 234 		Name: name,
 235+		Ref:  ref,
 236 		GitItemBase: &templates.GitItemLogPage{
 237 			Commits: commits,
 238 		},
 239diff --git a/pkg/handler/router.go b/pkg/handler/router.go
 240index f73e9fba6d0e2ce0127d6798fc26ebf017969c0d..79f70f11e263dbac66bf9660a97a4514b0dfd5fb 100644
 241--- a/pkg/handler/router.go
 242+++ b/pkg/handler/router.go
 243@@ -34,10 +34,10 @@ 	mux := mux.NewRouter()
 244 
 245 	mux.PathPrefix("/static").Handler(staticHandler)
 246 	mux.HandleFunc("/{name}/about", gitHandler.About)
 247-	mux.HandleFunc("/{name}/summary", gitHandler.Summary)
 248+	mux.HandleFunc("/{name}", gitHandler.Summary)
 249 	mux.HandleFunc("/{name}/refs", gitHandler.Refs)
 250-	mux.HandleFunc("/{name}/tree", gitHandler.Tree)
 251-	mux.HandleFunc("/{name}/log", gitHandler.Log)
 252+	mux.HandleFunc("/{name}/tree/{ref}", gitHandler.Tree)
 253+	mux.HandleFunc("/{name}/log/{ref}", gitHandler.Log)
 254 	mux.HandleFunc("/config", configHander)
 255 	mux.HandleFunc("/about", aboutHandler.About)
 256 	mux.HandleFunc("/", gitHandler.List)
 257diff --git a/pkg/service/git.go b/pkg/service/git.go
 258index 57b9b6e7327aa0901955e95bc0c2958d9185d408..9bf11f4e79cb77ae692820236f59db9bc9ea0453 100644
 259--- a/pkg/service/git.go
 260+++ b/pkg/service/git.go
 261@@ -15,6 +15,7 @@ 		Name              string
 262 		Title             string
 263 		LastCommitMessage string
 264 		LastCommitDate    string
 265+		Ref               string
 266 	}
 267 
 268 	GitService struct {
 269@@ -41,29 +42,50 @@ 	rs := g.configRepo.List()
 270 
 271 	repos := make([]*Repository, len(rs))
 272 	for i, r := range rs {
 273-		repo := git.NewGitRepository(r.Path)
 274+		repo, err := git.OpenRepository(r.Path)
 275+		if err != nil {
 276+			return nil, err
 277+		}
 278+		if err != nil {
 279+			return nil, err
 280+		}
 281+
 282 		obj, err := repo.LastCommit()
 283 		if err != nil {
 284 			return nil, err
 285 		}
 286 
 287+		head, err := repo.Head()
 288+		if err != nil {
 289+			return nil, err
 290+		}
 291+
 292 		baseName := path.Base(r.Path)
 293 		repos[i] = &Repository{
 294 			Name:              baseName,
 295 			Title:             baseName,
 296 			LastCommitMessage: obj.Message,
 297 			LastCommitDate:    obj.Author.When.Format(timeFormat),
 298+			Ref:               head.Name().Short(),
 299 		}
 300 	}
 301 
 302 	return repos, nil
 303 }
 304 
 305-func (g *GitService) ListCommits(name string) ([]*object.Commit, error) {
 306+func (g *GitService) ListCommits(name, ref string) ([]*object.Commit, error) {
 307 	// TODO: handle nil
 308 	r := g.configRepo.GetByName(name)
 309 
 310-	repo := git.NewGitRepository(r.Path)
 311+	repo, err := git.OpenRepository(r.Path)
 312+	if err != nil {
 313+		return nil, err
 314+	}
 315+
 316+	err = repo.SetRef(ref)
 317+	if err != nil {
 318+		return nil, err
 319+	}
 320 	return repo.Commits()
 321 }
 322 
 323@@ -71,7 +93,10 @@ func (g *GitService) ListTags(name string) ([]*object.Tag, error) {
 324 	// TODO: handle nil
 325 	r := g.configRepo.GetByName(name)
 326 
 327-	repo := git.NewGitRepository(r.Path)
 328+	repo, err := git.OpenRepository(r.Path)
 329+	if err != nil {
 330+		return nil, err
 331+	}
 332 	return repo.Tags()
 333 }
 334 
 335@@ -79,6 +104,21 @@ func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
 336 	// TODO: handle nil
 337 	r := g.configRepo.GetByName(name)
 338 
 339-	repo := git.NewGitRepository(r.Path)
 340+	repo, err := git.OpenRepository(r.Path)
 341+	if err != nil {
 342+		return nil, err
 343+	}
 344 	return repo.Branches()
 345 }
 346+
 347+func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
 348+	// TODO: handle nil
 349+	r := g.configRepo.GetByName(name)
 350+
 351+	repo, err := git.OpenRepository(r.Path)
 352+	if err != nil {
 353+		return nil, err
 354+	}
 355+
 356+	return repo.Head()
 357+}
 358diff --git a/templates/gititem.qtpl b/templates/gititem.qtpl
 359index d2fcea7fcbac20ca753c668f71b7937a7c61e7c5..3e2dd4e543265ca86fbe8832a7001b392edb0b7b 100644
 360--- a/templates/gititem.qtpl
 361+++ b/templates/gititem.qtpl
 362@@ -1,6 +1,6 @@
 363 {% interface 
 364 GitItemBase {
 365-   Nav(name string)
 366+   Nav(name, ref string)
 367    GitContent()
 368 }
 369 %}
 370@@ -8,6 +8,7 @@
 371 {% code
 372 type GitItemPage struct {
 373     Name string
 374+    Ref string
 375     GitItemBase
 376 }
 377 %}
 378@@ -17,12 +18,7 @@
 379 {% func (p *GitItemPage) Navbar() %}{%= Navbar(Git) %}{% endfunc %}
 380 
 381 {% func (p *GitItemPage) Content() %}
 382-<div class="row">
 383-    <h3>{%s p.Name %}</h3>
 384-</div>
 385-<div class="row">
 386-{%= p.Nav(p.Name) %}
 387-</div>
 388+{%= p.Nav(p.Name, p.Ref) %}
 389 <div class="container">
 390 {%= p.GitContent() %}
 391 </div>
 392diff --git a/templates/gititem.qtpl.go b/templates/gititem.qtpl.go
 393index 9709a43ec697fd27687af9e2ac9b424ff8e981a1..2c4610465d702fd2ceab108977a1dff00576ab68 100644
 394--- a/templates/gititem.qtpl.go
 395+++ b/templates/gititem.qtpl.go
 396@@ -20,11 +20,11 @@
 397 //line gititem.qtpl:2
 398 type GitItemBase interface {
 399 //line gititem.qtpl:2
 400-	Nav(name string) string
 401+	Nav(name, ref string) string
 402 //line gititem.qtpl:2
 403-	StreamNav(qw422016 *qt422016.Writer, name string)
 404+	StreamNav(qw422016 *qt422016.Writer, name, ref string)
 405 //line gititem.qtpl:2
 406-	WriteNav(qq422016 qtio422016.Writer, name string)
 407+	WriteNav(qq422016 qtio422016.Writer, name, ref string)
 408 //line gititem.qtpl:2
 409 	GitContent() string
 410 //line gititem.qtpl:2
 411@@ -37,160 +37,152 @@
 412 //line gititem.qtpl:9
 413 type GitItemPage struct {
 414 	Name string
 415+	Ref  string
 416 	GitItemBase
 417 }
 418 
 419-//line gititem.qtpl:15
 420+//line gititem.qtpl:16
 421 func (p *GitItemPage) StreamTitle(qw422016 *qt422016.Writer) {
 422-//line gititem.qtpl:15
 423+//line gititem.qtpl:16
 424 	qw422016.N().S(`Git | List`)
 425-//line gititem.qtpl:15
 426+//line gititem.qtpl:16
 427 }
 428 
 429-//line gititem.qtpl:15
 430+//line gititem.qtpl:16
 431 func (p *GitItemPage) WriteTitle(qq422016 qtio422016.Writer) {
 432-//line gititem.qtpl:15
 433+//line gititem.qtpl:16
 434 	qw422016 := qt422016.AcquireWriter(qq422016)
 435-//line gititem.qtpl:15
 436+//line gititem.qtpl:16
 437 	p.StreamTitle(qw422016)
 438-//line gititem.qtpl:15
 439+//line gititem.qtpl:16
 440 	qt422016.ReleaseWriter(qw422016)
 441-//line gititem.qtpl:15
 442+//line gititem.qtpl:16
 443 }
 444 
 445-//line gititem.qtpl:15
 446+//line gititem.qtpl:16
 447 func (p *GitItemPage) Title() string {
 448-//line gititem.qtpl:15
 449+//line gititem.qtpl:16
 450 	qb422016 := qt422016.AcquireByteBuffer()
 451-//line gititem.qtpl:15
 452+//line gititem.qtpl:16
 453 	p.WriteTitle(qb422016)
 454-//line gititem.qtpl:15
 455+//line gititem.qtpl:16
 456 	qs422016 := string(qb422016.B)
 457-//line gititem.qtpl:15
 458+//line gititem.qtpl:16
 459 	qt422016.ReleaseByteBuffer(qb422016)
 460-//line gititem.qtpl:15
 461+//line gititem.qtpl:16
 462 	return qs422016
 463-//line gititem.qtpl:15
 464+//line gititem.qtpl:16
 465 }
 466 
 467-//line gititem.qtpl:17
 468+//line gititem.qtpl:18
 469 func (p *GitItemPage) StreamNavbar(qw422016 *qt422016.Writer) {
 470-//line gititem.qtpl:17
 471+//line gititem.qtpl:18
 472 	StreamNavbar(qw422016, Git)
 473-//line gititem.qtpl:17
 474+//line gititem.qtpl:18
 475 }
 476 
 477-//line gititem.qtpl:17
 478+//line gititem.qtpl:18
 479 func (p *GitItemPage) WriteNavbar(qq422016 qtio422016.Writer) {
 480-//line gititem.qtpl:17
 481+//line gititem.qtpl:18
 482 	qw422016 := qt422016.AcquireWriter(qq422016)
 483-//line gititem.qtpl:17
 484+//line gititem.qtpl:18
 485 	p.StreamNavbar(qw422016)
 486-//line gititem.qtpl:17
 487+//line gititem.qtpl:18
 488 	qt422016.ReleaseWriter(qw422016)
 489-//line gititem.qtpl:17
 490+//line gititem.qtpl:18
 491 }
 492 
 493-//line gititem.qtpl:17
 494+//line gititem.qtpl:18
 495 func (p *GitItemPage) Navbar() string {
 496-//line gititem.qtpl:17
 497+//line gititem.qtpl:18
 498 	qb422016 := qt422016.AcquireByteBuffer()
 499-//line gititem.qtpl:17
 500+//line gititem.qtpl:18
 501 	p.WriteNavbar(qb422016)
 502-//line gititem.qtpl:17
 503+//line gititem.qtpl:18
 504 	qs422016 := string(qb422016.B)
 505-//line gititem.qtpl:17
 506+//line gititem.qtpl:18
 507 	qt422016.ReleaseByteBuffer(qb422016)
 508-//line gititem.qtpl:17
 509+//line gititem.qtpl:18
 510 	return qs422016
 511-//line gititem.qtpl:17
 512+//line gititem.qtpl:18
 513 }
 514 
 515-//line gititem.qtpl:19
 516+//line gititem.qtpl:20
 517 func (p *GitItemPage) StreamContent(qw422016 *qt422016.Writer) {
 518-//line gititem.qtpl:19
 519+//line gititem.qtpl:20
 520 	qw422016.N().S(`
 521-<div class="row">
 522-    <h3>`)
 523+`)
 524 //line gititem.qtpl:21
 525-	qw422016.E().S(p.Name)
 526+	p.StreamNav(qw422016, p.Name, p.Ref)
 527 //line gititem.qtpl:21
 528-	qw422016.N().S(`</h3>
 529-</div>
 530-<div class="row">
 531-`)
 532-//line gititem.qtpl:24
 533-	p.StreamNav(qw422016, p.Name)
 534-//line gititem.qtpl:24
 535 	qw422016.N().S(`
 536-</div>
 537 <div class="container">
 538 `)
 539-//line gititem.qtpl:27
 540+//line gititem.qtpl:23
 541 	p.StreamGitContent(qw422016)
 542-//line gititem.qtpl:27
 543+//line gititem.qtpl:23
 544 	qw422016.N().S(`
 545 </div>
 546 `)
 547-//line gititem.qtpl:29
 548+//line gititem.qtpl:25
 549 }
 550 
 551-//line gititem.qtpl:29
 552+//line gititem.qtpl:25
 553 func (p *GitItemPage) WriteContent(qq422016 qtio422016.Writer) {
 554-//line gititem.qtpl:29
 555+//line gititem.qtpl:25
 556 	qw422016 := qt422016.AcquireWriter(qq422016)
 557-//line gititem.qtpl:29
 558+//line gititem.qtpl:25
 559 	p.StreamContent(qw422016)
 560-//line gititem.qtpl:29
 561+//line gititem.qtpl:25
 562 	qt422016.ReleaseWriter(qw422016)
 563-//line gititem.qtpl:29
 564+//line gititem.qtpl:25
 565 }
 566 
 567-//line gititem.qtpl:29
 568+//line gititem.qtpl:25
 569 func (p *GitItemPage) Content() string {
 570-//line gititem.qtpl:29
 571+//line gititem.qtpl:25
 572 	qb422016 := qt422016.AcquireByteBuffer()
 573-//line gititem.qtpl:29
 574+//line gititem.qtpl:25
 575 	p.WriteContent(qb422016)
 576-//line gititem.qtpl:29
 577+//line gititem.qtpl:25
 578 	qs422016 := string(qb422016.B)
 579-//line gititem.qtpl:29
 580+//line gititem.qtpl:25
 581 	qt422016.ReleaseByteBuffer(qb422016)
 582-//line gititem.qtpl:29
 583+//line gititem.qtpl:25
 584 	return qs422016
 585-//line gititem.qtpl:29
 586+//line gititem.qtpl:25
 587 }
 588 
 589-//line gititem.qtpl:31
 590+//line gititem.qtpl:27
 591 func (p *GitItemPage) StreamScript(qw422016 *qt422016.Writer) {
 592-//line gititem.qtpl:31
 593+//line gititem.qtpl:27
 594 	qw422016.N().S(`
 595 `)
 596-//line gititem.qtpl:32
 597+//line gititem.qtpl:28
 598 }
 599 
 600-//line gititem.qtpl:32
 601+//line gititem.qtpl:28
 602 func (p *GitItemPage) WriteScript(qq422016 qtio422016.Writer) {
 603-//line gititem.qtpl:32
 604+//line gititem.qtpl:28
 605 	qw422016 := qt422016.AcquireWriter(qq422016)
 606-//line gititem.qtpl:32
 607+//line gititem.qtpl:28
 608 	p.StreamScript(qw422016)
 609-//line gititem.qtpl:32
 610+//line gititem.qtpl:28
 611 	qt422016.ReleaseWriter(qw422016)
 612-//line gititem.qtpl:32
 613+//line gititem.qtpl:28
 614 }
 615 
 616-//line gititem.qtpl:32
 617+//line gititem.qtpl:28
 618 func (p *GitItemPage) Script() string {
 619-//line gititem.qtpl:32
 620+//line gititem.qtpl:28
 621 	qb422016 := qt422016.AcquireByteBuffer()
 622-//line gititem.qtpl:32
 623+//line gititem.qtpl:28
 624 	p.WriteScript(qb422016)
 625-//line gititem.qtpl:32
 626+//line gititem.qtpl:28
 627 	qs422016 := string(qb422016.B)
 628-//line gititem.qtpl:32
 629+//line gititem.qtpl:28
 630 	qt422016.ReleaseByteBuffer(qb422016)
 631-//line gititem.qtpl:32
 632+//line gititem.qtpl:28
 633 	return qs422016
 634-//line gititem.qtpl:32
 635+//line gititem.qtpl:28
 636 }
 637diff --git a/templates/gititemabout.qtpl b/templates/gititemabout.qtpl
 638index 67d43f1249399e49aa1a240812427a3f72e8077c..e0fa9c3f184837a96d3194d5baacdcdfd866a56b 100644
 639--- a/templates/gititemabout.qtpl
 640+++ b/templates/gititemabout.qtpl
 641@@ -3,7 +3,7 @@ type GitItemAboutPage struct {
 642 }
 643 %}
 644 
 645-{% func (g *GitItemAboutPage) Nav(name string) %}{%= GitItemNav(name, Readme) %}{% endfunc %}
 646+{% func (g *GitItemAboutPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Readme) %}{% endfunc %}
 647 
 648 {% func (g *GitItemAboutPage) GitContent() %}
 649 <h4>About</h4>
 650diff --git a/templates/gititemabout.qtpl.go b/templates/gititemabout.qtpl.go
 651index 7b772e5bf41536602a120b48ed78b20de81e56d2..0827fbe114bd75cf7b2b8d8c7b67a29c5194ffb0 100644
 652--- a/templates/gititemabout.qtpl.go
 653+++ b/templates/gititemabout.qtpl.go
 654@@ -22,29 +22,29 @@ type GitItemAboutPage struct {
 655 }
 656 
 657 //line gititemabout.qtpl:6
 658-func (g *GitItemAboutPage) StreamNav(qw422016 *qt422016.Writer, name string) {
 659+func (g *GitItemAboutPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
 660 //line gititemabout.qtpl:6
 661-	StreamGitItemNav(qw422016, name, Readme)
 662+	StreamGitItemNav(qw422016, name, ref, Readme)
 663 //line gititemabout.qtpl:6
 664 }
 665 
 666 //line gititemabout.qtpl:6
 667-func (g *GitItemAboutPage) WriteNav(qq422016 qtio422016.Writer, name string) {
 668+func (g *GitItemAboutPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
 669 //line gititemabout.qtpl:6
 670 	qw422016 := qt422016.AcquireWriter(qq422016)
 671 //line gititemabout.qtpl:6
 672-	g.StreamNav(qw422016, name)
 673+	g.StreamNav(qw422016, name, ref)
 674 //line gititemabout.qtpl:6
 675 	qt422016.ReleaseWriter(qw422016)
 676 //line gititemabout.qtpl:6
 677 }
 678 
 679 //line gititemabout.qtpl:6
 680-func (g *GitItemAboutPage) Nav(name string) string {
 681+func (g *GitItemAboutPage) Nav(name, ref string) string {
 682 //line gititemabout.qtpl:6
 683 	qb422016 := qt422016.AcquireByteBuffer()
 684 //line gititemabout.qtpl:6
 685-	g.WriteNav(qb422016, name)
 686+	g.WriteNav(qb422016, name, ref)
 687 //line gititemabout.qtpl:6
 688 	qs422016 := string(qb422016.B)
 689 //line gititemabout.qtpl:6
 690diff --git a/templates/gititemlog.qtpl b/templates/gititemlog.qtpl
 691index 436c1d274193ee35357d087d94ce89d99ff30d7a..e037c52718fa440432f3e361b61625729fed8edb 100644
 692--- a/templates/gititemlog.qtpl
 693+++ b/templates/gititemlog.qtpl
 694@@ -6,7 +6,7 @@     Commits []*object.Commit
 695 }
 696 %}
 697 
 698-{% func (g *GitItemLogPage) Nav(name string) %}{%= GitItemNav(name, Log) %}{% endfunc %}
 699+{% func (g *GitItemLogPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Log) %}{% endfunc %}
 700 
 701 {% func (g *GitItemLogPage) GitContent() %}
 702 <div class="logs">
 703diff --git a/templates/gititemlog.qtpl.go b/templates/gititemlog.qtpl.go
 704index e63c8712559c77e4efff48789b7ab17c4bd4ce41..47e700d343dbf7be77ef68410f4d907ba0bd29fc 100644
 705--- a/templates/gititemlog.qtpl.go
 706+++ b/templates/gititemlog.qtpl.go
 707@@ -26,29 +26,29 @@ 	Commits []*object.Commit
 708 }
 709 
 710 //line gititemlog.qtpl:9
 711-func (g *GitItemLogPage) StreamNav(qw422016 *qt422016.Writer, name string) {
 712+func (g *GitItemLogPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
 713 //line gititemlog.qtpl:9
 714-	StreamGitItemNav(qw422016, name, Log)
 715+	StreamGitItemNav(qw422016, name, ref, Log)
 716 //line gititemlog.qtpl:9
 717 }
 718 
 719 //line gititemlog.qtpl:9
 720-func (g *GitItemLogPage) WriteNav(qq422016 qtio422016.Writer, name string) {
 721+func (g *GitItemLogPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
 722 //line gititemlog.qtpl:9
 723 	qw422016 := qt422016.AcquireWriter(qq422016)
 724 //line gititemlog.qtpl:9
 725-	g.StreamNav(qw422016, name)
 726+	g.StreamNav(qw422016, name, ref)
 727 //line gititemlog.qtpl:9
 728 	qt422016.ReleaseWriter(qw422016)
 729 //line gititemlog.qtpl:9
 730 }
 731 
 732 //line gititemlog.qtpl:9
 733-func (g *GitItemLogPage) Nav(name string) string {
 734+func (g *GitItemLogPage) Nav(name, ref string) string {
 735 //line gititemlog.qtpl:9
 736 	qb422016 := qt422016.AcquireByteBuffer()
 737 //line gititemlog.qtpl:9
 738-	g.WriteNav(qb422016, name)
 739+	g.WriteNav(qb422016, name, ref)
 740 //line gititemlog.qtpl:9
 741 	qs422016 := string(qb422016.B)
 742 //line gititemlog.qtpl:9
 743diff --git a/templates/gititemrefs.qtpl b/templates/gititemrefs.qtpl
 744index 9c588630a087401485881be712c413e026664f07..56f6c2bf557e1afc0a2dc12a5f918f6f347353d2 100644
 745--- a/templates/gititemrefs.qtpl
 746+++ b/templates/gititemrefs.qtpl
 747@@ -8,7 +8,7 @@     Branches []*plumbing.Reference
 748 }
 749 %}
 750 
 751-{% func (g *GitItemRefsPage) Nav(name string) %}{%= GitItemNav(name ,Refs) %}{% endfunc %}
 752+{% func (g *GitItemRefsPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Refs) %}{% endfunc %}
 753 
 754 {% func (g *GitItemRefsPage) GitContent() %}
 755 <div class="row">
 756@@ -36,7 +36,7 @@     <div class="logs">
 757       {% for _, b := range g.Branches %}
 758       <div class="row">
 759           <div class="col-xxl">
 760-           {%s b.String() %}
 761+           {%s b.Name().Short() %}
 762           </div>
 763       </div>
 764       {% endfor %}
 765diff --git a/templates/gititemrefs.qtpl.go b/templates/gititemrefs.qtpl.go
 766index f2d2b6fcec5540caa852103cb2513ce0bcb6b518..d2a362e5bacc6b8e2fcf10bb9da486ef48fcecda 100644
 767--- a/templates/gititemrefs.qtpl.go
 768+++ b/templates/gititemrefs.qtpl.go
 769@@ -30,29 +30,29 @@ 	Branches []*plumbing.Reference
 770 }
 771 
 772 //line gititemrefs.qtpl:11
 773-func (g *GitItemRefsPage) StreamNav(qw422016 *qt422016.Writer, name string) {
 774+func (g *GitItemRefsPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
 775 //line gititemrefs.qtpl:11
 776-	StreamGitItemNav(qw422016, name, Refs)
 777+	StreamGitItemNav(qw422016, name, ref, Refs)
 778 //line gititemrefs.qtpl:11
 779 }
 780 
 781 //line gititemrefs.qtpl:11
 782-func (g *GitItemRefsPage) WriteNav(qq422016 qtio422016.Writer, name string) {
 783+func (g *GitItemRefsPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
 784 //line gititemrefs.qtpl:11
 785 	qw422016 := qt422016.AcquireWriter(qq422016)
 786 //line gititemrefs.qtpl:11
 787-	g.StreamNav(qw422016, name)
 788+	g.StreamNav(qw422016, name, ref)
 789 //line gititemrefs.qtpl:11
 790 	qt422016.ReleaseWriter(qw422016)
 791 //line gititemrefs.qtpl:11
 792 }
 793 
 794 //line gititemrefs.qtpl:11
 795-func (g *GitItemRefsPage) Nav(name string) string {
 796+func (g *GitItemRefsPage) Nav(name, ref string) string {
 797 //line gititemrefs.qtpl:11
 798 	qb422016 := qt422016.AcquireByteBuffer()
 799 //line gititemrefs.qtpl:11
 800-	g.WriteNav(qb422016, name)
 801+	g.WriteNav(qb422016, name, ref)
 802 //line gititemrefs.qtpl:11
 803 	qs422016 := string(qb422016.B)
 804 //line gititemrefs.qtpl:11
 805@@ -117,7 +117,7 @@       <div class="row">
 806           <div class="col-xxl">
 807            `)
 808 //line gititemrefs.qtpl:39
 809-		qw422016.E().S(b.String())
 810+		qw422016.E().S(b.Name().Short())
 811 //line gititemrefs.qtpl:39
 812 		qw422016.N().S(`
 813           </div>
 814diff --git a/templates/gititemsummary.qtpl b/templates/gititemsummary.qtpl
 815index f4b0dd6ed86aa1d3f65b86798453e662db5c3c8b..5756ea51e1182941cb268f30836a0fc0902f324b 100644
 816--- a/templates/gititemsummary.qtpl
 817+++ b/templates/gititemsummary.qtpl
 818@@ -3,7 +3,7 @@ type GitItemSummaryPage struct {
 819 }
 820 %}
 821 
 822-{% func (g *GitItemSummaryPage) Nav(name string) %}{%= GitItemNav(name, Summary) %}{% endfunc %}
 823+{% func (g *GitItemSummaryPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Summary) %}{% endfunc %}
 824 
 825 {% func (g *GitItemSummaryPage) GitContent() %}
 826 <h4>Summary</h4>
 827diff --git a/templates/gititemsummary.qtpl.go b/templates/gititemsummary.qtpl.go
 828index aa41a17e5c03cc55cc9fa2a560cf7169f330ae8e..99cb984846d93b0e576a56e13479174083e0d4f5 100644
 829--- a/templates/gititemsummary.qtpl.go
 830+++ b/templates/gititemsummary.qtpl.go
 831@@ -22,29 +22,29 @@ type GitItemSummaryPage struct {
 832 }
 833 
 834 //line gititemsummary.qtpl:6
 835-func (g *GitItemSummaryPage) StreamNav(qw422016 *qt422016.Writer, name string) {
 836+func (g *GitItemSummaryPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
 837 //line gititemsummary.qtpl:6
 838-	StreamGitItemNav(qw422016, name, Summary)
 839+	StreamGitItemNav(qw422016, name, ref, Summary)
 840 //line gititemsummary.qtpl:6
 841 }
 842 
 843 //line gititemsummary.qtpl:6
 844-func (g *GitItemSummaryPage) WriteNav(qq422016 qtio422016.Writer, name string) {
 845+func (g *GitItemSummaryPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
 846 //line gititemsummary.qtpl:6
 847 	qw422016 := qt422016.AcquireWriter(qq422016)
 848 //line gititemsummary.qtpl:6
 849-	g.StreamNav(qw422016, name)
 850+	g.StreamNav(qw422016, name, ref)
 851 //line gititemsummary.qtpl:6
 852 	qt422016.ReleaseWriter(qw422016)
 853 //line gititemsummary.qtpl:6
 854 }
 855 
 856 //line gititemsummary.qtpl:6
 857-func (g *GitItemSummaryPage) Nav(name string) string {
 858+func (g *GitItemSummaryPage) Nav(name, ref string) string {
 859 //line gititemsummary.qtpl:6
 860 	qb422016 := qt422016.AcquireByteBuffer()
 861 //line gititemsummary.qtpl:6
 862-	g.WriteNav(qb422016, name)
 863+	g.WriteNav(qb422016, name, ref)
 864 //line gititemsummary.qtpl:6
 865 	qs422016 := string(qb422016.B)
 866 //line gititemsummary.qtpl:6
 867diff --git a/templates/gititemtree.qtpl b/templates/gititemtree.qtpl
 868index 778cc004ad00863b1b10e95b19a50e4b9a6dec8e..5ace7b0ea7262684dcbb60ef67ce6f4249ff15e3 100644
 869--- a/templates/gititemtree.qtpl
 870+++ b/templates/gititemtree.qtpl
 871@@ -3,7 +3,7 @@ type GitItemTreePage struct {
 872 }
 873 %}
 874 
 875-{% func (g *GitItemTreePage) Nav(name string) %}{%= GitItemNav(name, Tree) %}{% endfunc %}
 876+{% func (g *GitItemTreePage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Tree) %}{% endfunc %}
 877 
 878 {% func (g *GitItemTreePage) GitContent() %}
 879 <h4>Tree</h4>
 880diff --git a/templates/gititemtree.qtpl.go b/templates/gititemtree.qtpl.go
 881index 04861d1539348a8bad52ac42f30228b356496c99..d8beb0e09acb90fabbe5c2bb75de765952ca11a3 100644
 882--- a/templates/gititemtree.qtpl.go
 883+++ b/templates/gititemtree.qtpl.go
 884@@ -22,29 +22,29 @@ type GitItemTreePage struct {
 885 }
 886 
 887 //line gititemtree.qtpl:6
 888-func (g *GitItemTreePage) StreamNav(qw422016 *qt422016.Writer, name string) {
 889+func (g *GitItemTreePage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
 890 //line gititemtree.qtpl:6
 891-	StreamGitItemNav(qw422016, name, Tree)
 892+	StreamGitItemNav(qw422016, name, ref, Tree)
 893 //line gititemtree.qtpl:6
 894 }
 895 
 896 //line gititemtree.qtpl:6
 897-func (g *GitItemTreePage) WriteNav(qq422016 qtio422016.Writer, name string) {
 898+func (g *GitItemTreePage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
 899 //line gititemtree.qtpl:6
 900 	qw422016 := qt422016.AcquireWriter(qq422016)
 901 //line gititemtree.qtpl:6
 902-	g.StreamNav(qw422016, name)
 903+	g.StreamNav(qw422016, name, ref)
 904 //line gititemtree.qtpl:6
 905 	qt422016.ReleaseWriter(qw422016)
 906 //line gititemtree.qtpl:6
 907 }
 908 
 909 //line gititemtree.qtpl:6
 910-func (g *GitItemTreePage) Nav(name string) string {
 911+func (g *GitItemTreePage) Nav(name, ref string) string {
 912 //line gititemtree.qtpl:6
 913 	qb422016 := qt422016.AcquireByteBuffer()
 914 //line gititemtree.qtpl:6
 915-	g.WriteNav(qb422016, name)
 916+	g.WriteNav(qb422016, name, ref)
 917 //line gititemtree.qtpl:6
 918 	qs422016 := string(qb422016.B)
 919 //line gititemtree.qtpl:6
 920diff --git a/templates/gitlist.qtpl b/templates/gitlist.qtpl
 921index b7beca58d127482042da362b30d569f03ff67efb..3d7ef822b9bae8b6debebe51796799f2417513ed 100644
 922--- a/templates/gitlist.qtpl
 923+++ b/templates/gitlist.qtpl
 924@@ -17,15 +17,15 @@     <div class="event-list">
 925       {% for _, r := range p.Respositories %}
 926       <div class="event">
 927         <h4>
 928-          <a href="/{%s r.Name %}/summary">{%s r.Name %}</a>
 929+          <a href="/{%s r.Name %}">{%s r.Name %}</a>
 930         </h4>
 931         </hr>
 932         <p>{%s r.LastCommitMessage %}</p>
 933         <p><small>{%s r.LastCommitDate %}</small></p>
 934         <p>
 935-          <a href="/{%s r.Name %}/summary">summary</a>
 936-          <a href="/{%s r.Name %}/log">log</a>
 937-          <a href="/{%s r.Name %}/tree">tree</a>
 938+          <a href="/{%s r.Name %}/log/{%s r.Ref %}">log</a>
 939+          <a href="/{%s r.Name %}/tree/{%s r.Ref %}">tree</a>
 940+          <a href="/{%s r.Name %}/refs">refs</a>
 941         </p>
 942       </div>
 943       {% endfor %}
 944diff --git a/templates/gitlist.qtpl.go b/templates/gitlist.qtpl.go
 945index 73f887ab91d2df83f2be1e6241a0dfd57cd8427c..d9f7ec1ec45568e18d549fa56015753b5511221a 100644
 946--- a/templates/gitlist.qtpl.go
 947+++ b/templates/gitlist.qtpl.go
 948@@ -109,7 +109,7 @@           <a href="/`)
 949 //line gitlist.qtpl:20
 950 		qw422016.E().S(r.Name)
 951 //line gitlist.qtpl:20
 952-		qw422016.N().S(`/summary">`)
 953+		qw422016.N().S(`">`)
 954 //line gitlist.qtpl:20
 955 		qw422016.E().S(r.Name)
 956 //line gitlist.qtpl:20
 957@@ -131,17 +131,25 @@           <a href="/`)
 958 //line gitlist.qtpl:26
 959 		qw422016.E().S(r.Name)
 960 //line gitlist.qtpl:26
 961-		qw422016.N().S(`/summary">summary</a>
 962+		qw422016.N().S(`/log/`)
 963+//line gitlist.qtpl:26
 964+		qw422016.E().S(r.Ref)
 965+//line gitlist.qtpl:26
 966+		qw422016.N().S(`">log</a>
 967           <a href="/`)
 968 //line gitlist.qtpl:27
 969 		qw422016.E().S(r.Name)
 970 //line gitlist.qtpl:27
 971-		qw422016.N().S(`/log">log</a>
 972+		qw422016.N().S(`/tree/`)
 973+//line gitlist.qtpl:27
 974+		qw422016.E().S(r.Ref)
 975+//line gitlist.qtpl:27
 976+		qw422016.N().S(`">tree</a>
 977           <a href="/`)
 978 //line gitlist.qtpl:28
 979 		qw422016.E().S(r.Name)
 980 //line gitlist.qtpl:28
 981-		qw422016.N().S(`/tree">tree</a>
 982+		qw422016.N().S(`/refs">refs</a>
 983         </p>
 984       </div>
 985       `)
 986diff --git a/templates/navbar.qtpl b/templates/navbar.qtpl
 987index 8b0799d412ad6da105a309a921cfd8a14a51f99b..775f496a4b52da8eef28656dedee80fe9995871d 100644
 988--- a/templates/navbar.qtpl
 989+++ b/templates/navbar.qtpl
 990@@ -32,22 +32,27 @@           </div>
 991         </nav>
 992 {% endfunc %}
 993 
 994-{% func GitItemNav (name string, s GitSelection) %}
 995+{% func GitItemNav (name, ref string, s GitSelection) %}
 996+<div class="row">
 997+    <h3>{%s name %} {% if ref != "" && (s == Log || s == Tree)  %}@ {%s ref %}{% endif %}</h3>
 998+</div>
 999+<div class="row">
1000   <ul class="nav">
1001     <li class="nav-item">
1002       <a class="nav-link{%= insertIfEqual(s, Readme) %}" aria-current="page" href="/{%s name %}/about">about</a>
1003     </li>
1004     <li class="nav-item">
1005-      <a class="nav-link{%= insertIfEqual(s, Log) %}" aria-current="page" href="/{%s name %}/log">log</a>
1006+      <a class="nav-link{%= insertIfEqual(s, Log) %}" aria-current="page" href="/{%s name %}/log/{%s ref %}">log</a>
1007     </li>
1008     <li class="nav-item">
1009-      <a class="nav-link{%= insertIfEqual(s, Summary) %}" aria-current="page" href="/{%s name %}/summary">summary</a>
1010+      <a class="nav-link{%= insertIfEqual(s, Summary) %}" aria-current="page" href="/{%s name %}">summary</a>
1011     </li>
1012     <li class="nav-item">
1013       <a class="nav-link{%= insertIfEqual(s, Refs) %}" aria-current="page" href="/{%s name %}/refs">refs</a>
1014     </li>
1015     <li class="nav-item">
1016-      <a class="nav-link{%= insertIfEqual(s, Tree) %}" aria-current="page" href="/{%s name %}/tree">tree</a>
1017+      <a class="nav-link{%= insertIfEqual(s, Tree) %}" aria-current="page" href="/{%s name %}/tree/{%s ref %}">tree</a>
1018     </li>
1019   </ul>
1020+</div>
1021 {% endfunc %}
1022diff --git a/templates/navbar.qtpl.go b/templates/navbar.qtpl.go
1023index acf21b4a0b6c952c2df4a5567b7c34229db8da82..cddc6a6de17621590eb849a2ef2a27b84c661715 100644
1024--- a/templates/navbar.qtpl.go
1025+++ b/templates/navbar.qtpl.go
1026@@ -134,92 +134,119 @@ //line navbar.qtpl:33
1027 }
1028 
1029 //line navbar.qtpl:35
1030-func StreamGitItemNav(qw422016 *qt422016.Writer, name string, s GitSelection) {
1031+func StreamGitItemNav(qw422016 *qt422016.Writer, name, ref string, s GitSelection) {
1032 //line navbar.qtpl:35
1033 	qw422016.N().S(`
1034+<div class="row">
1035+    <h3>`)
1036+//line navbar.qtpl:37
1037+	qw422016.E().S(name)
1038+//line navbar.qtpl:37
1039+	qw422016.N().S(` `)
1040+//line navbar.qtpl:37
1041+	if ref != "" && (s == Log || s == Tree) {
1042+//line navbar.qtpl:37
1043+		qw422016.N().S(`@ `)
1044+//line navbar.qtpl:37
1045+		qw422016.E().S(ref)
1046+//line navbar.qtpl:37
1047+	}
1048+//line navbar.qtpl:37
1049+	qw422016.N().S(`</h3>
1050+</div>
1051+<div class="row">
1052   <ul class="nav">
1053     <li class="nav-item">
1054       <a class="nav-link`)
1055-//line navbar.qtpl:38
1056+//line navbar.qtpl:42
1057 	streaminsertIfEqual(qw422016, s, Readme)
1058-//line navbar.qtpl:38
1059+//line navbar.qtpl:42
1060 	qw422016.N().S(`" aria-current="page" href="/`)
1061-//line navbar.qtpl:38
1062+//line navbar.qtpl:42
1063 	qw422016.E().S(name)
1064-//line navbar.qtpl:38
1065+//line navbar.qtpl:42
1066 	qw422016.N().S(`/about">about</a>
1067     </li>
1068     <li class="nav-item">
1069       <a class="nav-link`)
1070-//line navbar.qtpl:41
1071+//line navbar.qtpl:45
1072 	streaminsertIfEqual(qw422016, s, Log)
1073-//line navbar.qtpl:41
1074+//line navbar.qtpl:45
1075 	qw422016.N().S(`" aria-current="page" href="/`)
1076-//line navbar.qtpl:41
1077+//line navbar.qtpl:45
1078 	qw422016.E().S(name)
1079-//line navbar.qtpl:41
1080-	qw422016.N().S(`/log">log</a>
1081+//line navbar.qtpl:45
1082+	qw422016.N().S(`/log/`)
1083+//line navbar.qtpl:45
1084+	qw422016.E().S(ref)
1085+//line navbar.qtpl:45
1086+	qw422016.N().S(`">log</a>
1087     </li>
1088     <li class="nav-item">
1089       <a class="nav-link`)
1090-//line navbar.qtpl:44
1091+//line navbar.qtpl:48
1092 	streaminsertIfEqual(qw422016, s, Summary)
1093-//line navbar.qtpl:44
1094+//line navbar.qtpl:48
1095 	qw422016.N().S(`" aria-current="page" href="/`)
1096-//line navbar.qtpl:44
1097+//line navbar.qtpl:48
1098 	qw422016.E().S(name)
1099-//line navbar.qtpl:44
1100-	qw422016.N().S(`/summary">summary</a>
1101+//line navbar.qtpl:48
1102+	qw422016.N().S(`">summary</a>
1103     </li>
1104     <li class="nav-item">
1105       <a class="nav-link`)
1106-//line navbar.qtpl:47
1107+//line navbar.qtpl:51
1108 	streaminsertIfEqual(qw422016, s, Refs)
1109-//line navbar.qtpl:47
1110+//line navbar.qtpl:51
1111 	qw422016.N().S(`" aria-current="page" href="/`)
1112-//line navbar.qtpl:47
1113+//line navbar.qtpl:51
1114 	qw422016.E().S(name)
1115-//line navbar.qtpl:47
1116+//line navbar.qtpl:51
1117 	qw422016.N().S(`/refs">refs</a>
1118     </li>
1119     <li class="nav-item">
1120       <a class="nav-link`)
1121-//line navbar.qtpl:50
1122+//line navbar.qtpl:54
1123 	streaminsertIfEqual(qw422016, s, Tree)
1124-//line navbar.qtpl:50
1125+//line navbar.qtpl:54
1126 	qw422016.N().S(`" aria-current="page" href="/`)
1127-//line navbar.qtpl:50
1128+//line navbar.qtpl:54
1129 	qw422016.E().S(name)
1130-//line navbar.qtpl:50
1131-	qw422016.N().S(`/tree">tree</a>
1132+//line navbar.qtpl:54
1133+	qw422016.N().S(`/tree/`)
1134+//line navbar.qtpl:54
1135+	qw422016.E().S(ref)
1136+//line navbar.qtpl:54
1137+	qw422016.N().S(`">tree</a>
1138     </li>
1139   </ul>
1140+</div>
1141 `)
1142-//line navbar.qtpl:53
1143+//line navbar.qtpl:58
1144 }
1145 
1146-//line navbar.qtpl:53
1147-func WriteGitItemNav(qq422016 qtio422016.Writer, name string, s GitSelection) {
1148-//line navbar.qtpl:53
1149+//line navbar.qtpl:58
1150+func WriteGitItemNav(qq422016 qtio422016.Writer, name, ref string, s GitSelection) {
1151+//line navbar.qtpl:58
1152 	qw422016 := qt422016.AcquireWriter(qq422016)
1153-//line navbar.qtpl:53
1154-	StreamGitItemNav(qw422016, name, s)
1155-//line navbar.qtpl:53
1156+//line navbar.qtpl:58
1157+	StreamGitItemNav(qw422016, name, ref, s)
1158+//line navbar.qtpl:58
1159 	qt422016.ReleaseWriter(qw422016)
1160-//line navbar.qtpl:53
1161+//line navbar.qtpl:58
1162 }
1163 
1164-//line navbar.qtpl:53
1165-func GitItemNav(name string, s GitSelection) string {
1166-//line navbar.qtpl:53
1167+//line navbar.qtpl:58
1168+func GitItemNav(name, ref string, s GitSelection) string {
1169+//line navbar.qtpl:58
1170 	qb422016 := qt422016.AcquireByteBuffer()
1171-//line navbar.qtpl:53
1172-	WriteGitItemNav(qb422016, name, s)
1173-//line navbar.qtpl:53
1174+//line navbar.qtpl:58
1175+	WriteGitItemNav(qb422016, name, ref, s)
1176+//line navbar.qtpl:58
1177 	qs422016 := string(qb422016.B)
1178-//line navbar.qtpl:53
1179+//line navbar.qtpl:58
1180 	qt422016.ReleaseByteBuffer(qb422016)
1181-//line navbar.qtpl:53
1182+//line navbar.qtpl:58
1183 	return qs422016
1184-//line navbar.qtpl:53
1185+//line navbar.qtpl:58
1186 }