Skip to content

Commit

Permalink
Open GitHub tree view for current ref.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmalloc committed Oct 20, 2024
1 parent c4fc782 commit 5357fa6
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 188 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 0.7.4 (2024-10-21)

- **[IMPROVED]** `grit open` (aka `browse`) now opens the GitHub tree view for
the current branch, tag or hash, instead of always showing the default branch.

## 0.7.3 (2022-03-23)

- The `default-branch` configuration setting now defaults to `main`
Expand Down
69 changes: 66 additions & 3 deletions cmd/grit/browse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package main

import (
"net/url"
"path"
"strings"

git "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/jmalloc/grit"
"github.com/jmalloc/grit/index"
"github.com/jmalloc/grit/pathutil"
"github.com/skratchdot/open-golang/open"
"github.com/urfave/cli"
)

func browse(cfg grit.Config, idx *index.Index, c *cli.Context, branchName *string) error {
func browse(cfg grit.Config, idx *index.Index, c *cli.Context) error {
dir, ok, err := dirFromSlugArg(cfg, idx, c, 0, pathutil.PreferBase)
if err != nil {
return err
Expand All @@ -37,11 +40,71 @@ func browse(cfg grit.Config, idx *index.Index, c *cli.Context, branchName *strin
Path: strings.TrimSuffix(ep.Path, ".git"),
}

if branchName != nil && *branchName != "" {
u.Path += "/tree/" + *branchName
r, err := git.PlainOpen(dir)
if err != nil {
return err
}

// If we can determine the "HEAD" of the local clone, open the tree view for
// that commit. Otherwise, open the repository's root.
if head, err := r.Head(); err == nil {

// If the head's name is "HEAD", it's a detached HEAD. If the HEAD
// refers to a branch, the name will be the reference to that branch.
if head.Name() == "HEAD" {
// In this case, we check to see if there is a singular tag that
// refers to the commit, and if so open the tree for the tag name.
//
// This is purely for UX, as the user probably expects to see the
// tag name in the URL.
head = resolveUniqueTag(r, head)
}

// If we still have a detached head, load the tree view for the commit
// hash; we have no more user-friendly tag or branch name.
ref := head.Name().Short()
if ref == "HEAD" {
ref = head.Hash().String()
}

u.Path = path.Join(u.Path, "tree", ref)
}

writef(c, "opening %s", u.String())

return open.Run(u.String())
}

// resolveUniqueTag returns the reference to a tag that refers to ref, if
// exactly one exists; otherwise, it returns ref.
func resolveUniqueTag(r *git.Repository, ref *plumbing.Reference) *plumbing.Reference {
tags, err := r.Tags()
if err != nil {
return ref
}
defer tags.Close()

var refs []*plumbing.Reference

tags.ForEach(
func(tagRef *plumbing.Reference) error {
if tagRef.Hash() == ref.Hash() {
// Lightweight tag that points to ref.
refs = append(refs, tagRef)
} else if tag, err := r.TagObject(tagRef.Hash()); err == nil {
// Annotated tag that points to ref.
if tag.Target == ref.Hash() {
refs = append(refs, tagRef)
}
}

return nil
},
)

if len(refs) == 1 {
return refs[0]
}

return ref
}
34 changes: 28 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/jmalloc/grit

go 1.16
go 1.23

require (
github.com/BurntSushi/toml v0.2.0
Expand All @@ -10,12 +10,34 @@ require (
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4
github.com/go-git/go-git/v5 v5.11.0
github.com/google/go-github v14.0.1-0.20171126021131-a89ea1cdf799+incompatible
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
github.com/juju/ansiterm v0.0.0-20161107204639-35c59b9e0fe2 // indirect
github.com/lunixbochs/vtclean v0.0.0-20170504063817-d14193dfc626 // indirect
github.com/manifoldco/promptui v0.2.1
github.com/mattn/go-colorable v0.0.10-0.20171111065953-6fcc0c1fd9b6 // indirect
github.com/manifoldco/promptui v0.9.0
github.com/mattn/go-isatty v0.0.3
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
github.com/urfave/cli v1.19.1
)

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
Loading

0 comments on commit 5357fa6

Please sign in to comment.