From f3bf4ea90beaeb7bed70c10e925e0cec6fb011aa Mon Sep 17 00:00:00 2001 From: Billy Gor Date: Tue, 11 Aug 2015 16:54:22 +0200 Subject: [PATCH] major pre-push optimization this change improves drastically pre-push behaviour, by not sending lfs objects which are already on a remote. Works perfectly with pushing new branches and tags. currently pre-push command analyse "local sha1" vs "remote sha1" of the ref being pushed and if "remote sha1" is available locally tries to send only lfs objects introduced with new commits. why this is broken: - remote branch might have moved forward (local repo is not up to date). In this case you have no chance to isolate new lfs objects ("remote sha1" does not exist locally) and git-lfs sends everything from the local branch history. - remote branch does not exist (or new tag is pushed). Same consequences. But what is important - local repository always have remote references, from which user created his local branch and started making some local changes. So, all we have to do is to identify new lfs objects which do not exist on remote references. And all this can be easily achieved with the same all mighty git rev-list command. This change makes git-lfs usable with gerrit, where changes are uploaded by using magic gerrit branches which does not really exist. i.e. git push origin master:refs/for/master in this case "refs/for/master" does not exist and git feeds all 0-s as "remote sha1". --- commands/command_pre_push.go | 3 ++- lfs/scanner.go | 27 ++++++++++++++++++++++----- test/test-credentials.sh | 10 ++++++---- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/commands/command_pre_push.go b/commands/command_pre_push.go index 60647d82..a18d011f 100644 --- a/commands/command_pre_push.go +++ b/commands/command_pre_push.go @@ -67,7 +67,8 @@ func prePushCommand(cmd *cobra.Command, args []string) { } // Just use scanner here - pointers, err := lfs.ScanRefs(left, right, nil) + scanOpt := &lfs.ScanRefsOptions{ScanMode: lfs.ScanLeftToRemoteMode, RemoteName: lfs.Config.CurrentRemote} + pointers, err := lfs.ScanRefs(left, right, scanOpt) if err != nil { Panic(err, "Error scanning for Git LFS files") } diff --git a/lfs/scanner.go b/lfs/scanner.go index b10fca5e..ede2e3dc 100644 --- a/lfs/scanner.go +++ b/lfs/scanner.go @@ -3,6 +3,7 @@ package lfs import ( "bufio" "bytes" + "errors" "io" "os/exec" "regexp" @@ -60,9 +61,18 @@ type indexFile struct { var z40 = regexp.MustCompile(`\^?0{40}`) +type ScanningMode int + +const ( + ScanRefsMode = ScanningMode(iota) // 0 - or default scan mode + ScanAllMode = ScanningMode(iota) + ScanLeftToRemoteMode = ScanningMode(iota) +) + type ScanRefsOptions struct { + ScanMode ScanningMode + RemoteName string SkipDeletedBlobs bool - scanAll bool nameMap map[string]string } @@ -73,7 +83,9 @@ func ScanRefs(refLeft, refRight string, opt *ScanRefsOptions) ([]*WrappedPointer if opt == nil { opt = &ScanRefsOptions{} } - opt.scanAll = refLeft == "" + if refLeft == "" { + opt.ScanMode = ScanAllMode + } opt.nameMap = make(map[string]string, 0) start := time.Now() @@ -174,9 +186,8 @@ func ScanIndex() ([]*WrappedPointer, error) { // channel from which sha1 strings can be read. func revListShas(refLeft, refRight string, opt ScanRefsOptions) (chan string, error) { refArgs := []string{"rev-list", "--objects"} - if opt.scanAll { - refArgs = append(refArgs, "--all") - } else { + switch opt.ScanMode { + case ScanRefsMode: if opt.SkipDeletedBlobs { refArgs = append(refArgs, "--no-walk") } else { @@ -187,6 +198,12 @@ func revListShas(refLeft, refRight string, opt ScanRefsOptions) (chan string, er if refRight != "" && !z40.MatchString(refRight) { refArgs = append(refArgs, refRight) } + case ScanAllMode: + refArgs = append(refArgs, "--all") + case ScanLeftToRemoteMode: + refArgs = append(refArgs, refLeft, "--not", "--remotes="+opt.RemoteName) + default: + return nil, errors.New("scanner: unknown scan type: " + strconv.Itoa(int(opt.ScanMode))) } cmd, err := startCommand("git", refArgs...) diff --git a/test/test-credentials.sh b/test/test-credentials.sh index 9fa5fef6..c562148a 100755 --- a/test/test-credentials.sh +++ b/test/test-credentials.sh @@ -122,13 +122,15 @@ begin_test "credentials with useHttpPath, with correct password" git lfs track "*.dat" 2>&1 | tee track.log grep "Tracking \*.dat" track.log - contents="a" + # creating new branch does not re-sent any objects existing on other + # remote branches anymore, generate new object, different from prev tests + contents="b" contents_oid=$(printf "$contents" | shasum -a 256 | cut -f 1 -d " ") - printf "$contents" > a.dat - git add a.dat + printf "$contents" > b.dat + git add b.dat git add .gitattributes - git commit -m "add a.dat" + git commit -m "add b.dat" git push origin with-path-correct-pass 2>&1 | tee push.log grep "(1 of 1 files)" push.log