Skip to content

Commit ad20334

Browse files
committed
Fix migrations where .git/objects is a symlink
Android's `repo` tool creates `.git/objects` as a symlink to a place outside the `.git` directory for unknown reasons. When that happens, Git operations where we set the working directory to that directory fail. This is because when Git performs discovery on the working directory, it first canonicalizes the path, which takes it outside of the `.git` directory and it then fails to find anything that looks like a Git repository. In our codebase, we set the path to the object directory root in a couple of places which cause this problem. To avoid this problem, simply join the repository root with `..`, which is always applied before canonicalization and will result in the path being properly set to the `.git` directory, which results in `git lfs migrate import` working correctly in this configuration.
1 parent 9b9bccb commit ad20334

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

git/githistory/rewriter.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/hex"
55
"fmt"
66
"os"
7+
"path/filepath"
78
"strings"
89
"sync"
910

@@ -313,7 +314,7 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
313314
return nil, errors.Wrap(err, tr.Tr.Get("could not find refs to update"))
314315
}
315316

316-
root, _ := r.db.Root()
317+
root, _ := r.gitDirectory()
317318

318319
updater := &refUpdater{
319320
cacheFn: r.uncacheCommit,
@@ -436,6 +437,15 @@ func copyEntryMode(e *gitobj.TreeEntry, mode int32) *gitobj.TreeEntry {
436437
return copied
437438
}
438439

440+
// gitDirectory returns a path to the .git directory on success.
441+
func (r *Rewriter) gitDirectory() (string, bool) {
442+
root, ok := r.db.Root()
443+
if ok {
444+
root = filepath.Join(root, "..")
445+
}
446+
return root, ok
447+
}
448+
439449
func (r *Rewriter) allows(typ gitobj.ObjectType, abs string) bool {
440450
switch typ {
441451
case gitobj.BlobObjectType:
@@ -529,7 +539,7 @@ func (r *Rewriter) refsToMigrate() ([]*git.Ref, error) {
529539
var refs []*git.Ref
530540
var err error
531541

532-
if root, ok := r.db.Root(); ok {
542+
if root, ok := r.gitDirectory(); ok {
533543
refs, err = git.AllRefsIn(root)
534544
} else {
535545
refs, err = git.AllRefs()
@@ -568,7 +578,7 @@ func (r *Rewriter) scannerOpts() *git.ScanRefsOptions {
568578
Names: make(map[string]string),
569579
}
570580

571-
if root, ok := r.db.Root(); ok {
581+
if root, ok := r.gitDirectory(); ok {
572582
opts.WorkingDir = root
573583
}
574584
return opts

t/t-migrate-import.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,31 @@ begin_test "migrate import (given branch with filter)"
142142
)
143143
end_test
144144

145+
begin_test "migrate import (.git objects/symlink)"
146+
(
147+
set -e
148+
mkdir other
149+
150+
setup_multiple_local_branches
151+
152+
mv .git/objects ../other/
153+
ln -s ../../other/objects .git/objects
154+
155+
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
156+
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
157+
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
158+
159+
git lfs migrate import
160+
161+
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
162+
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
163+
164+
assert_local_object "$md_oid" "140"
165+
assert_local_object "$txt_oid" "120"
166+
refute_local_object "$md_feature_oid" "30"
167+
)
168+
end_test
169+
145170
begin_test "migrate import (default branch, exclude remote refs)"
146171
(
147172
set -e

0 commit comments

Comments
 (0)