github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/symbolicref.go (about) 1 package git 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 ) 8 9 var DetachedHead error = errors.New("In Detached HEAD state") 10 11 // A SymbolicRef is generally "HEAD". It's a fake symlink used by git 12 // to support operating systems that don't have symlinks 13 type SymbolicRef string 14 15 func (s SymbolicRef) String() string { 16 return string(s) 17 } 18 19 func (s SymbolicRef) CommitID(c *Client) (CommitID, error) { 20 rspec, err := SymbolicRefGet(c, SymbolicRefOptions{}, s) 21 if err != nil { 22 return CommitID{}, err 23 } 24 return rspec.CommitID(c) 25 } 26 27 // SymbolicRefOptions represents the command line options 28 // that may be passed on the command line. (NB. None of these 29 // are implemented.) 30 type SymbolicRefOptions struct { 31 Quiet bool 32 Delete bool 33 Short bool 34 } 35 36 // Gets a RefSpec for a symbolic ref. Returns "" if symname is not a valid 37 // symbolic ref. 38 func SymbolicRefGet(c *Client, opts SymbolicRefOptions, symname SymbolicRef) (RefSpec, error) { 39 file := c.GitDir.File(File(symname)) 40 41 value, err := file.ReadAll() 42 if err != nil { 43 return "", err 44 } 45 46 if !strings.HasPrefix(value, "ref: ") { 47 return RefSpec(value), DetachedHead 48 } 49 if opts.Short { 50 return RefSpec(strings.TrimSpace(strings.TrimPrefix(value, "ref: refs/heads/"))), nil 51 } 52 return RefSpec(strings.TrimSpace(strings.TrimPrefix(value, "ref: "))), nil 53 } 54 55 func SymbolicRefDelete(c *Client, opts SymbolicRefOptions, symname SymbolicRef) error { 56 file := c.GitDir.File(File(symname)) 57 if !file.Exists() { 58 return fmt.Errorf("SymbolicRef %s does not exist.", symname) 59 } 60 return file.Remove() 61 62 } 63 64 func SymbolicRefUpdate(c *Client, opts SymbolicRefOptions, symname SymbolicRef, refvalue RefSpec, reason string) error { 65 if !strings.HasPrefix(refvalue.String(), "refs/") { 66 return fmt.Errorf("Refusing to point %s outside of refs/", symname) 67 } 68 69 if reason != "" { 70 if reflog := c.GitDir.File(File("logs/" + symname.String())); reflog.Exists() { 71 if err := updateReflog(c, false, reflog, symname, refvalue, reason); err != nil { 72 return fmt.Errorf("Error updating reflog: %v", err) 73 } 74 } 75 } 76 77 file, err := c.GitDir.Create(File(symname)) 78 if err != nil { 79 return fmt.Errorf("Error creating SymbolicRef: %v", err) 80 } 81 defer file.Close() 82 83 fmt.Fprintf(file, "ref: %s", refvalue) 84 return nil 85 }