agentsclimarketplace

Local sync

Skill getpipher/skills/skills/git-tools/skills/local-sync

Comprehensive git synchronization - fetch all remotes, update all branches, and ensure local repo matches remote completely (dual-remote aware)From its SKILL.md

Install
npx -y skills add getpipher/skills --skill local-sync

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.7 KB, ~3.3k tokens by cl100k_base, as published. Nobody here has run it

Bismillah! I'll perform a comprehensive synchronization of your local repository with all remote repositories to ensure nothing is left behind.

Arguments provided: $ARGUMENTS

Comprehensive Local-Remote Synchronization (Dual-Remote Aware)

This command ensures your local repository is completely synchronized with all remote repositories. Fully supports dual-remote setups (GitHub + GitLab) and multi-remote configurations.

Supported Arguments

  • --cleanup - Remove obsolete local branches (only if not on ANY remote)
  • --create-missing - Create local tracking branches for new remote branches
  • --force - Override local changes with remote versions
  • --prefer-remote <name> - Preferred remote for branch creation (default: origin)

Implementation Steps

Step 1: Pre-sync Repository Analysis & Remote Detection

echo "πŸ“Š **Repository Analysis**"
echo ""

# Check for uncommitted changes
if [[ -n $(git status --porcelain) ]]; then
    echo "⚠️  Warning: You have uncommitted changes:"
    git status --short
    echo ""
fi

# Detect all configured remotes
echo "πŸ”— **Configured Remotes:**"
remotes=($(git remote))
for remote in "${remotes[@]}"; do
    url=$(git remote get-url "$remote" 2>/dev/null)
    echo "  β”œβ”€ $remote β†’ $url"
done
echo ""

# Current branch info
current_branch=$(git branch --show-current)
echo "🌿 **Current Branch:** $current_branch"
echo ""

Step 2: Comprehensive Fetch from All Remotes

echo "πŸ”„ **Fetching from all remotes...**"
echo ""

fetch_failed=()
for remote in "${remotes[@]}"; do
    echo -n "  Fetching $remote... "
    if git fetch "$remote" --tags --prune 2>/dev/null; then
        echo "βœ“"
    else
        echo "βœ— (failed)"
        fetch_failed+=("$remote")
    fi
done

