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  }