Skip to content

Commit 9afae6f

Browse files
committed
Merge branch 'master' into ttaylorr/prove
2 parents 0beae6a + d263a97 commit 9afae6f

16 files changed

+503
-87
lines changed

commands/command_migrate.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,31 @@ func includeExcludeRefs(l *tasklog.Logger, args []string) (include, exclude []st
173173
include = append(include, migrateIncludeRefs...)
174174
exclude = append(exclude, migrateExcludeRefs...)
175175
} else if migrateEverything {
176-
localRefs, err := git.LocalRefs()
176+
refs, err := git.AllRefsIn("")
177177
if err != nil {
178178
return nil, nil, err
179179
}
180180

181-
for _, ref := range localRefs {
182-
include = append(include, ref.Refspec())
181+
for _, ref := range refs {
182+
switch ref.Type {
183+
case git.RefTypeLocalBranch, git.RefTypeLocalTag,
184+
git.RefTypeRemoteBranch, git.RefTypeRemoteTag:
185+
186+
include = append(include, ref.Refspec())
187+
case git.RefTypeOther:
188+
parts := strings.SplitN(ref.Refspec(), "/", 3)
189+
if len(parts) < 2 {
190+
continue
191+
}
192+
193+
switch parts[1] {
194+
// The following are GitLab-, GitHub-, VSTS-,
195+
// and BitBucket-specific reference naming
196+
// conventions.
197+
case "merge-requests", "pull", "pull-requests":
198+
include = append(include, ref.Refspec())
199+
}
200+
}
183201
}
184202
} else {
185203
bare, err := git.IsBare()

config/config.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ func (c *Configuration) LocalGitStorageDir() string {
311311
return c.Filesystem().GitStorageDir
312312
}
313313

314-
func (c *Configuration) LocalReferenceDir() string {
315-
return c.Filesystem().ReferenceDir
314+
func (c *Configuration) LocalReferenceDirs() []string {
315+
return c.Filesystem().ReferenceDirs
316316
}
317317

318318
func (c *Configuration) LFSStorageDir() string {
@@ -346,7 +346,12 @@ func (c *Configuration) Filesystem() *fs.Filesystem {
346346

347347
if c.fs == nil {
348348
lfsdir, _ := c.Git.Get("lfs.storage")
349-
c.fs = fs.New(c.LocalGitDir(), c.LocalWorkingDir(), lfsdir)
349+
c.fs = fs.New(
350+
c.Os,
351+
c.LocalGitDir(),
352+
c.LocalWorkingDir(),
353+
lfsdir,
354+
)
350355
}
351356

352357
return c.fs

config/git_fetcher.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func keyIsUnsafe(key string) bool {
158158
}
159159

160160
var safeKeys = []string{
161+
"lfs.allowincompletepush",
161162
"lfs.fetchexclude",
162163
"lfs.fetchinclude",
163164
"lfs.gitprotocol",

docs/man/git-lfs-migrate.1.ronn

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ The following configuration:
190190

191191
Would, therefore, include commits: F, E, D, C, B, but exclude commit A.
192192

193-
The presence of flag `--everything` indicates that all local references should be
194-
migrated.
193+
The presence of flag `--everything` indicates that all local and remote
194+
references should be migrated.
195195

196196
## EXAMPLES
197197

@@ -253,16 +253,20 @@ Note: This will require a force push to any existing Git remotes.
253253

254254
### Migrate without rewriting local history
255255

256-
You can also migrate files without modifying the existing history of your respoitory:
256+
You can also migrate files without modifying the existing history of your
257+
repository:
257258

258259
Without a specified commit message:
260+
259261
```
260-
git lfs migrate import --no-rewrite test.zip *.mp3 *.psd
262+
$ git lfs migrate import --no-rewrite test.zip *.mp3 *.psd
261263
```
264+
262265
With a specified commit message:
266+
263267
```
264-
git lfs migrate import --no-rewrite -m "Import .zip, .mp3, .psd files" \
265-
test.zip *.mpd *.psd
268+
$ git lfs migrate import --no-rewrite -m "Import .zip, .mp3, .psd files" \
269+
test.zip *.mpd *.psd
266270
```
267271

268272
## SEE ALSO

fs/fs.go

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fs
22

33
import (
4+
"bufio"
45
"bytes"
56
"fmt"
67
"io/ioutil"
@@ -12,20 +13,29 @@ import (
1213
"sync"
1314

1415
"github.com/git-lfs/git-lfs/tools"
16+
"github.com/rubyist/tracerx"
1517
)
1618

1719
var oidRE = regexp.MustCompile(`\A[[:alnum:]]{64}`)
1820

21+
// Environment is a copy of a subset of the interface
22+
// github.com/git-lfs/git-lfs/config.Environment.
23+
//
24+
// For more information, see config/environment.go.
25+
type Environment interface {
26+
Get(key string) (val string, ok bool)
27+
}
28+
1929
// Object represents a locally stored LFS object.
2030
type Object struct {
2131
Oid string
2232
Size int64
2333
}
2434

2535
type Filesystem struct {
26-
GitStorageDir string // parent of objects/lfs (may be same as GitDir but may not)
27-
LFSStorageDir string // parent of lfs objects and tmp dirs. Default: ".git/lfs"
28-
ReferenceDir string // alternative local media dir (relative to clone reference repo)
36+
GitStorageDir string // parent of objects/lfs (may be same as GitDir but may not)
37+
LFSStorageDir string // parent of lfs objects and tmp dirs. Default: ".git/lfs"
38+
ReferenceDirs []string // alternative local media dirs (relative to clone reference repo)
2939
lfsobjdir string
3040
tmpdir string
3141
logdir string
@@ -105,12 +115,16 @@ func (f *Filesystem) localObjectDir(oid string) string {
105115
return filepath.Join(f.LFSObjectDir(), oid[0:2], oid[2:4])
106116
}
107117

108-
func (f *Filesystem) ObjectReferencePath(oid string) string {
109-
if len(f.ReferenceDir) == 0 {
110-
return f.ReferenceDir
118+
func (f *Filesystem) ObjectReferencePaths(oid string) []string {
119+
if len(f.ReferenceDirs) == 0 {
120+
return nil
111121
}
112122

113-
return filepath.Join(f.ReferenceDir, oid[0:2], oid[2:4], oid)
123+
var paths []string
124+
for _, ref := range f.ReferenceDirs {
125+
paths = append(paths, filepath.Join(ref, oid[0:2], oid[2:4], oid))
126+
}
127+
return paths
114128
}
115129

116130
func (f *Filesystem) LFSObjectDir() string {
@@ -159,12 +173,12 @@ func (f *Filesystem) Cleanup() error {
159173
// New initializes a new *Filesystem with the given directories. gitdir is the
160174
// path to the bare repo, workdir is the path to the repository working
161175
// directory, and lfsdir is the optional path to the `.git/lfs` directory.
162-
func New(gitdir, workdir, lfsdir string) *Filesystem {
176+
func New(env Environment, gitdir, workdir, lfsdir string) *Filesystem {
163177
fs := &Filesystem{
164178
GitStorageDir: resolveGitStorageDir(gitdir),
165179
}
166180

167-
fs.ReferenceDir = resolveReferenceDir(fs.GitStorageDir)
181+
fs.ReferenceDirs = resolveReferenceDirs(env, fs.GitStorageDir)
168182

169183
if len(lfsdir) == 0 {
170184
lfsdir = "lfs"
@@ -179,19 +193,75 @@ func New(gitdir, workdir, lfsdir string) *Filesystem {
179193
return fs
180194
}
181195

182-
func resolveReferenceDir(gitStorageDir string) string {
196+
func resolveReferenceDirs(env Environment, gitStorageDir string) []string {
197+
var references []string
198+
199+
envAlternates, ok := env.Get("GIT_ALTERNATE_OBJECT_DIRECTORIES")
200+
if ok {
201+
splits := strings.Split(envAlternates, string(os.PathListSeparator))
202+
for _, split := range splits {
203+
if dir, ok := existsAlternate(split); ok {
204+
references = append(references, dir)
205+
}
206+
}
207+
}
208+
183209
cloneReferencePath := filepath.Join(gitStorageDir, "objects", "info", "alternates")
184210
if tools.FileExists(cloneReferencePath) {
185-
buffer, err := ioutil.ReadFile(cloneReferencePath)
186-
if err == nil {
187-
path := strings.TrimSpace(string(buffer[:]))
188-
referenceLfsStoragePath := filepath.Join(filepath.Dir(path), "lfs", "objects")
189-
if tools.DirExists(referenceLfsStoragePath) {
190-
return referenceLfsStoragePath
211+
f, err := os.Open(cloneReferencePath)
212+
if err != nil {
213+
tracerx.Printf("could not open %s: %s",
214+
cloneReferencePath, err)
215+
return nil
216+
}
217+
defer f.Close()
218+
219+
scanner := bufio.NewScanner(f)
220+
for scanner.Scan() {
221+
text := strings.TrimSpace(scanner.Text())
222+
if len(text) == 0 || strings.HasPrefix(text, "#") {
223+
continue
191224
}
225+
226+
if dir, ok := existsAlternate(text); ok {
227+
references = append(references, dir)
228+
}
229+
}
230+
231+
if err := scanner.Err(); err != nil {
232+
tracerx.Printf("could not scan %s: %s",
233+
cloneReferencePath, err)
234+
}
235+
}
236+
return references
237+
}
238+
239+
// existsAlternate takes an object directory given in "objs" (read as a single,
240+
// line from .git/objects/info/alternates). If that is a satisfiable alternates
241+
// directory (i.e., it exists), the directory is returned along with "true". If
242+
// not, the empty string and false is returned instead.
243+
func existsAlternate(objs string) (string, bool) {
244+
objs = strings.TrimSpace(objs)
245+
if strings.HasPrefix(objs, "\"") {
246+
var err error
247+
248+
unquote := strings.LastIndex(objs, "\"")
249+
if unquote == 0 {
250+
return "", false
192251
}
252+
253+
objs, err = strconv.Unquote(objs[:unquote+1])
254+
if err != nil {
255+
return "", false
256+
}
257+
}
258+
259+
storage := filepath.Join(filepath.Dir(objs), "lfs", "objects")
260+
261+
if tools.DirExists(storage) {
262+
return storage, true
193263
}
194-
return ""
264+
return "", false
195265
}
196266

197267
// From a git dir, get the location that objects are to be stored (we will store lfs alongside)

lfs/gitfilter_smudge.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ import (
1616

1717
func (f *GitFilter) SmudgeToFile(filename string, ptr *Pointer, download bool, manifest *tq.Manifest, cb tools.CopyCallback) error {
1818
os.MkdirAll(filepath.Dir(filename), 0755)
19+
20+
if stat, _ := os.Stat(filename); stat != nil && stat.Mode()&0200 == 0 {
21+
if err := os.Chmod(filename, stat.Mode()|0200); err != nil {
22+
return errors.Wrap(err,
23+
"Could not restore write permission")
24+
}
25+
26+
// When we're done, return the file back to its normal
27+
// permission bits.
28+
defer os.Chmod(filename, stat.Mode())
29+
}
30+
1931
file, err := os.Create(filename)
2032
if err != nil {
2133
return fmt.Errorf("Could not create working directory file: %v", err)

lfs/lfs.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ func Environ(cfg *config.Configuration, manifest *tq.Manifest) []string {
3535

3636
fetchPruneConfig := NewFetchPruneConfig(cfg.Git)
3737

38+
references := strings.Join(cfg.LocalReferenceDirs(), ", ")
39+
3840
env = append(env,
3941
fmt.Sprintf("LocalWorkingDir=%s", cfg.LocalWorkingDir()),
4042
fmt.Sprintf("LocalGitDir=%s", cfg.LocalGitDir()),
4143
fmt.Sprintf("LocalGitStorageDir=%s", cfg.LocalGitStorageDir()),
4244
fmt.Sprintf("LocalMediaDir=%s", cfg.LFSObjectDir()),
43-
fmt.Sprintf("LocalReferenceDir=%s", cfg.LocalReferenceDir()),
45+
fmt.Sprintf("LocalReferenceDirs=%s", references),
4446
fmt.Sprintf("TempDir=%s", cfg.TempDir()),
4547
fmt.Sprintf("ConcurrentTransfers=%d", api.ConcurrentTransfers),
4648
fmt.Sprintf("TusTransfers=%v", cfg.TusTransfersAllowed()),
@@ -98,13 +100,19 @@ func LinkOrCopyFromReference(cfg *config.Configuration, oid string, size int64)
98100
if cfg.LFSObjectExists(oid, size) {
99101
return nil
100102
}
101-
altMediafile := cfg.Filesystem().ObjectReferencePath(oid)
103+
altMediafiles := cfg.Filesystem().ObjectReferencePaths(oid)
102104
mediafile, err := cfg.Filesystem().ObjectPath(oid)
103105
if err != nil {
104106
return err
105107
}
106-
if altMediafile != "" && tools.FileExistsOfSize(altMediafile, size) {
107-
return LinkOrCopy(cfg, altMediafile, mediafile)
108+
for _, altMediafile := range altMediafiles {
109+
tracerx.Printf("altMediafile: %s", altMediafile)
110+
if altMediafile != "" && tools.FileExistsOfSize(altMediafile, size) {
111+
err = LinkOrCopy(cfg, altMediafile, mediafile)
112+
if err == nil {
113+
break
114+
}
115+
}
108116
}
109-
return nil
117+
return err
110118
}

0 commit comments

Comments
 (0)