|$ curl https://forge-ai.dev/api/markdown?path=docs/git/remote
$cat docs/git-—-remote-repositories.md
updated Recently·45 min read·published

Git — Remote Repositories

GitVersion ControlIntermediate
Introduction

Remote repositories are versions of your project hosted on the internet or network (GitHub, GitLab, Bitbucket, or your own server). Git uses a distributed model where every local repository is a complete copy of the remote — each clone is a full backup.

This section covers remote configuration, authentication (SSH vs HTTPS), pushing and pulling, upstream tracking, tags, multiple remotes, and submodules.

Managing Remotes

A remote is a bookmark pointing to another repository. By convention, the primary remote is named origin. You can have multiple remotes pointing to different locations.

terminal
Bash
1# List configured remotes
2git remote -v
3# origin https://github.com/user/repo.git (fetch)
4# origin https://github.com/user/repo.git (push)
5
6# Add a new remote
7git remote add upstream https://github.com/other/repo.git
8
9# Remove a remote
10git remote remove upstream
11
12# Rename a remote
13git remote rename origin upstream
14
15# Change remote URL
16git remote set-url origin https://github.com/user/new-repo.git
17
18# Show detailed info about a remote
19git remote show origin
Authentication: SSH vs HTTPS

Git supports two main protocols for authenticating with remote servers. Each has trade-offs in convenience and security.

FeatureHTTPSSSH
SetupNone (uses credentials helper)Generate key pair, add to server
AuthenticationPersonal Access Token (PAT)SSH key pair
Firewall friendly✓ (port 443)✗ (port 22, often blocked)
Token expiryYes (configurable)No (key lasts until revoked)
Two-factor auth✓ (PAT works with 2FA)✓ (key bypasses 2FA)
terminal
Bash
1# HTTPS (recommended for most users)
2git clone https://github.com/user/repo.git
3
4# Cache credentials (macOS: Keychain, Windows: Git Credential Manager)
5git config --global credential.helper osxkeychain
6
7# SSH setup
8# 1. Generate SSH key
9ssh-keygen -t ed25519 -C "your_email@example.com"
10
11# 2. Add key to ssh-agent
12eval "$(ssh-agent -s)"
13ssh-add ~/.ssh/id_ed25519
14
15# 3. Copy public key and add to GitHub/GitLab
16cat ~/.ssh/id_ed25519.pub
17
18# 4. Clone with SSH
19git clone git@github.com:user/repo.git
20
21# SSH config for multiple accounts
22cat ~/.ssh/config
23# Host github-work
24# HostName github.com
25# User git
26# IdentityFile ~/.ssh/id_ed25519_work
🔥

pro tip

Use HTTPS with a credential helper for most scenarios — it works through corporate firewalls and proxies. Use SSH when you need key-based access for automation (CI/CD pipelines, deployment scripts) or when managing multiple accounts on the same host.
Push, Pull, and Fetch

These three commands form the core of remote communication. Understanding their differences is critical for collaborative work.

terminal
Bash
1# Fetch — download remote changes without merging
2git fetch origin
3# Remote branches updated, local branches unchanged
4# You can inspect changes before merging:
5git log origin/main..main
6
7# Pull — fetch + merge (or rebase)
8git pull origin main
9# This is equivalent to:
10# git fetch origin
11# git merge origin/main
12
13# Pull with rebase (linear history)
14git pull --rebase origin main
15
16# Configure pull to always rebase
17git config --global pull.rebase true
18
19# Push — upload local commits to remote
20git push origin main
21
22# Push and set upstream tracking
23git push -u origin feature-branch
24# Next time: just "git push" from this branch
25
26# Force push (use with extreme caution)
27git push --force-with-lease origin feature-branch
28# Safer than --force — checks if remote has changed

warning

Avoid git push --force. Use --force-with-leaseinstead — it checks that your remote-tracking branch matches the remote before overwriting. This prevents accidentally overwriting someone else's pushes. Even better, avoid force-pushing to shared branches entirely.
Upstream Tracking

Upstream tracking links a local branch to a remote branch. Once set, Git knows where to push and pull automatically without specifying the remote and branch every time.

terminal
Bash
1# Set upstream when pushing
2git push -u origin feature-branch
3
4# Set upstream for an existing branch
5git branch -u origin/feature-branch
6
7# Or use --set-upstream-to
8git branch --set-upstream-to=origin/feature-branch
9
10# View tracking relationship
11git branch -vv
12# main abc123 [origin/main] Latest update
13# feature-x def456 [origin/feature-x] Add feature X
14# local-only ghi789 (no tracking)
15
16# Delete upstream tracking (without deleting remote)
17git branch --unset-upstream feature-branch
18
19# Sync with upstream (fetch + prune deleted remote branches)
20git fetch -p origin

info

After git push -u, you can use git push and git pull without arguments from that branch. This is especially useful for feature branches where you push frequently.
Multiple Remotes

Many projects use multiple remotes — for example, a personal fork, the upstream project, and a deployment target. This is common in the fork-and-PR workflow.

terminal
Bash
1# Fork workflow: personal fork + upstream
2git remote add origin git@github.com:you/repo.git # Your fork
3git remote add upstream git@github.com:original/repo.git # Original
4
5# Sync from upstream
6git fetch upstream
7git checkout main
8git merge upstream/main
9git push origin main
10
11# Push to a different remote
12git push upstream feature-branch
13
14# Fetch from all remotes
15git fetch --all
16
17# Show all remotes
18git remote -v
19
20# Delete a remote
21git remote remove upstream

best practice

Use descriptive remote names. origin is your personal fork, upstream is the main project repository. For deployment, consider staging or production as remote names. This makes your intent clear when pushing.
Remote Branches

Remote-tracking branches (like origin/main) are local read-only references to the state of remote branches. They update when you fetch or pull, and they cannot be checked out directly — you must create a local branch from them.

terminal
Bash
1# List remote branches
2git branch -r
3# origin/HEAD -> origin/main
4# origin/develop
5# origin/feature-login
6
7# Create a local branch from a remote branch
8git checkout -b feature-login origin/feature-login
9# Modern alternative:
10git switch feature-login
11# (creates local tracking branch automatically)
12
13# Delete a remote branch
14git push origin --delete feature-login
15
16# Delete a local remote-tracking reference
17git branch -d -r origin/feature-login
18
19# Prune stale remote-tracking branches
20git remote prune origin
21# or: git fetch -p origin

warning

Deleting a remote branch (git push --delete) does not delete the local remote-tracking reference. Run git remote prune origin or git fetch -p to clean up stale references. Otherwise, your local git branch -r will show branches that no longer exist on the remote.
Tags on Remote

Tags are not automatically pushed to remotes. You must explicitly push them, and they have their own synchronization behavior distinct from branches.

terminal
Bash
1# Push a specific tag
2git push origin v1.0.0
3
4# Push all tags
5git push origin --tags
6
7# Push tags matching a pattern
8git push origin --follow-tags
9# (only pushes annotated tags reachable from pushed commits)
10
11# Delete a remote tag
12git push --delete origin v1.0.0
13
14# Alternative: push empty ref to delete
15git push origin :refs/tags/v1.0.0
16
17# Fetch tags from remote
18git fetch --tags origin
19
20# Fetch tags + prune deleted tags
21git fetch --tags -p origin
22
23# Check if a tag exists locally that doesn't exist remotely
24git tag --list | while read tag; do
25 git ls-remote --tags origin "$tag" | grep -q . || echo "Missing: $tag"
26done
🔥

pro tip

Use git push --follow-tags instead of --tags. It only pushes annotated tags that are reachable from the commits being pushed, preventing old or unrelated tags from being sent to the remote.
Submodules

Submodules embed one Git repository inside another. They pin a specific commit from an external project, providing reproducible dependencies without copying files.

terminal
Bash
1# Add a submodule
2git submodule add https://github.com/lib/library.git lib/library
3
4# Clone a repo WITH its submodules
5git clone --recurse-submodules https://github.com/user/repo.git
6
7# If you already cloned without submodules:
8git submodule init
9git submodule update
10
11# Update all submodules to their latest remote commits
12git submodule update --remote
13
14# Pull with submodule updates
15git pull --recurse-submodules
16
17# Check submodule status
18git submodule status
19
20# Show diff including submodule changes
21git diff --submodule
22
23# Remove a submodule (three steps)
24git submodule deinit lib/library
25git rm lib/library
26rm -rf .git/modules/lib/library

Submodule vs Alternatives

FeatureSubmoduleMonorepoPackage Manager
Version pinning✓ Exact commit✓ Single version✓ Semver range
Develop across repos
Clone timeSlower (nested clones)FasterFastest (cached)
ComplexityHighLowLow

best practice

Submodules add significant complexity. Consider alternatives first: monorepos for closely related projects, or package managers (npm, pip, cargo) for external dependencies. Use submodules only when you need precise commit-level pinning of an actively developed dependency that your team also contributes to.
Advanced Remote Operations

These advanced commands handle edge cases in remote synchronization, from shallow fetches to bundle transfers for air-gapped environments.

terminal
Bash
1# Shallow fetch (limited history, faster)
2git fetch --depth 10 origin
3
4# Deepen a shallow clone
5git fetch --deepen 50 origin
6
7# Convert to full clone
8git fetch --unshallow origin
9
10# Fetch a single branch
11git fetch origin main
12
13# Push to multiple remotes in one command
14git remote add all git@github.com:user/repo.git
15git remote set-url --add --push all git@github.com:mirror/repo.git
16git push all main
17
18# Create a bundle (for air-gapped environments)
19git bundle create repo.bundle --all
20
21# Clone from a bundle
22git clone repo.bundle repo
23
24# List references in a bundle
25git bundle list-heads repo.bundle
26
27# Prune remote tracking branches
28git fetch --prune origin

info

Git bundles are useful for transferring repositories to air-gapped systems or when direct network access is unavailable. They create a single file containing all Git objects and references, which can be transferred via USB drive or other offline methods.
Common Pitfalls

✗ Pushing to main without review

git push origin main

Most teams protect main with branch rules. Direct pushes are rejected. Always use pull requests for changes to protected branches.

✗ Credential issues

remote: Support for password authentication was removed.

GitHub removed password authentication in 2021. Use a Personal Access Token (HTTPS) or an SSH key. Configure a credential helper to avoid re-entering tokens.

✗ Diverged history after rebase

hint: Updates were rejected because the tip of your current branch is behind

After rebasing a pushed branch, force-push is required. Use --force-with-lease and communicate with your team before doing so.

✗ Pushing large files

error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413

GitHub has a 100 MB file size limit and repos over 5 GB trigger warnings. Use Git LFS for large files or reduce binary assets.

$Blueprint — Engineering Documentation·Section ID: GIT-03·Revision: 1.0