Git Remotes

Remote repository management and collaboration.

Remote Fundamentals

# LIST REMOTES
git remote                               # Names only
git remote -v                            # With URLs
git remote show origin                   # Detailed info

# ADD REMOTE
git remote add origin git@github.com:user/repo.git
git remote add upstream git@github.com:original/repo.git
git remote add gitlab git@gitlab.com:user/repo.git

# CHANGE REMOTE URL
git remote set-url origin git@github.com:newuser/repo.git
git remote set-url --push origin git@other-host.com:user/repo.git  # Push to different URL

# RENAME REMOTE
git remote rename origin old-origin
git remote rename gitlab origin

# REMOVE REMOTE
git remote remove gitlab
git remote rm gitlab                     # Short form

# REMOTE CONVENTIONS
# origin   = your fork or primary remote
# upstream = original repo you forked from
# gitlab   = mirror on GitLab
# backup   = backup location

# SHOW REMOTE DETAILS
git remote show origin
# Shows:
# - Fetch/push URLs
# - HEAD branch
# - Remote branches
# - Local branches tracking remote
# - Stale branches

Fetch Patterns

# BASIC FETCH
git fetch                                # Fetch from origin
git fetch origin                         # Same, explicit
git fetch --all                          # Fetch from ALL remotes

# FETCH SPECIFIC
git fetch origin main                    # Only main branch
git fetch origin feature                 # Specific branch
git fetch origin refs/pull/123/head:pr-123  # GitHub PR

# FETCH WITH PRUNE
git fetch --prune                        # Remove stale remote-tracking branches
git fetch -p                             # Short form
git fetch --prune-tags                   # Also prune tags

# FETCH TAGS
git fetch --tags                         # Fetch all tags
git fetch origin --tags                  # Tags from specific remote

# FETCH DRY RUN
git fetch --dry-run                      # Show what would be fetched

# FETCH VS PULL
# fetch: download changes, don't merge
# pull:  fetch + merge (or rebase)
# PREFER fetch + manual merge for control

# AFTER FETCH
git log origin/main..HEAD                # Your commits not on remote
git log HEAD..origin/main                # Remote commits you don't have
git diff origin/main                     # Your changes vs remote

# CONFIGURE FETCH DEFAULTS
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
# Fetch all branches by default

Pull Patterns

# BASIC PULL
git pull                                 # Pull from tracking branch
git pull origin main                     # Pull specific branch

# PULL WITH REBASE
git pull --rebase                        # Rebase instead of merge
git pull --rebase=merges                 # Preserve local merges
git pull -r                              # Short for --rebase

# MAKE REBASE DEFAULT
git config pull.rebase true              # For this repo
git config --global pull.rebase true     # Global default

# PULL STRATEGIES
git pull --ff-only                       # Only if fast-forward possible
git pull --no-ff                         # Always create merge commit

# PULL SPECIFIC BRANCH
git pull origin feature                  # Pull feature into current
git pull origin feature:local-feature    # Pull into specific local branch

# PULL ALL REMOTES
git pull --all                           # Pull from all remotes

# HANDLE PULL CONFLICTS
git pull
# CONFLICT...
# Fix conflicts, then:
git add resolved-files
git commit                               # Complete merge

# OR if rebasing:
git pull --rebase
# CONFLICT...
git add resolved-files
git rebase --continue

# SAFE PULL WORKFLOW
git fetch origin
git log HEAD..origin/main                # Review incoming changes
git merge origin/main                    # Controlled merge
# OR: git rebase origin/main
To reset your local branch to exactly match the remote (discard all local changes), see Rewriting: Reset Operations — git fetch origin && git reset --hard origin/main.

Push Patterns

# BASIC PUSH
git push                                 # Push to tracking branch
git push origin main                     # Push main to origin

# PUSH WITH UPSTREAM
git push -u origin main                  # Push and set upstream
git push --set-upstream origin main      # Same, verbose
# After this, just "git push" works

# PUSH ALL BRANCHES
git push --all                           # All local branches
git push origin --all                    # To specific remote

# PUSH TAGS
git push --tags                          # All tags
git push origin v1.0.0                   # Specific tag
git push --follow-tags                   # Push commits + related tags

# DELETE REMOTE BRANCH
git push origin --delete feature         # Delete remote branch
git push origin :feature                 # Same, older syntax