if [[ ${#fetch_failed[@]} -gt 0 ]]; then
    echo ""
    echo "⚠️  Failed to fetch from: ${fetch_failed[*]}"
fi
echo ""

Step 3: Current Branch Synchronization

echo "πŸ“₯ **Synchronizing current branch ($current_branch)...**"

# Check if current branch has upstream
if git rev-parse --verify @{upstream} >/dev/null 2>&1; then
    upstream=$(git rev-parse --abbrev-ref @{upstream})
    echo "  Upstream: $upstream"

    # Check ahead/behind status
    ahead=$(git rev-list --count @{upstream}..HEAD 2>/dev/null || echo 0)
    behind=$(git rev-list --count HEAD..@{upstream} 2>/dev/null || echo 0)

    if [[ $behind -gt 0 ]]; then
        echo "  Behind by $behind commit(s), pulling..."
        git pull --ff-only 2>/dev/null || {
            echo "  ⚠️  Fast-forward failed, attempting merge..."
            git pull --no-ff
        }
    else
        echo "  βœ“ Already up to date"
    fi

    if [[ $ahead -gt 0 ]]; then
        echo "  ⚠️  Ahead by $ahead commit(s) - consider pushing"
    fi
else
    echo "  ⚠️  No upstream tracking branch configured"
fi
echo ""

Step 4: Update All Local Tracking Branches

echo "πŸ”„ **Updating all local tracking branches...**"
echo ""

git for-each-ref --format='%(refname:short) %(upstream:short)' refs/heads | while read local upstream; do
    if [[ -n "$upstream" && "$local" != "$current_branch" ]]; then
        remote_name="${upstream%%/*}"

        # Check if upstream exists
        if git rev-parse --verify "$upstream" >/dev/null 2>&1; then
            local_sha=$(git rev-parse "$local")
            remote_sha=$(git rev-parse "$upstream")

            if [[ "$local_sha" != "$remote_sha" ]]; then
                # Check if can fast-forward
                if git merge-base --is-ancestor "$local" "$upstream" 2>/dev/null; then
                    echo -n "  Updating $local from $upstream... "
                    git update-ref "refs/heads/$local" "$remote_sha" && echo "βœ“" || echo "βœ—"
                else
                    echo "  ⚠️  $local has diverged from $upstream (manual merge needed)"
                fi
            fi
        fi
    fi
done
echo ""

Step 5: Discover Remote Branches Across All Remotes

echo "πŸ” **Discovering remote branches...**"
echo ""

declare -A branch_remotes  # branch_name -> "remote1,remote2"
declare -A new_branches    # branches not in local

# Collect all remote branches and which remotes have them
for remote in "${remotes[@]}"; do
    while read -r remote_branch; do
        [[ -z "$remote_branch" ]] && continue
        [[ "$remote_branch" == *"/HEAD" ]] && continue

        branch_name="${remote_branch#$remote/}"

        # Track which remotes have this branch
        if [[ -n "${branch_remotes[$branch_name]}" ]]; then
            branch_remotes[$branch_name]="${branch_remotes[$branch_name]},$remote"
        else
            branch_remotes[$branch_name]="$remote"
        fi

        # Check if local branch exists
        if ! git show-ref --verify --quiet "refs/heads/$branch_name"; then
            new_branches[$branch_name]="${branch_remotes[$branch_name]}"
        fi
    done < <(git branch -r --list "$remote/*" | sed 's/^[[:space:]]*//')
done

# Display new remote branches
if [[ ${#new_branches[@]} -gt 0 ]]; then
    echo "πŸ†• **New remote branches (not local):**"
    for branch in "${!new_branches[@]}"; do
        remotes_list="${new_branches[$branch]}"
        # Determine display label
        if [[ "$remotes_list" == *","* ]]; then
            echo "  β”œβ”€ $branch (on: $remotes_list)"
        else
            echo "  β”œβ”€ $branch ($remotes_list only)"
        fi
    done
    echo ""
else
    echo "  βœ“ No new remote branches found"
    echo ""
fi

Step 6: Create Missing Local Branches (if --create-missing)

if [[ "$ARGUMENTS" == *"--create-missing"* ]]; then
    echo "πŸ“ **Creating local tracking branches...**"

    # Determine preferred remote
    prefer_remote="origin"
    if [[ "$ARGUMENTS" =~ --prefer-remote[[:space:]]+([^[:space:]]+) ]]; then
        prefer_remote="${BASH_REMATCH[1]}"
    fi
    echo "  Preferred remote: $prefer_remote"
    echo ""

    for branch in "${!new_branches[@]}"; do
        remotes_list="${new_branches[$branch]}"

        # Select source remote (prefer specified, fallback to first available)
        if [[ "$remotes_list" == *"$prefer_remote"* ]]; then
            source_remote="$prefer_remote"
        else
            source_remote="${remotes_list%%,*}"
        fi

        echo -n "  Creating $branch from $source_remote/$branch... "
        if git branch --track "$branch" "$source_remote/$branch" 2>/dev/null; then
            echo "βœ“"
        else
            echo "βœ—"
        fi
    done
    echo ""
fi

Step 7: Smart Cleanup Obsolete Branches (if --cleanup)

Check if branch exists on ANY remote before considering it obsolete.

if [[ "$ARGUMENTS" == *"--cleanup"* ]]; then
    echo "πŸ—‘οΈ  **Checking for obsolete local branches...**"
    echo ""

    obsolete_branches=()

    git for-each-ref --format='%(refname:short)' refs/heads | while read local_branch; do
        # Skip current branch
        [[ "$local_branch" == "$current_branch" ]] && continue

        # Skip main/master/dev protected branches
        [[ "$local_branch" =~ ^(main|master|dev|develop)$ ]] && continue

        exists_on_remote=false

        # Check if branch exists on ANY remote
        for remote in "${remotes[@]}"; do
            if git ls-remote --heads "$remote" "$local_branch" 2>/dev/null | grep -q .; then
                exists_on_remote=true
                break
            fi
        done

        if [[ "$exists_on_remote" == false ]]; then
            # Double-check: does it have upstream that's gone?
            upstream=$(git rev-parse --abbrev-ref "$local_branch@{upstream}" 2>/dev/null)
            if [[ -n "$upstream" ]] || [[ -z "$(git log -1 --since='3 months ago' "$local_branch" 2>/dev/null)" ]]; then
                echo "  ⚠️  $local_branch - not on any remote"
                obsolete_branches+=("$local_branch")
            fi
        fi
    done

    if [[ ${#obsolete_branches[@]} -gt 0 ]]; then
        echo ""
        echo "Found ${#obsolete_branches[@]} obsolete branch(es)."

        if [[ "$ARGUMENTS" == *"--force"* ]]; then
            for branch in "${obsolete_branches[@]}"; do
                git branch -D "$branch" && echo "  Deleted: $branch"
            done
        else
            echo "Run with --force to auto-delete, or delete manually:"
            for branch in "${obsolete_branches[@]}"; do
                echo "  git branch -d $branch"
            done
        fi
    else
        echo "  βœ“ No obsolete branches found"
    fi
    echo ""
fi

Step 8: Comprehensive Multi-Remote Status Report

echo ""
echo "═══════════════════════════════════════════════════════════════"
echo "πŸ”„ **SYNCHRONIZATION COMPLETE**"
echo "═══════════════════════════════════════════════════════════════"
echo ""

# Remote status
echo "πŸ”— **Remotes Synchronized:**"
for remote in "${remotes[@]}"; do
    url=$(git remote get-url "$remote" 2>/dev/null)
    if [[ " ${fetch_failed[*]} " =~ " $remote " ]]; then
        echo "  β”œβ”€ $remote βœ— (fetch failed)"
    else
        echo "  β”œβ”€ $remote βœ“"
    fi
done
echo ""

# Branch status with ahead/behind for all tracking branches
echo "🌿 **Local Branches Status:**"
git for-each-ref --format='%(refname:short) %(upstream:short) %(upstream:track)' refs/heads | while read local upstream track; do
    if [[ -n "$upstream" ]]; then
        echo "  $local β†’ $upstream $track"
    else
        echo "  $local (no upstream)"
    fi
done
echo ""

# Summary of remote-only branches per remote
echo "🌐 **Remote-Only Branches:**"
for remote in "${remotes[@]}"; do
    count=0
    while read -r remote_branch; do
        [[ -z "$remote_branch" ]] && continue
        [[ "$remote_branch" == *"/HEAD" ]] && continue
        branch_name="${remote_branch#$remote/}"
        if ! git show-ref --verify --quiet "refs/heads/$branch_name"; then
            ((count++))
        fi
    done < <(git branch -r --list "$remote/*" | sed 's/^[[:space:]]*//')
    echo "  $remote: $count new branch(es)"
done
echo ""

# Recent activity
echo "πŸ“ˆ **Recent Activity (last 10 commits across all branches):**"
git log --oneline --graph --decorate --all -10
echo ""

# Sync summary
echo "βœ… **Sync Summary:**"
echo "  β€’ Remotes fetched: ${#remotes[@]} (failed: ${#fetch_failed[@]})"
echo "  β€’ Current branch: $current_branch"
echo "  β€’ Cleanup: $(if [[ "$ARGUMENTS" == *"--cleanup"* ]]; then echo "Yes"; else echo "No (use --cleanup)"; fi)"
echo "  β€’ Create missing: $(if [[ "$ARGUMENTS" == *"--create-missing"* ]]; then echo "Yes"; else echo "No (use --create-missing)"; fi)"
echo ""
echo "πŸš€ **Repository is now fully synchronized with all remotes!**"

Usage Examples

# Basic synchronization (all remotes)
/local-sync

# Sync and create local branches for all new remote branches
/local-sync --create-missing

# Sync and create branches, preferring gitlab as source
/local-sync --create-missing --prefer-remote gitlab

# Sync and clean up obsolete local branches (checks ALL remotes)
/local-sync --cleanup

# Complete sync with all options
/local-sync --create-missing --cleanup

# Force sync (override local changes, auto-delete obsolete)
/local-sync --force --cleanup

Dual-Remote Behavior

ScenarioBehavior
Branch on GitHub onlyShows as "(origin only)" or "(github only)"
Branch on GitLab onlyShows as "(gitlab only)"
Branch on bothShows as "(on: origin,gitlab)"
Local branch, gone from origin but exists on gitlabNOT deleted - still on a remote
Local branch, gone from ALL remotesMarked obsolete, safe to delete
--create-missingUses --prefer-remote or first available

Safety Features

  1. Multi-Remote Awareness: Never deletes branches that exist on ANY configured remote
  2. Protected Branches: Skips main/master/dev/develop from cleanup
  3. Uncommitted Changes Warning: Alerts before operations
  4. Fetch Failure Handling: Continues sync even if one remote fails
  5. Non-Destructive Default: Requires --force for auto-deletion
  6. Clear Reporting: Shows exactly which remote(s) have each branch

This command ensures your local repository stays completely synchronized with all remotes, respecting your dual-push GitHub + GitLab setup. InshaAllah, this will keep your development workflow smooth and up-to-date!

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 624,978. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.