Lightweight and easily self-hostable Git forge. git.poy.ooo
git-forge selfhosting homebrew
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143package git
import ( "errors" "farga/lib" "fmt" "os" "path/filepath" "strings"
git "github.com/go-git/go-git/v6" "github.com/go-git/go-git/v6/plumbing" "github.com/go-git/go-git/v6/plumbing/object" "github.com/google/uuid")
var ErrEmptyRepo = errors.New("git: repository has no branches. (blank repo)")var ErrRepoDoesNotExist = errors.New("git: no such repository exists.")var ErrRepoHasNoBranches = errors.New("git: repository has no branches.")var ErrRepoHasNoHead = errors.New("git: repository has no HEAD.")var ErrInvalidBranch = errors.New("git: no such branch exists.")
func RepoPath(user uuid.UUID, repo uuid.UUID) string { base, err := filepath.Abs(lib.GitReposDir) if err != nil { return "" }
return strings.TrimSuffix(filepath.Join( base, user.String(), repo.String(), )+"/", ".git")}
// creates a git repofunc InitRepo(userID uuid.UUID, repoID uuid.UUID) (*git.Repository, error) { repoPath := RepoPath(userID, repoID) // if you want to auto-setup a branch, run: // plumbedBranch := plumbing.NewBranchReferenceName(branch) // repo, err := git.PlainInit(repoPath, true, git.WithDefaultBranch(plumbedBranch)) // is a bare repo: https://tms-outsource.com/blog/posts/what-is-a-bare-repository/ repo, err := git.PlainInit(repoPath, true) // is a bare repo: https://tms-outsource.com/blog/posts/what-is-a-bare-repository/ return repo, err}
type GitRepo struct { Git *git.Repository Head *plumbing.Reference ShortHash string LatestCommit *object.Commit Readme ReadmeType Files []File}
// Opens a git repo by the defined branch (branch can be nil to be autoselected as HEAD)func Repo(userID uuid.UUID, repoID uuid.UUID, branch string) (*GitRepo, error) { path := RepoPath(userID, repoID) repo, err := git.PlainOpen(path) if err != nil { switch err { case git.ErrRepositoryNotExists: return nil, ErrRepoDoesNotExist default: return nil, err } }
head, err := ResolveHead(repo, branch) // potentially nil. if err != nil && err != ErrRepoHasNoHead { return nil, err }
var latestCommit *object.Commit var shortHash string var readme ReadmeType
// extra info if head != nil { latestCommit, err = object.GetCommit(repo.Storer, head.Hash()) if err != nil { fmt.Println(err) } else { if tree, err := latestCommit.Tree(); err == nil { readme = Readme(tree) } shortHash, err = ShortenHash(head.Hash().String()) } }
return &GitRepo{ Git: repo, ShortHash: shortHash, Head: head, LatestCommit: latestCommit, Readme: readme, }, nil}
// resolves the head of a git repofunc ResolveHead(repo *git.Repository, branchName string) (ref *plumbing.Reference, err error) { // if a branch was provided if branchName != "" { ref, err = repo.Reference(plumbing.NewBranchReferenceName(branchName), false) if errors.Is(err, plumbing.ErrReferenceNotFound) { return nil, ErrInvalidBranch // doesn't exist. } return ref, nil }
ref, err = repo.Head() // get HEAD as default if err != nil { // no HEAD? fine. I'll do it myself branches, branchErr := repo.Branches() if branchErr != nil { return nil, branchErr // idk man. } firstBranch, nextErr := branches.Next() branches.Close() if nextErr != nil { // holy shit there are no branches return nil, ErrRepoHasNoHead } // thank god there's a branch return firstBranch, nil } // just return HEAD return ref, nil}
// gets the tree from a commit.func BaseTree(repo *git.Repository, head *plumbing.Reference) (*object.Tree, error) { commit, err := object.GetCommit(repo.Storer, head.Hash()) if err != nil { return nil, err } return commit.Tree()}
// deletes a repo on-disk.func DeleteRepo(userID uuid.UUID, repoID uuid.UUID) { os.RemoveAll(RepoPath(userID, repoID))}