Support in-place updates from v3

A few small accomodations and we can clean up properly.
This commit is contained in:
Tim Hockin 2023-02-25 19:24:14 -08:00
parent 7eaba7605a
commit 12c1ece35f
3 changed files with 69 additions and 5 deletions

View File

@ -1554,6 +1554,8 @@ func (git *repoSync) cleanup(ctx context.Context, worktree worktree) error {
if err := removeDirContents(git.worktreeFor("").Path(), git.log, worktree.Hash()); err != nil { if err := removeDirContents(git.worktreeFor("").Path(), git.log, worktree.Hash()); err != nil {
cleanupErrs = append(cleanupErrs, err) cleanupErrs = append(cleanupErrs, err)
} }
// Let git know we don't need those old commits any more.
if _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil { if _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
cleanupErrs = append(cleanupErrs, err) cleanupErrs = append(cleanupErrs, err)
} }
@ -1678,6 +1680,9 @@ func (git *repoSync) currentWorktree() (worktree, error) {
if target == "" { if target == "" {
return "", nil return "", nil
} }
if filepath.IsAbs(target) {
return worktree(target), nil
}
return worktree(git.root.Join(target)), nil return worktree(git.root.Join(target)), nil
} }
@ -1736,12 +1741,17 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
currentHash = "" currentHash = ""
} }
} }
changed := (currentHash != remoteHash)
if changed || git.syncCount == 0 {
git.log.V(0).Info("update required", "ref", git.ref, "local", currentHash, "remote", remoteHash)
// We have to do at least one fetch, to ensure that parameters like depth // This catches in-place upgrades from older versions where the worktree
// are set properly. This is cheap when we already have the target hash. // path was different.
changed := (currentHash != remoteHash) || (currentWorktree != git.worktreeFor(currentHash))
// We have to do at least one fetch, to ensure that parameters like depth
// are set properly. This is cheap when we already have the target hash.
if changed || git.syncCount == 0 {
git.log.V(0).Info("update required", "ref", git.ref, "local", currentHash, "remote", remoteHash, "syncCount", git.syncCount)
// Parameters like depth are set at fetch time.
if err := git.fetch(ctx, remoteHash); err != nil { if err := git.fetch(ctx, remoteHash); err != nil {
return false, "", err return false, "", err
} }
@ -1785,6 +1795,11 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
git.syncCount++ git.syncCount++
// Clean up old worktree(s) and run GC. // Clean up old worktree(s) and run GC.
if currentWorktree != git.worktreeFor(currentHash) {
// The old worktree might have come from a prior version, and so
// not get caught by the normal cleanup.
os.RemoveAll(currentWorktree.Path().String())
}
if err := git.cleanup(ctx, newWorktree); err != nil { if err := git.cleanup(ctx, newWorktree); err != nil {
git.log.Error(err, "git cleanup failed", "newWorktree", newWorktree) git.log.Error(err, "git cleanup failed", "newWorktree", newWorktree)
} }

View File

@ -591,6 +591,50 @@ function e2e::worktree_cleanup() {
assert_file_absent "$ROOT/.worktrees/not_a_directory" assert_file_absent "$ROOT/.worktrees/not_a_directory"
} }
##############################################
# Test v3->v4 upgrade
##############################################
function e2e::v3_v4_upgrade_in_place() {
echo "$FUNCNAME 1" > "$REPO"/file
git -C "$REPO" commit -qam "$FUNCNAME"
# sync once
GIT_SYNC \
--one-time \
--repo="file://$REPO" \
--root="$ROOT" \
--link="link"
assert_link_exists "$ROOT"/link
assert_file_exists "$ROOT"/link/file
assert_file_eq "$ROOT"/link/file "$FUNCNAME 1"
# simulate v3's worktrees
WT="$(readlink "$ROOT/link")"
SHA="$(basename "$WT")"
mv -f "$ROOT/$WT" "$ROOT/$SHA"
ln -sf "$SHA" "$ROOT/link"
# make a second commit
echo "$FUNCNAME 2" > "$REPO"/file2
git -C "$REPO" add file2
git -C "$REPO" commit -qam "$FUNCNAME new file"
# sync again
GIT_SYNC \
--one-time \
--repo="file://$REPO" \
--root="$ROOT" \
--link="link"
assert_link_exists "$ROOT"/link
assert_file_exists "$ROOT"/link/file
assert_file_eq "$ROOT"/link/file "$FUNCNAME 1"
assert_file_exists "$ROOT"/link/file2
assert_file_eq "$ROOT"/link/file2 "$FUNCNAME 2"
assert_file_absent "$ROOT/$SHA"
}
############################################## ##############################################
# Test readlink # Test readlink
############################################## ##############################################

View File

@ -4,6 +4,11 @@ Git-sync v4 is a significant change from v3. It includes several flag changes
(though many of the old flags are kept for backwards compatibility), but more (though many of the old flags are kept for backwards compatibility), but more
importantly it fundamentally changes the way the internal sync-loop works. importantly it fundamentally changes the way the internal sync-loop works.
It should be possible to upgrade a synced repo (e.g. in a volume) from git-sync
v3 to git-sync v4, but appropriate caution should be used for critical
deployments. We have a test which covers this, but there are many degrees of
config which we simply can't predict.
## The v3 loop ## The v3 loop
The way git-sync v3.x works is sort of like how a human might work: The way git-sync v3.x works is sort of like how a human might work: