Git — Remote Repositories
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.
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.
| 1 | # List configured remotes |
| 2 | git 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 |
| 7 | git remote add upstream https://github.com/other/repo.git |
| 8 | |
| 9 | # Remove a remote |
| 10 | git remote remove upstream |
| 11 | |
| 12 | # Rename a remote |
| 13 | git remote rename origin upstream |
| 14 | |
| 15 | # Change remote URL |
| 16 | git remote set-url origin https://github.com/user/new-repo.git |
| 17 | |
| 18 | # Show detailed info about a remote |
| 19 | git remote show origin |
Git supports two main protocols for authenticating with remote servers. Each has trade-offs in convenience and security.
| Feature | HTTPS | SSH |
|---|---|---|
| Setup | None (uses credentials helper) | Generate key pair, add to server |
| Authentication | Personal Access Token (PAT) | SSH key pair |
| Firewall friendly | ✓ (port 443) | ✗ (port 22, often blocked) |
| Token expiry | Yes (configurable) | No (key lasts until revoked) |
| Two-factor auth | ✓ (PAT works with 2FA) | ✓ (key bypasses 2FA) |
| 1 | # HTTPS (recommended for most users) |
| 2 | git clone https://github.com/user/repo.git |
| 3 | |
| 4 | # Cache credentials (macOS: Keychain, Windows: Git Credential Manager) |
| 5 | git config --global credential.helper osxkeychain |
| 6 | |
| 7 | # SSH setup |
| 8 | # 1. Generate SSH key |
| 9 | ssh-keygen -t ed25519 -C "your_email@example.com" |
| 10 | |
| 11 | # 2. Add key to ssh-agent |
| 12 | eval "$(ssh-agent -s)" |
| 13 | ssh-add ~/.ssh/id_ed25519 |
| 14 | |
| 15 | # 3. Copy public key and add to GitHub/GitLab |
| 16 | cat ~/.ssh/id_ed25519.pub |
| 17 | |
| 18 | # 4. Clone with SSH |
| 19 | git clone git@github.com:user/repo.git |
| 20 | |
| 21 | # SSH config for multiple accounts |
| 22 | cat ~/.ssh/config |
| 23 | # Host github-work |
| 24 | # HostName github.com |
| 25 | # User git |
| 26 | # IdentityFile ~/.ssh/id_ed25519_work |
pro tip
These three commands form the core of remote communication. Understanding their differences is critical for collaborative work.
| 1 | # Fetch — download remote changes without merging |
| 2 | git fetch origin |
| 3 | # Remote branches updated, local branches unchanged |
| 4 | # You can inspect changes before merging: |
| 5 | git log origin/main..main |
| 6 | |
| 7 | # Pull — fetch + merge (or rebase) |
| 8 | git pull origin main |
| 9 | # This is equivalent to: |
| 10 | # git fetch origin |
| 11 | # git merge origin/main |
| 12 | |
| 13 | # Pull with rebase (linear history) |
| 14 | git pull --rebase origin main |
| 15 | |
| 16 | # Configure pull to always rebase |
| 17 | git config --global pull.rebase true |
| 18 | |
| 19 | # Push — upload local commits to remote |
| 20 | git push origin main |
| 21 | |
| 22 | # Push and set upstream tracking |
| 23 | git push -u origin feature-branch |
| 24 | # Next time: just "git push" from this branch |
| 25 | |
| 26 | # Force push (use with extreme caution) |
| 27 | git push --force-with-lease origin feature-branch |
| 28 | # Safer than --force — checks if remote has changed |
warning
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.
| 1 | # Set upstream when pushing |
| 2 | git push -u origin feature-branch |
| 3 | |
| 4 | # Set upstream for an existing branch |
| 5 | git branch -u origin/feature-branch |
| 6 | |
| 7 | # Or use --set-upstream-to |
| 8 | git branch --set-upstream-to=origin/feature-branch |
| 9 | |
| 10 | # View tracking relationship |
| 11 | git 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) |
| 17 | git branch --unset-upstream feature-branch |
| 18 | |
| 19 | # Sync with upstream (fetch + prune deleted remote branches) |
| 20 | git fetch -p origin |
info
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.
| 1 | # Fork workflow: personal fork + upstream |
| 2 | git remote add origin git@github.com:you/repo.git # Your fork |
| 3 | git remote add upstream git@github.com:original/repo.git # Original |
| 4 | |
| 5 | # Sync from upstream |
| 6 | git fetch upstream |
| 7 | git checkout main |
| 8 | git merge upstream/main |
| 9 | git push origin main |
| 10 | |
| 11 | # Push to a different remote |
| 12 | git push upstream feature-branch |
| 13 | |
| 14 | # Fetch from all remotes |
| 15 | git fetch --all |
| 16 | |
| 17 | # Show all remotes |
| 18 | git remote -v |
| 19 | |
| 20 | # Delete a remote |
| 21 | git remote remove upstream |
best practice
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.
| 1 | # List remote branches |
| 2 | git branch -r |
| 3 | # origin/HEAD -> origin/main |
| 4 | # origin/develop |
| 5 | # origin/feature-login |
| 6 | |
| 7 | # Create a local branch from a remote branch |
| 8 | git checkout -b feature-login origin/feature-login |
| 9 | # Modern alternative: |
| 10 | git switch feature-login |
| 11 | # (creates local tracking branch automatically) |
| 12 | |
| 13 | # Delete a remote branch |
| 14 | git push origin --delete feature-login |
| 15 | |
| 16 | # Delete a local remote-tracking reference |
| 17 | git branch -d -r origin/feature-login |
| 18 | |
| 19 | # Prune stale remote-tracking branches |
| 20 | git remote prune origin |
| 21 | # or: git fetch -p origin |
warning
Submodules embed one Git repository inside another. They pin a specific commit from an external project, providing reproducible dependencies without copying files.
| 1 | # Add a submodule |
| 2 | git submodule add https://github.com/lib/library.git lib/library |
| 3 | |
| 4 | # Clone a repo WITH its submodules |
| 5 | git clone --recurse-submodules https://github.com/user/repo.git |
| 6 | |
| 7 | # If you already cloned without submodules: |
| 8 | git submodule init |
| 9 | git submodule update |
| 10 | |
| 11 | # Update all submodules to their latest remote commits |
| 12 | git submodule update --remote |
| 13 | |
| 14 | # Pull with submodule updates |
| 15 | git pull --recurse-submodules |
| 16 | |
| 17 | # Check submodule status |
| 18 | git submodule status |
| 19 | |
| 20 | # Show diff including submodule changes |
| 21 | git diff --submodule |
| 22 | |
| 23 | # Remove a submodule (three steps) |
| 24 | git submodule deinit lib/library |
| 25 | git rm lib/library |
| 26 | rm -rf .git/modules/lib/library |
Submodule vs Alternatives
| Feature | Submodule | Monorepo | Package Manager |
|---|---|---|---|
| Version pinning | ✓ Exact commit | ✓ Single version | ✓ Semver range |
| Develop across repos | ✓ | ✗ | ✗ |
| Clone time | Slower (nested clones) | Faster | Fastest (cached) |
| Complexity | High | Low | Low |
best practice
These advanced commands handle edge cases in remote synchronization, from shallow fetches to bundle transfers for air-gapped environments.
| 1 | # Shallow fetch (limited history, faster) |
| 2 | git fetch --depth 10 origin |
| 3 | |
| 4 | # Deepen a shallow clone |
| 5 | git fetch --deepen 50 origin |
| 6 | |
| 7 | # Convert to full clone |
| 8 | git fetch --unshallow origin |
| 9 | |
| 10 | # Fetch a single branch |
| 11 | git fetch origin main |
| 12 | |
| 13 | # Push to multiple remotes in one command |
| 14 | git remote add all git@github.com:user/repo.git |
| 15 | git remote set-url --add --push all git@github.com:mirror/repo.git |
| 16 | git push all main |
| 17 | |
| 18 | # Create a bundle (for air-gapped environments) |
| 19 | git bundle create repo.bundle --all |
| 20 | |
| 21 | # Clone from a bundle |
| 22 | git clone repo.bundle repo |
| 23 | |
| 24 | # List references in a bundle |
| 25 | git bundle list-heads repo.bundle |
| 26 | |
| 27 | # Prune remote tracking branches |
| 28 | git fetch --prune origin |
info
✗ Pushing to main without review
git push origin mainMost 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 behindAfter 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: 413GitHub has a 100 MB file size limit and repos over 5 GB trigger warnings. Use Git LFS for large files or reduce binary assets.