func updateSymlink()

in cmd/git-sync/main.go [647:682]


func updateSymlink(ctx context.Context, gitRoot, link, newDir string) (string, error) {
	linkDir, linkFile := filepath.Split(link)

	// Make sure the link directory exists. We do this here, rather than at
	// startup because it might be under --root and that gets wiped in some
	// circumstances.
	if err := os.MkdirAll(filepath.Dir(linkDir), os.FileMode(int(0755))); err != nil {
		return "", fmt.Errorf("error making symlink dir: %v", err)
	}

	// Get currently-linked repo directory (to be removed), unless it doesn't exist
	oldWorktreePath, err := filepath.EvalSymlinks(link)
	if err != nil && !os.IsNotExist(err) {
		return "", fmt.Errorf("error accessing current worktree: %v", err)
	}

	// newDir is absolute, so we need to change it to a relative path.  This is
	// so it can be volume-mounted at another path and the symlink still works.
	newDirRelative, err := filepath.Rel(linkDir, newDir)
	if err != nil {
		return "", fmt.Errorf("error converting to relative path: %v", err)
	}

	const tmplink = "tmp-link"
	log.V(1).Info("creating tmp symlink", "root", linkDir, "dst", newDirRelative, "src", tmplink)
	if _, err := cmdRunner.Run(ctx, linkDir, "ln", "-snf", newDirRelative, tmplink); err != nil {
		return "", fmt.Errorf("error creating symlink: %v", err)
	}

	log.V(1).Info("renaming symlink", "root", linkDir, "old_name", tmplink, "new_name", linkFile)
	if _, err := cmdRunner.Run(ctx, linkDir, "mv", "-T", tmplink, linkFile); err != nil {
		return "", fmt.Errorf("error replacing symlink: %v", err)
	}

	return oldWorktreePath, nil
}