code: func catFileBatchTree(treeblobs *TreeBlobChannelWrapper) (*PointerChannelWrapper, error) {
  	scanner, err := NewPointerScanner()
  	if err != nil {
  		return nil, err
  	}
  
  	pointers := make(chan *WrappedPointer, chanBufSize)
  	errchan := make(chan error, 10) // Multiple errors possible
  
  	go func() {
  		hasNext := true
  		for t := range treeblobs.Results {
  			hasNext = scanner.Scan(t.Sha1)
  
  			if p := scanner.Pointer(); p != nil {
  				p.Name = t.Filename
  				pointers <- p
  			}
  
  			if err := scanner.Err(); err != nil {
  				errchan <- err
  			}
  
  			if !hasNext {
  				break
  			}
  		}
  
  		// If the scanner quit early, we may still have treeblobs to
  		// read, so waiting for it to close will cause a deadlock.
  		if hasNext {
  			// Deal with nested error from incoming treeblobs
  			err := treeblobs.Wait()
  			if err != nil {
  				errchan <- err
  			}
  		}
  
  		if err = scanner.Close(); err != nil {
  			errchan <- err
  		}
  
  		close(pointers)
  		close(errchan)
  	}()
  
  	return NewPointerChannelWrapper(pointers, errchan), nil
  }
docs: // catFileBatchTree uses git cat-file --batch to get the object contents
  // of a git object, given its sha1. The contents will be decoded into
  // a Git LFS pointer. treeblobs is a channel over which blob entries
  // will be sent. It returns a channel from which point.Pointers can be read.