Skip to content

Commit ffc08c1

Browse files
authored
Do not read or write git reference files directly (#18079)
Git will and can pack references into packfiles and therefore if you write/read the files directly you will get false results. Instead you should use update-ref and show-ref. To that end I have created three new functions in git/repo_commit.go that will do this correctly. Related #17191 Signed-off-by: Andrew Thornton <[email protected]>
1 parent e0cf3d8 commit ffc08c1

File tree

6 files changed

+32
-45
lines changed

6 files changed

+32
-45
lines changed

modules/git/repo_commit_gogit.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
3131
return ref.Hash().String(), nil
3232
}
3333

34+
// SetReference sets the commit ID string of given reference (e.g. branch or tag).
35+
func (repo *Repository) SetReference(name, commitID string) error {
36+
return repo.gogitRepo.Storer.SetReference(plumbing.NewReferenceFromStrings(name, commitID))
37+
}
38+
39+
// RemoveReference removes the given reference (e.g. branch or tag).
40+
func (repo *Repository) RemoveReference(name string) error {
41+
return repo.gogitRepo.Storer.RemoveReference(plumbing.ReferenceName(name))
42+
}
43+
3444
// ConvertToSHA1 returns a Hash object from a potential ID string
3545
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
3646
if len(commitID) == 40 {

modules/git/repo_commit_nogogit.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
4949
return string(shaBs), nil
5050
}
5151

52+
// SetReference sets the commit ID string of given reference (e.g. branch or tag).
53+
func (repo *Repository) SetReference(name, commitID string) error {
54+
_, err := NewCommandContext(repo.Ctx, "update-ref", name, commitID).RunInDir(repo.Path)
55+
return err
56+
}
57+
58+
// RemoveReference removes the given reference (e.g. branch or tag).
59+
func (repo *Repository) RemoveReference(name string) error {
60+
_, err := NewCommandContext(repo.Ctx, "update-ref", "--no-deref", "-d", name).RunInDir(repo.Path)
61+
return err
62+
}
63+
5264
// IsCommitExist returns true if given commit exists in current repository.
5365
func (repo *Repository) IsCommitExist(name string) bool {
5466
_, err := NewCommandContext(repo.Ctx, "cat-file", "-e", name).RunInDir(repo.Path)

modules/git/repo_compare.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"errors"
1212
"fmt"
1313
"io"
14-
"io/ioutil"
1514
"os"
1615
"path/filepath"
1716
"regexp"
@@ -275,25 +274,6 @@ func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) err
275274
return err
276275
}
277276

278-
// ReadPullHead will fetch a pull ref if possible or return an error
279-
func (repo *Repository) ReadPullHead(prID int64) (commitSHA string, err error) {
280-
headPath := fmt.Sprintf("refs/pull/%d/head", prID)
281-
fullHeadPath := filepath.Join(repo.Path, headPath)
282-
loadHead, err := os.Open(fullHeadPath)
283-
if err != nil {
284-
return "", err
285-
}
286-
defer loadHead.Close()
287-
// Read only the first line of the patch - usually it contains the first commit made in patch
288-
scanner := bufio.NewScanner(loadHead)
289-
scanner.Scan()
290-
commitHead := scanner.Text()
291-
if len(commitHead) != 40 {
292-
return "", errors.New("head file doesn't contain valid commit ID")
293-
}
294-
return commitHead, nil
295-
}
296-
297277
// ReadPatchCommit will check if a diff patch exists and return stats
298278
func (repo *Repository) ReadPatchCommit(prID int64) (commitSHA string, err error) {
299279
// Migrated repositories download patches to "pulls" location
@@ -315,16 +295,3 @@ func (repo *Repository) ReadPatchCommit(prID int64) (commitSHA string, err error
315295
}
316296
return commitSHA, nil
317297
}
318-
319-
// WritePullHead will populate a PR head retrieved from patch file
320-
func (repo *Repository) WritePullHead(prID int64, commitSHA string) error {
321-
headPath := fmt.Sprintf("refs/pull/%d", prID)
322-
fullHeadPath := filepath.Join(repo.Path, headPath)
323-
// Create missing directory just in case
324-
if err := os.MkdirAll(fullHeadPath, os.ModePerm); err != nil {
325-
return err
326-
}
327-
commitBytes := []byte(commitSHA)
328-
pullPath := filepath.Join(fullHeadPath, "head")
329-
return ioutil.WriteFile(pullPath, commitBytes, os.ModePerm)
330-
}

modules/git/repo_compare_test.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"bytes"
99
"io"
1010
"path/filepath"
11-
"strings"
1211
"testing"
1312

1413
"code.gitea.io/gitea/modules/util"
@@ -63,18 +62,18 @@ func TestReadWritePullHead(t *testing.T) {
6362
assert.NoError(t, err)
6463
defer repo.Close()
6564
// Try to open non-existing Pull
66-
_, err = repo.ReadPullHead(0)
65+
_, err = repo.GetRefCommitID(PullPrefix + "0/head")
6766
assert.Error(t, err)
6867
// Write a fake sha1 with only 40 zeros
69-
newCommit := strings.Repeat("0", 40)
70-
err = repo.WritePullHead(1, newCommit)
68+
newCommit := "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"
69+
err = repo.SetReference(PullPrefix+"1/head", newCommit)
7170
assert.NoError(t, err)
72-
headFile := filepath.Join(repo.Path, "refs/pull/1/head")
7371
// Remove file after the test
74-
defer util.Remove(headFile)
75-
assert.FileExists(t, headFile)
72+
defer func() {
73+
_ = repo.RemoveReference(PullPrefix + "1/head")
74+
}()
7675
// Read the file created
77-
headContents, err := repo.ReadPullHead(1)
76+
headContents, err := repo.GetRefCommitID(PullPrefix + "1/head")
7877
assert.NoError(t, err)
7978
assert.Len(t, string(headContents), 40)
8079
assert.True(t, string(headContents) == newCommit)

routers/web/repo/pull.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,13 +325,13 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C
325325
if pull.MergeBase == "" {
326326
var commitSHA, parentCommit string
327327
// If there is a head or a patch file, and it is readable, grab info
328-
commitSHA, err := ctx.Repo.GitRepo.ReadPullHead(pull.Index)
328+
commitSHA, err := ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitRefName())
329329
if err != nil {
330330
// Head File does not exist, try the patch
331331
commitSHA, err = ctx.Repo.GitRepo.ReadPatchCommit(pull.Index)
332332
if err == nil {
333333
// Recreate pull head in files for next time
334-
if err := ctx.Repo.GitRepo.WritePullHead(pull.Index, commitSHA); err != nil {
334+
if err := ctx.Repo.GitRepo.SetReference(pull.GetGitRefName(), commitSHA); err != nil {
335335
log.Error("Could not write head file", err)
336336
}
337337
} else {

services/migrations/gitea_uploader.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,8 +698,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
698698
if pr.Head.SHA != "" {
699699
// Git update-ref remove bad references with a relative path
700700
log.Warn("Deprecated local head, removing : %v", pr.Head.SHA)
701-
relPath := pr.GetGitRefName()
702-
_, err = git.NewCommand("update-ref", "--no-deref", "-d", relPath).RunInDir(g.repo.RepoPath())
701+
err = g.gitRepo.RemoveReference(pr.GetGitRefName())
703702
} else {
704703
// The SHA is empty, remove the head file
705704
log.Warn("Empty reference, removing : %v", pullHead)

0 commit comments

Comments
 (0)