github.com/git-lfs/git-lfs@v2.5.2+incompatible/commands/command_push.go (about) 1 package commands 2 3 import ( 4 "os" 5 6 "github.com/git-lfs/git-lfs/errors" 7 "github.com/git-lfs/git-lfs/git" 8 "github.com/git-lfs/git-lfs/lfs" 9 "github.com/git-lfs/git-lfs/tq" 10 "github.com/rubyist/tracerx" 11 "github.com/spf13/cobra" 12 ) 13 14 var ( 15 pushDryRun = false 16 pushObjectIDs = false 17 pushAll = false 18 useStdin = false 19 20 // shares some global vars and functions with command_pre_push.go 21 ) 22 23 // pushCommand pushes local objects to a Git LFS server. It takes two 24 // arguments: 25 // 26 // `<remote> <remote ref>` 27 // 28 // Remote must be a remote name, not a URL 29 // 30 // pushCommand calculates the git objects to send by comparing the range 31 // of commits between the local and remote git servers. 32 func pushCommand(cmd *cobra.Command, args []string) { 33 if len(args) == 0 { 34 Print("Specify a remote and a remote branch name (`git lfs push origin master`)") 35 os.Exit(1) 36 } 37 38 requireGitVersion() 39 40 // Remote is first arg 41 if err := cfg.SetValidPushRemote(args[0]); err != nil { 42 Exit("Invalid remote name %q: %s", args[0], err) 43 } 44 45 ctx := newUploadContext(pushDryRun) 46 if pushObjectIDs { 47 if len(args) < 2 { 48 Print("Usage: git lfs push --object-id <remote> <lfs-object-id> [lfs-object-id] ...") 49 return 50 } 51 52 uploadsWithObjectIDs(ctx, args[1:]) 53 } else { 54 if len(args) < 1 { 55 Print("Usage: git lfs push --dry-run <remote> [ref]") 56 return 57 } 58 59 uploadsBetweenRefAndRemote(ctx, args[1:]) 60 } 61 } 62 63 func uploadsBetweenRefAndRemote(ctx *uploadContext, refnames []string) { 64 tracerx.Printf("Upload refs %v to remote %v", refnames, ctx.Remote) 65 66 updates, err := lfsPushRefs(refnames, pushAll) 67 if err != nil { 68 Error(err.Error()) 69 Exit("Error getting local refs.") 70 } 71 72 if err := uploadForRefUpdates(ctx, updates, pushAll); err != nil { 73 ExitWithError(err) 74 } 75 } 76 77 func uploadsWithObjectIDs(ctx *uploadContext, oids []string) { 78 pointers := make([]*lfs.WrappedPointer, len(oids)) 79 for i, oid := range oids { 80 mp, err := ctx.gitfilter.ObjectPath(oid) 81 if err != nil { 82 ExitWithError(errors.Wrap(err, "Unable to find local media path:")) 83 } 84 85 stat, err := os.Stat(mp) 86 if err != nil { 87 ExitWithError(errors.Wrap(err, "Unable to stat local media path")) 88 } 89 90 pointers[i] = &lfs.WrappedPointer{ 91 Name: mp, 92 Pointer: &lfs.Pointer{ 93 Oid: oid, 94 Size: stat.Size(), 95 }, 96 } 97 } 98 99 q := ctx.NewQueue(tq.RemoteRef(currentRemoteRef())) 100 ctx.UploadPointers(q, pointers...) 101 ctx.CollectErrors(q) 102 ctx.ReportErrors() 103 } 104 105 // lfsPushRefs returns valid ref updates from the given ref and --all arguments. 106 // Either one or more refs can be explicitly specified, or --all indicates all 107 // local refs are pushed. 108 func lfsPushRefs(refnames []string, pushAll bool) ([]*git.RefUpdate, error) { 109 localrefs, err := git.LocalRefs() 110 if err != nil { 111 return nil, err 112 } 113 114 if pushAll && len(refnames) == 0 { 115 refs := make([]*git.RefUpdate, len(localrefs)) 116 for i, lr := range localrefs { 117 refs[i] = git.NewRefUpdate(cfg.Git, cfg.PushRemote(), lr, nil) 118 } 119 return refs, nil 120 } 121 122 reflookup := make(map[string]*git.Ref, len(localrefs)) 123 for _, ref := range localrefs { 124 reflookup[ref.Name] = ref 125 } 126 127 refs := make([]*git.RefUpdate, len(refnames)) 128 for i, name := range refnames { 129 if left, ok := reflookup[name]; ok { 130 refs[i] = git.NewRefUpdate(cfg.Git, cfg.PushRemote(), left, nil) 131 } else { 132 left := &git.Ref{Name: name, Type: git.RefTypeOther, Sha: name} 133 refs[i] = git.NewRefUpdate(cfg.Git, cfg.PushRemote(), left, nil) 134 } 135 } 136 137 return refs, nil 138 } 139 140 func init() { 141 RegisterCommand("push", pushCommand, func(cmd *cobra.Command) { 142 cmd.Flags().BoolVarP(&pushDryRun, "dry-run", "d", false, "Do everything except actually send the updates") 143 cmd.Flags().BoolVarP(&pushObjectIDs, "object-id", "o", false, "Push LFS object ID(s)") 144 cmd.Flags().BoolVarP(&pushAll, "all", "a", false, "Push all objects for the current ref to the remote.") 145 }) 146 }