From 64095a2c8d5a3a72c55d7bd0737c5542a5aeee09 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 3 Jul 2025 22:38:37 +0300 Subject: feat: add SSH backup locations with --backup flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add support for SSH backup locations (e.g., paul@server:git/) - Backup locations are one-way only (push only, never pull) - Automatic bare repository creation on SSH servers - Add --backup flag to opt-in to backup syncing - Backup locations are disabled by default for offline resilience - Update version to 0.2.0 This allows users to maintain private backups on home servers that may be offline without affecting regular sync operations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- internal/sync/repository_setup.go | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'internal/sync/repository_setup.go') diff --git a/internal/sync/repository_setup.go b/internal/sync/repository_setup.go index 15d436e..3ebafbd 100644 --- a/internal/sync/repository_setup.go +++ b/internal/sync/repository_setup.go @@ -22,7 +22,21 @@ func (s *Syncer) setupNewRepository(repoPath string) error { return fmt.Errorf("no organizations configured") } - firstOrg := &s.config.Organizations[0] + // Find first non-backup organization to clone from + var firstOrg *config.Organization + var firstOrgIndex int + for i := range s.config.Organizations { + if !s.config.Organizations[i].BackupLocation { + firstOrg = &s.config.Organizations[i] + firstOrgIndex = i + break + } + } + + if firstOrg == nil { + return fmt.Errorf("no non-backup organizations configured to clone from") + } + if err := s.cloneRepository(firstOrg, repoPath); err != nil { return fmt.Errorf("failed to clone repository: %w", err) } @@ -35,8 +49,17 @@ func (s *Syncer) setupNewRepository(repoPath string) error { } // Add other organizations as remotes - for i := 1; i < len(s.config.Organizations); i++ { + for i := range s.config.Organizations { + if i == firstOrgIndex { + continue // Skip the first org we already cloned from + } org := &s.config.Organizations[i] + + // Skip backup locations if backup is not enabled + if org.BackupLocation && !s.backupEnabled { + continue + } + if err := s.addRemote(repoPath, org); err != nil { return fmt.Errorf("failed to add remote %s: %w", s.getRemoteName(org), err) } @@ -52,6 +75,12 @@ func (s *Syncer) setupExistingRepository(repoPath string) error { // Check and add any missing remotes for i := range s.config.Organizations { org := &s.config.Organizations[i] + + // Skip backup locations if backup is not enabled + if org.BackupLocation && !s.backupEnabled { + continue + } + remoteName := s.getRemoteName(org) // Check if remote exists @@ -86,6 +115,12 @@ func (s *Syncer) getRemotesMap() map[string]*config.Organization { remotes := make(map[string]*config.Organization) for i := range s.config.Organizations { org := &s.config.Organizations[i] + + // Skip backup locations if backup is not enabled + if org.BackupLocation && !s.backupEnabled { + continue + } + remoteName := s.getRemoteName(org) remotes[remoteName] = org } -- cgit v1.2.3