From 4830613701014ca6a93856d82fbf947da3bdcc78 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 9 Jun 2026 21:34:32 -0400 Subject: [PATCH] Add cross-machine sync tooling (clone/pull/push all module repos) repos.txt + sync-*.sh let any machine (Mac or Windows/Git Bash) hydrate all 49 module repos and keep them in sync via GitHub+gitea. Pulls are fast-forward only (never clobber local work); pushes send commits only and flag uncommitted repos. See SYNC.md for the two-machine workflow. Co-Authored-By: Claude Opus 4.8 (1M context) --- SYNC.md | 58 ++++++++++++++++++++++++++++++++++++++++++++ repos.txt | 52 +++++++++++++++++++++++++++++++++++++++ sync-clone-all.sh | 28 +++++++++++++++++++++ sync-pull-all.sh | 44 +++++++++++++++++++++++++++++++++ sync-push-all.sh | 36 +++++++++++++++++++++++++++ sync-refresh-list.sh | 23 ++++++++++++++++++ 6 files changed, 241 insertions(+) create mode 100644 SYNC.md create mode 100644 repos.txt create mode 100755 sync-clone-all.sh create mode 100755 sync-pull-all.sh create mode 100755 sync-push-all.sh create mode 100755 sync-refresh-list.sh diff --git a/SYNC.md b/SYNC.md new file mode 100644 index 00000000..aa583320 --- /dev/null +++ b/SYNC.md @@ -0,0 +1,58 @@ +# Syncing Odoo-Modules across machines (Mac + Windows) + +Each module/suite folder here is its **own git repo** (private on GitHub at +`gsinghpal/`, mirrored to gitea `admin/`). This parent folder is a +separate repo that holds the shared files (CLAUDE.md, docs, scripts, these sync +helpers). The cloud (GitHub) is the hub: both machines push to it and pull from it. + +Nothing here ever deletes your work. Pulls are fast-forward only, so local changes +are never overwritten; pushes only send commits. + +## First-time setup on a new machine (e.g. the Windows PC) + +1. Install **Git** (Git for Windows includes "Git Bash", which runs these scripts). +2. Sign in to GitHub once so git can push/pull: + - easiest: `gh auth login` (or let Git Credential Manager prompt on first pull) +3. Get everything: + ``` + git clone https://github.com/gsinghpal/Odoo-Modules.git + cd Odoo-Modules + bash sync-clone-all.sh + ``` + That clones the parent, then all 49 module repos into place. + +(gitea is an optional second mirror. The first push to it will ask for your +`git.nexasystems.ca` login. If you only use GitHub, those gitea lines just fail +quietly and GitHub stays the source of truth.) + +## Daily workflow (same on Mac and Windows) + +- **Before you start:** `bash sync-pull-all.sh` - pulls the latest for the parent + and every module. Anything with local changes or a diverged history is skipped and + listed, so you can handle it yourself. +- **Do your work**, then **commit inside the module(s) you changed**: + ``` + cd fusion_clock + git add -A + git commit -m "..." + cd .. + ``` +- **When done:** `bash sync-push-all.sh` - pushes every committed change to GitHub + + gitea, and flags any repo that still has uncommitted changes (so nothing is + silently left behind). + +## Golden rule for two machines + +Push from the machine you worked on **before** you switch to the other one, and run +`sync-pull-all.sh` on the other machine **before** you start. That keeps both in sync +and avoids diverged histories. + +## Helper scripts + +| Script | What it does | +|--------|--------------| +| `sync-clone-all.sh` | Clone any module repo listed in `repos.txt` that isn't here yet. | +| `sync-pull-all.sh` | Fast-forward pull the parent + all modules (safe, never clobbers). | +| `sync-push-all.sh` | Push committed work for the parent + all modules to GitHub + gitea. | +| `sync-refresh-list.sh` | Rebuild `repos.txt` from the repos present here (after adding/removing a module). | +| `repos.txt` | The list of module repo names the scripts act on. | diff --git a/repos.txt b/repos.txt new file mode 100644 index 00000000..e37ddca0 --- /dev/null +++ b/repos.txt @@ -0,0 +1,52 @@ +# Module repos that live as independent git repos inside this folder. +# Owner: github.com/gsinghpal/ + gitea git.nexasystems.ca/admin/ +# One repo name per line. Used by sync-*.sh. Regenerate with: bash sync-refresh-list.sh +disable_iap_calls +disable_odoo_online +disable_publisher_warranty +fusion_accounts +fusion_api +fusion_canada_post +fusion_centralize_billing +fusion_chatter_enhance +fusion_claims +fusion_clock +fusion_clock_ai +fusion_clover +fusion_digitize +fusion_faxes +fusion_helpdesk +fusion_helpdesk_central +fusion_inventory +fusion_loaners_management +fusion_login_audit +fusion_ltc_management +fusion_notes +fusion_odoo_fixes +fusion_payroll +fusion_pdf_preview +fusion_planning +fusion_portal +fusion_poynt +fusion_rental +fusion_repairs +fusion_reports_templates +fusion_ringcentral +fusion_schedule +fusion_service_charges +fusion_shipping +fusion_so_to_po +fusion_tasks +fusion_templates +fusion_theme_switcher +fusion_voip_ringcentral +fusion_whitelabels +network_logger +nexa_coa_setup +fusion_plating +fusion_accounting +fusion_iot +fusion_labels +fusion_projects +fusion-statements +fusion-woo-odoo diff --git a/sync-clone-all.sh b/sync-clone-all.sh new file mode 100755 index 00000000..03b1df25 --- /dev/null +++ b/sync-clone-all.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Clone every module repo listed in repos.txt into this folder. +# Run once on a new machine, right after you clone the parent Odoo-Modules repo. +# Adds both GitHub (origin) and gitea remotes. Never deletes or overwrites folders. +# +# Mac/Linux: bash sync-clone-all.sh +# Windows : open "Git Bash" here, then: bash sync-clone-all.sh +set -uo pipefail +cd "$(dirname "$0")" || exit 1 +GH="https://github.com/gsinghpal" +GITEA="https://git.nexasystems.ca/admin" +[ -f repos.txt ] || { echo "repos.txt not found next to this script"; exit 1; } + +cloned=0; skipped=0; failed=0 +while IFS= read -r f; do + case "$f" in ''|\#*) continue ;; esac + if [ -d "$f/.git" ]; then + echo "skip (already here): $f"; skipped=$((skipped+1)); continue + fi + if git clone -q "$GH/$f.git" "$f"; then + git -C "$f" remote add gitea "$GITEA/$f.git" 2>/dev/null || true + echo "cloned: $f"; cloned=$((cloned+1)) + else + echo "FAILED: $f"; failed=$((failed+1)) + fi +done < repos.txt +echo "----------------------------------------" +echo "cloned=$cloned skipped=$skipped failed=$failed" diff --git a/sync-pull-all.sh b/sync-pull-all.sh new file mode 100755 index 00000000..262dad49 --- /dev/null +++ b/sync-pull-all.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Pull the latest for the parent repo + every module repo. +# Fast-forward only: it NEVER overwrites or deletes your local work. If a repo has +# diverged or has conflicting local changes, it is skipped and reported so you can +# handle it by hand. Clones any module folder that is missing. +# Run this before you start working on a machine. +# +# bash sync-pull-all.sh +set -uo pipefail +cd "$(dirname "$0")" || exit 1 +GH="https://github.com/gsinghpal" +GITEA="https://git.nexasystems.ca/admin" + +pull_one() { + local d="$1" + local br; br=$(git -C "$d" symbolic-ref --short HEAD 2>/dev/null || echo main) + if git -C "$d" pull --ff-only -q origin "$br" 2>/dev/null; then + echo "updated: $d" + else + if [ -n "$(git -C "$d" status --porcelain --untracked-files=no)" ]; then + echo "SKIP (uncommitted changes block ff): $d -> commit, then re-run" + else + echo "SKIP (diverged, needs manual merge): $d" + fi + fi +} + +echo "== parent ==" +pull_one . +[ -f repos.txt ] || { echo "repos.txt not found"; exit 1; } +echo "== modules ==" +while IFS= read -r f; do + case "$f" in ''|\#*) continue ;; esac + if [ ! -d "$f/.git" ]; then + if git clone -q "$GH/$f.git" "$f"; then + git -C "$f" remote add gitea "$GITEA/$f.git" 2>/dev/null || true + echo "cloned (was missing): $f" + else + echo "FAILED clone: $f" + fi + continue + fi + pull_one "$f" +done < repos.txt diff --git a/sync-push-all.sh b/sync-push-all.sh new file mode 100755 index 00000000..e29cb70b --- /dev/null +++ b/sync-push-all.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Push your committed work for the parent + every module repo to BOTH GitHub +# (origin) and gitea. Only commits are pushed. Any repo that still has UNCOMMITTED +# changes is flagged, so you can see exactly what has not been synced yet. +# Run this after you finish working, once you have committed your changes. +# +# bash sync-push-all.sh +set -uo pipefail +cd "$(dirname "$0")" || exit 1 + +push_one() { + local d="$1" + local br; br=$(git -C "$d" symbolic-ref --short HEAD 2>/dev/null || echo main) + local flag="" + [ -n "$(git -C "$d" status --porcelain --untracked-files=no)" ] && flag=" [HAS UNCOMMITTED CHANGES - not pushed]" + local any=0 + for r in origin gitea; do + git -C "$d" remote get-url "$r" >/dev/null 2>&1 || continue + any=1 + if git -C "$d" push -q "$r" "$br" 2>/dev/null; then + echo "pushed: $d -> $r$flag" + else + echo "push FAILED (or nothing to push): $d -> $r$flag" + fi + done + [ "$any" = 0 ] && echo "no remotes: $d" +} + +echo "== parent ==" +push_one . +[ -f repos.txt ] || { echo "repos.txt not found"; exit 1; } +echo "== modules ==" +while IFS= read -r f; do + case "$f" in ''|\#*) continue ;; esac + if [ -d "$f/.git" ]; then push_one "$f"; else echo "skip (not cloned): $f"; fi +done < repos.txt diff --git a/sync-refresh-list.sh b/sync-refresh-list.sh new file mode 100755 index 00000000..fb504e1d --- /dev/null +++ b/sync-refresh-list.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Regenerate repos.txt from the actual module folders present here (any top-level +# folder that is its own git repo with a github.com/gsinghpal origin). Run this +# after you add or remove a module repo, then commit repos.txt so both machines +# pick up the change. +# +# bash sync-refresh-list.sh +set -uo pipefail +cd "$(dirname "$0")" || exit 1 + +{ + echo "# Module repos that live as independent git repos inside this folder." + echo "# Owner: github.com/gsinghpal/ + gitea git.nexasystems.ca/admin/" + echo "# One repo name per line. Used by sync-*.sh. Regenerate with: bash sync-refresh-list.sh" + for d in */; do + d="${d%/}" + [ -d "$d/.git" ] || continue + url=$(git -C "$d" remote get-url origin 2>/dev/null || true) + case "$url" in *github.com/gsinghpal/*) echo "$d" ;; esac + done +} > repos.txt.tmp && mv repos.txt.tmp repos.txt + +echo "repos.txt now lists $(grep -cvE '^\s*#|^\s*$' repos.txt) repos"