@@ -118,6 +118,7 @@ type repoSync struct {
118118 cmd string // the git command to run
119119 root absPath // absolute path to the root directory
120120 remoteRepo string // remote repo to sync
121+ localRepo absPath // absolute path to the local repo
121122 ref string // the ref to sync
122123 depth int // for shallow sync
123124 filter string // for partial clone
@@ -727,6 +728,7 @@ func main() {
727728 cmd : * flGitCmd ,
728729 root : absRoot ,
729730 remoteRepo : * flRepo ,
731+ localRepo : absRoot .Join (".repo" ),
730732 ref : * flRef ,
731733 depth : * flDepth ,
732734 filter : * flFilter ,
@@ -1252,40 +1254,37 @@ func (git *repoSync) initRepo(ctx context.Context) error {
12521254 needGitInit := false
12531255
12541256 // Check out the git root, and see if it is already usable.
1255- _ , err := os .Stat (git .root .String ())
1257+ _ , err := os .Stat (git .localRepo .String ())
12561258 switch {
12571259 case os .IsNotExist (err ):
12581260 // Probably the first sync. defaultDirMode ensures that this is usable
12591261 // as a volume when the consumer isn't running as the same UID.
1260- git .log .V (1 ).Info ("repo directory does not exist, creating it" , "path" , git .root )
1261- if err := os .MkdirAll (git .root .String (), defaultDirMode ); err != nil {
1262+ git .log .V (1 ).Info ("repo directory does not exist, creating it" , "path" , git .localRepo )
1263+ if err := os .MkdirAll (git .localRepo .String (), defaultDirMode ); err != nil {
12621264 return err
12631265 }
12641266 needGitInit = true
12651267 case err != nil :
12661268 return err
12671269 default :
12681270 // Make sure the directory we found is actually usable.
1269- git .log .V (3 ).Info ("repo directory exists" , "path" , git .root )
1271+ git .log .V (3 ).Info ("repo directory exists" , "path" , git .localRepo )
12701272 if git .sanityCheckRepo (ctx ) {
1271- git .log .V (4 ).Info ("repo directory is valid" , "path" , git .root )
1273+ git .log .V (4 ).Info ("repo directory is valid" , "path" , git .localRepo )
12721274 } else {
1273- // Maybe a previous run crashed? Git won't use this dir. We remove
1274- // the contents rather than the dir itself, because a common use-case
1275- // is to have a volume mounted at git.root, which makes removing it
1276- // impossible.
1277- git .log .V (0 ).Info ("repo directory was empty or failed checks" , "path" , git .root )
1278- if err := removeDirContents (git .root , git .log ); err != nil {
1279- return fmt .Errorf ("can't wipe unusable root directory: %w" , err )
1275+ // Maybe a previous run crashed? Git won't use this dir.
1276+ git .log .V (0 ).Info ("repo directory was empty or failed checks" , "path" , git .localRepo )
1277+ if err := os .RemoveAll (git .localRepo .String ()); err != nil {
1278+ return fmt .Errorf ("can't remove unusable repo directory: %w" , err )
12801279 }
12811280 needGitInit = true
12821281 }
12831282 }
12841283
12851284 if needGitInit {
12861285 // Running `git init` in an existing repo is safe (according to git docs).
1287- git .log .V (0 ).Info ("initializing repo directory" , "path" , git .root )
1288- if _ , _ , err := git .Run (ctx , git .root , "init" , "-b" , "git-sync" ); err != nil {
1286+ git .log .V (0 ).Info ("initializing repo directory" , "path" , git .localRepo )
1287+ if _ , _ , err := git .Run (ctx , git .localRepo , "init" , "-b" , "git-sync" ); err != nil {
12891288 return err
12901289 }
12911290 if ! git .sanityCheckRepo (ctx ) {
@@ -1295,17 +1294,17 @@ func (git *repoSync) initRepo(ctx context.Context) error {
12951294
12961295 // The "origin" remote has special meaning, like in relative-path
12971296 // submodules.
1298- if stdout , stderr , err := git .Run (ctx , git .root , "remote" , "get-url" , "origin" ); err != nil {
1297+ if stdout , stderr , err := git .Run (ctx , git .localRepo , "remote" , "get-url" , "origin" ); err != nil {
12991298 if ! strings .Contains (stderr , "No such remote" ) {
13001299 return err
13011300 }
13021301 // It doesn't exist - make it.
1303- if _ , _ , err := git .Run (ctx , git .root , "remote" , "add" , "origin" , git .remoteRepo ); err != nil {
1302+ if _ , _ , err := git .Run (ctx , git .localRepo , "remote" , "add" , "origin" , git .remoteRepo ); err != nil {
13041303 return err
13051304 }
13061305 } else if strings .TrimSpace (stdout ) != git .remoteRepo {
13071306 // It exists, but is wrong.
1308- if _ , _ , err := git .Run (ctx , git .root , "remote" , "set-url" , "origin" , git .remoteRepo ); err != nil {
1307+ if _ , _ , err := git .Run (ctx , git .localRepo , "remote" , "set-url" , "origin" , git .remoteRepo ); err != nil {
13091308 return err
13101309 }
13111310 }
@@ -1352,32 +1351,32 @@ func hasGitLockFile(gitRoot absPath) (string, error) {
13521351
13531352// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
13541353func (git * repoSync ) sanityCheckRepo (ctx context.Context ) bool {
1355- git .log .V (3 ).Info ("sanity-checking git repo" , "repo" , git .root )
1354+ git .log .V (3 ).Info ("sanity-checking git repo" , "repo" , git .localRepo )
13561355 // If it is empty, we are done.
1357- if empty , err := dirIsEmpty (git .root ); err != nil {
1358- git .log .Error (err , "can't list repo directory" , "path" , git .root )
1356+ if empty , err := dirIsEmpty (git .localRepo ); err != nil {
1357+ git .log .Error (err , "can't list repo directory" , "path" , git .localRepo )
13591358 return false
13601359 } else if empty {
1361- git .log .V (3 ).Info ("repo directory is empty" , "path" , git .root )
1360+ git .log .V (3 ).Info ("repo directory is empty" , "path" , git .localRepo )
13621361 return false
13631362 }
13641363
13651364 // Check that this is actually the root of the repo.
1366- if root , _ , err := git .Run (ctx , git .root , "rev-parse" , "--show-toplevel" ); err != nil {
1367- git .log .Error (err , "can't get repo toplevel" , "path" , git .root )
1365+ if root , _ , err := git .Run (ctx , git .localRepo , "rev-parse" , "--show-toplevel" ); err != nil {
1366+ git .log .Error (err , "can't get repo toplevel" , "path" , git .localRepo )
13681367 return false
13691368 } else {
13701369 root = strings .TrimSpace (root )
1371- if root != git .root .String () {
1372- git .log .Error (nil , "repo directory is under another repo" , "path" , git .root , "parent" , root )
1370+ if root != git .localRepo .String () {
1371+ git .log .Error (nil , "repo directory is under another repo" , "path" , git .localRepo , "parent" , root )
13731372 return false
13741373 }
13751374 }
13761375
13771376 // Consistency-check the repo. Don't use --verbose because it can be
13781377 // REALLY verbose.
1379- if _ , _ , err := git .Run (ctx , git .root , "fsck" , "--no-progress" , "--connectivity-only" ); err != nil {
1380- git .log .Error (err , "repo fsck failed" , "path" , git .root )
1378+ if _ , _ , err := git .Run (ctx , git .localRepo , "fsck" , "--no-progress" , "--connectivity-only" ); err != nil {
1379+ git .log .Error (err , "repo fsck failed" , "path" , git .localRepo )
13811380 return false
13821381 }
13831382
@@ -1399,7 +1398,7 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
13991398// files checked out - git could have died halfway through and the repo will
14001399// still pass this check.
14011400func (git * repoSync ) sanityCheckWorktree (ctx context.Context , worktree worktree ) bool {
1402- git .log .V (3 ).Info ("sanity-checking worktree" , "repo" , git .root , "worktree" , worktree )
1401+ git .log .V (3 ).Info ("sanity-checking worktree" , "repo" , git .localRepo , "worktree" , worktree )
14031402
14041403 // If it is empty, we are done.
14051404 if empty , err := dirIsEmpty (worktree .Path ()); err != nil {
@@ -1439,13 +1438,6 @@ func dirIsEmpty(dir absPath) (bool, error) {
14391438 return len (dirents ) == 0 , nil
14401439}
14411440
1442- // removeDirContents iterated the specified dir and removes all contents.
1443- func removeDirContents (dir absPath , log * logging.Logger ) error {
1444- return removeDirContentsIf (dir , log , func (fi os.FileInfo ) (bool , error ) {
1445- return true , nil
1446- })
1447- }
1448-
14491441func removeDirContentsIf (dir absPath , log * logging.Logger , fn func (fi os.FileInfo ) (bool , error )) error {
14501442 dirents , err := os .ReadDir (dir .String ())
14511443 if err != nil {
@@ -1529,7 +1521,7 @@ func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) erro
15291521 if err := os .RemoveAll (worktree .Path ().String ()); err != nil {
15301522 return fmt .Errorf ("error removing directory: %w" , err )
15311523 }
1532- if _ , _ , err := git .Run (ctx , git .root , "worktree" , "prune" , "--verbose" ); err != nil {
1524+ if _ , _ , err := git .Run (ctx , git .localRepo , "worktree" , "prune" , "--verbose" ); err != nil {
15331525 return err
15341526 }
15351527 return nil
@@ -1550,7 +1542,7 @@ func (git *repoSync) createWorktree(ctx context.Context, hash string) (worktree,
15501542 }
15511543
15521544 git .log .V (1 ).Info ("adding worktree" , "path" , worktree .Path (), "hash" , hash )
1553- _ , _ , err := git .Run (ctx , git .root , "worktree" , "add" , "--force" , "--detach" , worktree .Path ().String (), hash , "--no-checkout" )
1545+ _ , _ , err := git .Run (ctx , git .localRepo , "worktree" , "add" , "--force" , "--detach" , worktree .Path ().String (), hash , "--no-checkout" )
15541546 if err != nil {
15551547 return "" , err
15561548 }
@@ -1568,7 +1560,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
15681560 // using relative paths, so that other containers can use a different volume
15691561 // mount name.
15701562 var rootDotGit string
1571- if rel , err := filepath .Rel (worktree .Path ().String (), git .root .String ()); err != nil {
1563+ if rel , err := filepath .Rel (worktree .Path ().String (), git .localRepo .String ()); err != nil {
15721564 return err
15731565 } else {
15741566 rootDotGit = filepath .Join (rel , ".git" )
@@ -1580,7 +1572,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
15801572
15811573 // If sparse checkout is requested, configure git for it, otherwise
15821574 // unconfigure it.
1583- gitInfoPath := filepath .Join (git .root .String (), ".git/worktrees" , hash , "info" )
1575+ gitInfoPath := filepath .Join (git .localRepo .String (), ".git/worktrees" , hash , "info" )
15841576 gitSparseConfigPath := filepath .Join (gitInfoPath , "sparse-checkout" )
15851577 if git .sparseFile == "" {
15861578 os .RemoveAll (gitSparseConfigPath )
@@ -1661,13 +1653,13 @@ func (git *repoSync) cleanup(ctx context.Context) error {
16611653
16621654 // Let git know we don't need those old commits any more.
16631655 git .log .V (3 ).Info ("pruning worktrees" )
1664- if _ , _ , err := git .Run (ctx , git .root , "worktree" , "prune" , "--verbose" ); err != nil {
1656+ if _ , _ , err := git .Run (ctx , git .localRepo , "worktree" , "prune" , "--verbose" ); err != nil {
16651657 cleanupErrs = append (cleanupErrs , err )
16661658 }
16671659
16681660 // Expire old refs.
16691661 git .log .V (3 ).Info ("expiring unreachable refs" )
1670- if _ , _ , err := git .Run (ctx , git .root , "reflog" , "expire" , "--expire-unreachable=all" , "--all" ); err != nil {
1662+ if _ , _ , err := git .Run (ctx , git .localRepo , "reflog" , "expire" , "--expire-unreachable=all" , "--all" ); err != nil {
16711663 cleanupErrs = append (cleanupErrs , err )
16721664 }
16731665
@@ -1683,7 +1675,7 @@ func (git *repoSync) cleanup(ctx context.Context) error {
16831675 args = append (args , "--aggressive" )
16841676 }
16851677 git .log .V (3 ).Info ("running git garbage collection" )
1686- if _ , _ , err := git .Run (ctx , git .root , args ... ); err != nil {
1678+ if _ , _ , err := git .Run (ctx , git .localRepo , args ... ); err != nil {
16871679 cleanupErrs = append (cleanupErrs , err )
16881680 }
16891681 }
@@ -1786,7 +1778,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
17861778 // their underlying commit hashes, but has no effect if we fetched a
17871779 // branch, plain tag, or hash.
17881780 var remoteHash string
1789- if output , _ , err := git .Run (ctx , git .root , "rev-parse" , "FETCH_HEAD^{}" ); err != nil {
1781+ if output , _ , err := git .Run (ctx , git .localRepo , "rev-parse" , "FETCH_HEAD^{}" ); err != nil {
17901782 return false , "" , err
17911783 } else {
17921784 remoteHash = strings .Trim (output , "\n " )
@@ -1818,14 +1810,14 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
18181810 // Reset the repo (note: not the worktree - that happens later) to the new
18191811 // ref. This makes subsequent fetches much less expensive. It uses --soft
18201812 // so no files are checked out.
1821- if _ , _ , err := git .Run (ctx , git .root , "reset" , "--soft" , remoteHash , "--" ); err != nil {
1813+ if _ , _ , err := git .Run (ctx , git .localRepo , "reset" , "--soft" , remoteHash ); err != nil {
18221814 return false , "" , err
18231815 }
18241816
18251817 // If we have a new hash, make a new worktree
18261818 newWorktree := currentWorktree
18271819 if changed {
1828- // Create a worktree for this hash in git.root .
1820+ // Create a worktree for this hash.
18291821 if wt , err := git .createWorktree (ctx , remoteHash ); err != nil {
18301822 return false , "" , err
18311823 } else {
@@ -1901,15 +1893,15 @@ func (git *repoSync) fetch(ctx context.Context, ref string) error {
19011893 if git .filter != "" {
19021894 args = append (args , "--filter" , git .filter )
19031895 }
1904- if _ , _ , err := git .Run (ctx , git .root , args ... ); err != nil {
1896+ if _ , _ , err := git .Run (ctx , git .localRepo , args ... ); err != nil {
19051897 return err
19061898 }
19071899
19081900 return nil
19091901}
19101902
19111903func (git * repoSync ) isShallow (ctx context.Context ) (bool , error ) {
1912- boolStr , _ , err := git .Run (ctx , git .root , "rev-parse" , "--is-shallow-repository" )
1904+ boolStr , _ , err := git .Run (ctx , git .localRepo , "rev-parse" , "--is-shallow-repository" )
19131905 if err != nil {
19141906 return false , fmt .Errorf ("can't determine repo shallowness: %w" , err )
19151907 }
0 commit comments