1diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
2index 096303374b4fa36a7a62cf4f97a4bea41cb44c73..fd62e44b540b98d3f9dc04ab4d463215200deafa 100644
3--- a/pkg/handler/git/handler.go
4+++ b/pkg/handler/git/handler.go
5@@ -34,6 +34,7 @@
6 gitService interface {
7 ListRepositories() ([]*service.Repository, error)
8 ListCommits(name string, ref string, count int) ([]*object.Commit, error)
9+ LastCommit(name string, ref string) (*object.Commit, error)
10 GetHead(name string) (*plumbing.Reference, error)
11 GetTree(name, ref, path string) (*object.Tree, error)
12 IsBinary(name, ref, path string) (bool, error)
13@@ -325,6 +326,27 @@ Name: name,
14 Ref: ref,
15 GitItemBase: &templates.GitItemLogPage{
16 Commits: commits,
17+ },
18+ }
19+ templates.WritePageTemplate(w, gitList)
20+ return nil
21+}
22+
23+func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error {
24+ ext.SetHTML(w)
25+ name := r.PathValue("name")
26+ ref := r.PathValue("ref")
27+
28+ commit, err := g.gitService.LastCommit(name, ref)
29+ if err != nil {
30+ return err
31+ }
32+
33+ gitList := &templates.GitItemPage{
34+ Name: name,
35+ Ref: ref,
36+ GitItemBase: &templates.GitItemCommitPage{
37+ Commit: commit,
38 },
39 }
40 templates.WritePageTemplate(w, gitList)
41diff --git a/pkg/handler/router.go b/pkg/handler/router.go
42index 6ee7ba344943842ee40233b224fda539bcb4392b..f464ac28e50750b95b3447333f7362f3c31e3c5a 100644
43--- a/pkg/handler/router.go
44+++ b/pkg/handler/router.go
45@@ -41,6 +41,7 @@ mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
46 mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
47 mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
48 mux.HandleFunc("/{name}/log/{ref}/", gitHandler.Log)
49+ mux.HandleFunc("/{name}/commit/{ref}/", gitHandler.Commit)
50 mux.HandleFunc("/{name}/archive/{file}", gitHandler.Archive)
51 mux.HandleFunc("/config", configHandler)
52 mux.HandleFunc("/about", aboutHandler.About)
53diff --git a/pkg/service/git.go b/pkg/service/git.go
54index 1d212043bc292f173d2e44ccb451871a4469f99e..df4e3aa36917ce74895247c02a4f2a4f39f868b8 100644
55--- a/pkg/service/git.go
56+++ b/pkg/service/git.go
57@@ -94,6 +94,25 @@ }
58 return repo.Commits(count)
59 }
60
61+func (g *GitService) LastCommit(name, ref string) (*object.Commit, error) {
62+ r := g.configRepo.GetByName(name)
63+ if r == nil {
64+ return nil, ErrRepositoryNotFound
65+ }
66+
67+ repo, err := git.OpenRepository(r.Path)
68+ if err != nil {
69+ return nil, err
70+ }
71+
72+ err = repo.SetRef(ref)
73+ if err != nil {
74+ return nil, err
75+ }
76+
77+ return repo.LastCommit()
78+}
79+
80 func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, prefix string) error {
81 r := g.configRepo.GetByName(name)
82 if r == nil {
83diff --git a/templates/gititemcommit.qtpl b/templates/gititemcommit.qtpl
84new file mode 100644
85index 0000000000000000000000000000000000000000..e685f23d3e39c7ac8b44f8291617624c97f9cf92
86--- /dev/null
87+++ b/templates/gititemcommit.qtpl
88@@ -0,0 +1,19 @@
89+{% import "github.com/go-git/go-git/v5/plumbing/object" %}
90+
91+{% code
92+type GitItemCommitPage struct {
93+ Commit *object.Commit
94+}
95+%}
96+
97+{% func (g *GitItemCommitPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Log) %}{% endfunc %}
98+
99+{% func (g *GitItemCommitPage) GitContent(name, ref string) %}
100+<div class="event-list">
101+ {%= Commit(name, g.Commit) %}
102+</div>
103+
104+<div class="alert alert-info text-center" role="alert">
105+ This page is work in progress.
106+</div>
107+{% endfunc %}
108diff --git a/templates/gititemcommit.qtpl.go b/templates/gititemcommit.qtpl.go
109new file mode 100644
110index 0000000000000000000000000000000000000000..13c1fa9ae3b12dc697d47280e043e8489b8c83cf
111--- /dev/null
112+++ b/templates/gititemcommit.qtpl.go
113@@ -0,0 +1,104 @@
114+// Code generated by qtc from "gititemcommit.qtpl". DO NOT EDIT.
115+// See https://github.com/valyala/quicktemplate for details.
116+
117+//line gititemcommit.qtpl:1
118+package templates
119+
120+//line gititemcommit.qtpl:1
121+import "github.com/go-git/go-git/v5/plumbing/object"
122+
123+//line gititemcommit.qtpl:3
124+import (
125+ qtio422016 "io"
126+
127+ qt422016 "github.com/valyala/quicktemplate"
128+)
129+
130+//line gititemcommit.qtpl:3
131+var (
132+ _ = qtio422016.Copy
133+ _ = qt422016.AcquireByteBuffer
134+)
135+
136+//line gititemcommit.qtpl:4
137+type GitItemCommitPage struct {
138+ Commit *object.Commit
139+}
140+
141+//line gititemcommit.qtpl:9
142+func (g *GitItemCommitPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
143+//line gititemcommit.qtpl:9
144+ StreamGitItemNav(qw422016, name, ref, Log)
145+//line gititemcommit.qtpl:9
146+}
147+
148+//line gititemcommit.qtpl:9
149+func (g *GitItemCommitPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
150+//line gititemcommit.qtpl:9
151+ qw422016 := qt422016.AcquireWriter(qq422016)
152+//line gititemcommit.qtpl:9
153+ g.StreamNav(qw422016, name, ref)
154+//line gititemcommit.qtpl:9
155+ qt422016.ReleaseWriter(qw422016)
156+//line gititemcommit.qtpl:9
157+}
158+
159+//line gititemcommit.qtpl:9
160+func (g *GitItemCommitPage) Nav(name, ref string) string {
161+//line gititemcommit.qtpl:9
162+ qb422016 := qt422016.AcquireByteBuffer()
163+//line gititemcommit.qtpl:9
164+ g.WriteNav(qb422016, name, ref)
165+//line gititemcommit.qtpl:9
166+ qs422016 := string(qb422016.B)
167+//line gititemcommit.qtpl:9
168+ qt422016.ReleaseByteBuffer(qb422016)
169+//line gititemcommit.qtpl:9
170+ return qs422016
171+//line gititemcommit.qtpl:9
172+}
173+
174+//line gititemcommit.qtpl:11
175+func (g *GitItemCommitPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
176+//line gititemcommit.qtpl:11
177+ qw422016.N().S(`
178+<div class="event-list">
179+ `)
180+//line gititemcommit.qtpl:13
181+ StreamCommit(qw422016, name, g.Commit)
182+//line gititemcommit.qtpl:13
183+ qw422016.N().S(`
184+</div>
185+
186+<div class="alert alert-info text-center" role="alert">
187+ This page is work in progress.
188+</div>
189+`)
190+//line gititemcommit.qtpl:19
191+}
192+
193+//line gititemcommit.qtpl:19
194+func (g *GitItemCommitPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
195+//line gititemcommit.qtpl:19
196+ qw422016 := qt422016.AcquireWriter(qq422016)
197+//line gititemcommit.qtpl:19
198+ g.StreamGitContent(qw422016, name, ref)
199+//line gititemcommit.qtpl:19
200+ qt422016.ReleaseWriter(qw422016)
201+//line gititemcommit.qtpl:19
202+}
203+
204+//line gititemcommit.qtpl:19
205+func (g *GitItemCommitPage) GitContent(name, ref string) string {
206+//line gititemcommit.qtpl:19
207+ qb422016 := qt422016.AcquireByteBuffer()
208+//line gititemcommit.qtpl:19
209+ g.WriteGitContent(qb422016, name, ref)
210+//line gititemcommit.qtpl:19
211+ qs422016 := string(qb422016.B)
212+//line gititemcommit.qtpl:19
213+ qt422016.ReleaseByteBuffer(qb422016)
214+//line gititemcommit.qtpl:19
215+ return qs422016
216+//line gititemcommit.qtpl:19
217+}