# FORCE PUSH (careful!)
git push --force                         # Overwrite remote (DANGEROUS)
git push --force-with-lease              # Safe force (fails if remote changed)
# ALWAYS use --force-with-lease over --force

# PUSH SPECIFIC COMMIT
git push origin abc1234:main             # Push commit to remote branch

# PUSH TO DIFFERENT BRANCH
git push origin local-branch:remote-branch

# DRY RUN
git push --dry-run                       # Show what would be pushed
git push -n                              # Short form

# PUSH ALL REMOTES
for remote in $(git remote); do
  git push "$remote" main
done

Multi-Remote Workflows

# SETUP MULTI-REMOTE
git remote add origin git@github.com:EvanusModestus/repo.git
git remote add gitlab git@gitlab.com:EvanusModestus/repo.git
git remote add backup git@backup-server.com:repo.git

# VIEW ALL REMOTES
git remote -v
# origin  git@github.com:EvanusModestus/repo.git (fetch)
# origin  git@github.com:EvanusModestus/repo.git (push)
# gitlab  git@gitlab.com:EvanusModestus/repo.git (fetch)
# gitlab  git@gitlab.com:EvanusModestus/repo.git (push)

# PUSH TO ALL REMOTES
git push origin main
git push gitlab main
# OR:
for remote in origin gitlab backup; do
  git push "$remote" main
done

# CONFIGURE PUSH TO MULTIPLE URLS
# Add multiple push URLs to single remote:
git remote set-url --add --push origin git@github.com:user/repo.git
git remote set-url --add --push origin git@gitlab.com:user/repo.git
# Now "git push origin" pushes to both!

# FETCH FROM ALL
git fetch --all                          # All remotes
git remote update                        # Same

# COMPARE REMOTES
git log origin/main..gitlab/main --oneline
# Commits on GitLab not on GitHub

# FORK WORKFLOW (upstream)
git remote add upstream git@github.com:original/repo.git
git fetch upstream
git merge upstream/main                  # Get changes from original
git push origin main                     # Push to your fork

# KEEP FORK IN SYNC
git fetch upstream
git checkout main
git rebase upstream/main
git push origin main

# DIFFERENT FETCH/PUSH REMOTES
git remote set-url origin git@github.com:upstream/repo.git         # Fetch from upstream
git remote set-url --push origin git@github.com:myfork/repo.git    # Push to fork

Infrastructure Repository Remotes

# DOMUS-* REPO REMOTE SETUP
# Most repos push to both GitHub and GitLab

# VIEW REMOTES FOR REPO
git -C ~/atelier/_bibliotheca/domus-infra-ops remote -v
# origin	git@github.com:EvanusModestus/domus-infra-ops.git (fetch)
# origin	git@github.com:EvanusModestus/domus-infra-ops.git (push)
# gitlab	git@gitlab.com:EvanusModestus/domus-infra-ops.git (fetch)
# gitlab	git@gitlab.com:EvanusModestus/domus-infra-ops.git (push)

# PUSH TO ALL REMOTES (single repo)
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push origin main
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push gitlab main

# PUSH ALL DOMUS-* REPOS TO ALL REMOTES
for repo in ~/atelier/_bibliotheca/domus-*/; do
  name=$(basename "$repo")
  echo "=== $name ==="
  for remote in origin gitlab; do
    SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket \
      git -C "$repo" push "$remote" main 2>/dev/null || echo "  $remote: skipped/failed"
  done
done

# CHECK SYNC STATUS ACROSS REMOTES
for repo in domus-infra-ops domus-captures domus-ise-linux; do
  echo "=== $repo ==="
  git -C ~/atelier/_bibliotheca/$repo fetch --all -q
  origin=$(git -C ~/atelier/_bibliotheca/$repo rev-parse origin/main)
  gitlab=$(git -C ~/atelier/_bibliotheca/$repo rev-parse gitlab/main 2>/dev/null || echo "N/A")
  local=$(git -C ~/atelier/_bibliotheca/$repo rev-parse main)
  echo "  local:  ${local:0:7}"
  echo "  origin: ${origin:0:7}"
  echo "  gitlab: ${gitlab:0:7}"
done

# ADD REMOTE TO EXISTING REPO
cd ~/atelier/_bibliotheca/domus-new-repo
git remote add origin git@github.com:EvanusModestus/domus-new-repo.git
git remote add gitlab git@gitlab.com:EvanusModestus/domus-new-repo.git
git push -u origin main
git push -u gitlab main

