github.com/purpleclay/gitz@v0.8.2-0.20240515052600-43f80eea2fe1/push.go (about) 1 package git 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // PushOption provides a way of setting specific options during a git 9 // push operation. Each supported option can customize the way in which 10 // references are pushed back to the remote 11 type PushOption func(*pushOptions) 12 13 type pushOptions struct { 14 All bool 15 Config []string 16 Delete bool 17 PushOptions []string 18 Tags bool 19 RefSpecs []string 20 } 21 22 // WithAllBranches will push all locally created branch references 23 // back to the remote 24 func WithAllBranches() PushOption { 25 return func(opts *pushOptions) { 26 opts.All = true 27 } 28 } 29 30 // WithAllTags will push all locally created tag references back 31 // to the remote 32 func WithAllTags() PushOption { 33 return func(opts *pushOptions) { 34 opts.Tags = true 35 } 36 } 37 38 // WithDeleteRefSpecs will trigger the deletion of any named references 39 // when pushed back to the remote 40 func WithDeleteRefSpecs(refs ...string) PushOption { 41 return func(opts *pushOptions) { 42 opts.Delete = true 43 opts.RefSpecs = trim(refs...) 44 } 45 } 46 47 // WithPushConfig allows temporary git config to be set while pushing 48 // changes to the remote. Config set using this approach will override 49 // any config defined within existing git config files. Config must be 50 // provided as key value pairs, mismatched config will result in an 51 // [ErrMissingConfigValue] error. Any invalid paths will result in an 52 // [ErrInvalidConfigPath] error 53 func WithPushConfig(kv ...string) PushOption { 54 return func(opts *pushOptions) { 55 opts.Config = trim(kv...) 56 } 57 } 58 59 // WithPushOptions allows any number of aribitrary strings to be pushed 60 // to the remote server. All options are transmitted in their received 61 // order. A server must have the git config setting receive.advertisePushOptions 62 // set to true to receive push options 63 func WithPushOptions(options ...string) PushOption { 64 return func(opts *pushOptions) { 65 opts.PushOptions = trim(options...) 66 } 67 } 68 69 // WithRefSpecs allows local references to be cherry-picked and 70 // pushed back to the remote. A reference (or refspec) can be as 71 // simple as a name, where git will automatically resolve any 72 // ambiguity, or as explicit as providing a source and destination 73 // for each local reference within the remote. Check out the official 74 // git documentation on how to write a more complex [refspec] 75 // 76 // [refspec]: https://git-scm.com/docs/git-push#Documentation/git-push.txt-ltrefspecgt82308203 77 func WithRefSpecs(refs ...string) PushOption { 78 return func(opts *pushOptions) { 79 opts.RefSpecs = trim(refs...) 80 } 81 } 82 83 // Push (or upload) all local changes to the remote repository. 84 // By default, changes associated with the current branch will 85 // be pushed back to the remote. Options can be provided to 86 // configure branch and tag push semantics 87 func (c *Client) Push(opts ...PushOption) (string, error) { 88 options := &pushOptions{} 89 for _, opt := range opts { 90 opt(options) 91 } 92 93 cfg, err := ToInlineConfig(options.Config...) 94 if err != nil { 95 return "", err 96 } 97 98 var buf strings.Builder 99 buf.WriteString("git") 100 101 if len(cfg) > 0 { 102 buf.WriteString(" ") 103 buf.WriteString(strings.Join(cfg, " ")) 104 } 105 buf.WriteString(" push") 106 107 for _, po := range options.PushOptions { 108 buf.WriteString(" --push-option=" + po) 109 } 110 111 if options.All { 112 buf.WriteString(" --all") 113 } else if options.Tags { 114 buf.WriteString(" --tags") 115 } else if len(options.RefSpecs) > 0 { 116 buf.WriteString(" origin ") 117 if options.Delete { 118 buf.WriteString("--delete ") 119 } 120 121 buf.WriteString(strings.Join(options.RefSpecs, " ")) 122 } else { 123 out, err := c.exec("git branch --show-current") 124 if err != nil { 125 return out, err 126 } 127 buf.WriteString(fmt.Sprintf(" origin %s", out)) 128 } 129 130 return c.exec(buf.String()) 131 } 132 133 // PushRef will push an individual reference to the remote repository 134 // Deprecated: use [Push] instead 135 func (c *Client) PushRef(ref string) (string, error) { 136 return c.exec(fmt.Sprintf("git push origin %s", ref)) 137 }