# PRUNE STALE REMOTES ACROSS REPOS
for repo in ~/atelier/_bibliotheca/domus-*/; do
  git -C "$repo" fetch --all --prune
done

# VERIFY SSH AUTH BEFORE PUSH
ssh -T git@github.com                    # Test GitHub
ssh -T git@gitlab.com                    # Test GitLab

SSH Remote Configuration

# SSH VS HTTPS
# SSH:   git@github.com:user/repo.git
# HTTPS: https://github.com/user/repo.git

# CONVERT HTTPS TO SSH
git remote set-url origin git@github.com:user/repo.git

# CONVERT SSH TO HTTPS
git remote set-url origin https://github.com/user/repo.git

# SSH CONFIG FOR MULTIPLE GITHUB ACCOUNTS
# ~/.ssh/config:
# Host github-personal
#     HostName github.com
#     User git
#     IdentityFile ~/.ssh/id_ed25519_personal
#
# Host github-work
#     HostName github.com
#     User git
#     IdentityFile ~/.ssh/id_ed25519_work

# USE WITH REMOTES
git remote add personal git@github-personal:personal-user/repo.git
git remote add work git@github-work:work-org/repo.git

# VAULT SSH CA INTEGRATION
# Sign certificate before pushing:
~/.local/bin/vault-ssh-sign
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push origin main

# TEST SSH CONNECTION
ssh -vT git@github.com                   # Verbose test
ssh -T git@gitlab.com                    # GitLab test

# SPECIFY SSH KEY FOR GIT
GIT_SSH_COMMAND="ssh -i ~/.ssh/specific_key" git push

# SSH AGENT FORWARDING
# For push from remote servers
ssh -A server                            # Forward agent
git push origin main                     # Uses forwarded key

Remote Gotchas

# WRONG: Pushing without upstream
git push
# Error: no upstream branch

# CORRECT: Set upstream first
git push -u origin main
# Future pushes: just "git push"

# WRONG: Force pushing shared branches
git push --force origin main
# Overwrites others' work!

# CORRECT: Use --force-with-lease or don't force
git push --force-with-lease origin main
# OR don't force push main at all

# WRONG: Pulling with dirty working tree
git pull
# Error: Your local changes would be overwritten

# CORRECT: Stash or commit first
git stash
git pull
git stash pop

# WRONG: Fetching but not pruning
git fetch
# Stale branches accumulate forever

# CORRECT: Fetch with prune
git fetch --prune
# OR configure: git config remote.origin.prune true

# WRONG: Assuming origin is always correct
git push origin main
# origin could point anywhere!

# CORRECT: Verify remotes
git remote -v
git remote show origin

# WRONG: Pushing large files
git add big-video.mp4
git commit -m "add video"
git push
# Rejected or very slow!

# CORRECT: Use Git LFS for large files
git lfs install
git lfs track "*.mp4"
git add .gitattributes big-video.mp4
git commit -m "add video (LFS)"
git push

# WRONG: Mixing SSH and HTTPS remotes
# May have credential caching issues

# CORRECT: Use consistent protocol
git remote set-url origin git@github.com:user/repo.git
git remote set-url gitlab git@gitlab.com:user/repo.git

# WRONG: Not fetching before comparing
git log origin/main..HEAD
# May show stale data!

# CORRECT: Fetch first
git fetch origin
git log origin/main..HEAD

Quick Reference

# REMOTE MANAGEMENT
git remote -v                            # List remotes
git remote add name URL                  # Add remote
git remote set-url origin URL            # Change URL
git remote remove name                   # Remove remote

# FETCH
git fetch                                # From origin
git fetch --all                          # All remotes
git fetch --prune                        # Remove stale refs
git fetch origin main                    # Specific branch

# PULL
git pull                                 # Fetch + merge
git pull --rebase                        # Fetch + rebase
git pull origin main                     # From specific

# PUSH
git push                                 # To tracking branch
git push -u origin main                  # Set upstream
git push --all                           # All branches
git push --tags                          # All tags
git push origin --delete branch          # Delete remote branch
git push --force-with-lease              # Safe force push

# COMPARISON
git log origin/main..HEAD                # Local not on remote
git log HEAD..origin/main                # Remote not local
git fetch && git status                  # See ahead/behind

# MULTI-REMOTE
git push origin main && git push gitlab main
for remote in origin gitlab; do git push "$remote" main; done

# SSH REMOTES
git remote set-url origin git@github.com:user/repo.git
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push

See Also