Git: Working with Remotes
A remote is a reference to another copy of the repository — usually on a server (GitHub, GitLab, a VPS). Remotes let multiple people share work. Git keeps local "remote-tracking branches" (like origin/main) as snapshots of the last known state of the remote; these are updated with git fetch.
Commands Covered
git remote · git fetch · git pull · git push · git ls-remote
git remote
# List remotes $ git remote # origin # List remotes with URLs $ git remote -v # origin https://github.com/user/repo.git (fetch) # origin https://github.com/user/repo.git (push) # Add a remote $ git remote add origin https://github.com/user/repo.git $ git remote add upstream https://github.com/original/repo.git # Remove a remote $ git remote remove upstream $ git remote rm upstream # same # Rename a remote $ git remote rename origin old-origin # Change a remote's URL $ git remote set-url origin https://github.com/user/new-repo.git # Switch from HTTPS to SSH: $ git remote set-url origin git@github.com:user/repo.git # Show detailed info about a remote (branches, tracking info) $ git remote show origin # Prune stale remote-tracking branches (branches deleted on remote) $ git remote prune origin $ git fetch --prune # same effect; prune during fetch
git fetch
Downloads objects and refs from a remote but does NOT modify your working tree or local branches. Safe to run at any time — it just updates your remote-tracking branches (origin/main, etc.).
# Fetch all changes from origin (the default remote) $ git fetch $ git fetch origin # Fetch a specific branch $ git fetch origin main $ git fetch origin feature-login # Fetch from all remotes $ git fetch --all # Fetch and prune stale remote-tracking branches $ git fetch --prune $ git fetch -p # Fetch all tags $ git fetch --tags # Fetch and show what changed $ git fetch origin $ git log HEAD..origin/main # commits on remote not yet local $ git diff HEAD origin/main # diff between local and remote
git pull
git pull is git fetch followed by a merge (or rebase) in one step. It integrates remote changes into your current branch.
# Pull from the tracked remote branch $ git pull # Pull from a specific remote and branch $ git pull origin main # Pull with rebase instead of merge (cleaner history) $ git pull --rebase $ git pull --rebase origin main # Set rebase as the default pull strategy globally: $ git config --global pull.rebase true # Pull and prune stale remote-tracking branches $ git pull --prune # Pull without merging or rebasing — just fetch (then you decide) $ git fetch origin $ git log HEAD..origin/main # review incoming commits $ git merge origin/main # then manually merge # If a pull creates merge conflicts: $ git pull # CONFLICT — fix files $ git add conflicted-file.c $ git commit # or: git rebase --continue if pulling with --rebase
pull vs. fetch + merge
| Command | What it does | When to use |
|---|---|---|
git pull | fetch + merge in one step | Quick; fine when you trust what's on the remote |
git pull --rebase | fetch + rebase in one step | Cleaner linear history; preferred in many teams |
git fetch then review | fetch without integrating | When you want to see what changed before merging |
git push
Uploads local commits to a remote repository. Push only works cleanly when the remote doesn't have commits you don't have locally (i.e., your branch is up to date with the remote).
# Push current branch to its tracked remote branch $ git push # Push to a specific remote and branch $ git push origin main $ git push origin feature-login # Push and set the upstream tracking branch (first push of a new branch) $ git push -u origin feature-login $ git push --set-upstream origin feature-login # After -u, you can just use: git push (no args needed) # Push all local branches $ git push --all origin # Push all tags $ git push --tags # Push a specific tag $ git push origin v1.0.0 # Delete a remote branch $ git push origin --delete feature-old $ git push origin :feature-old # older syntax — same effect # Delete a remote tag $ git push origin --delete v0.1-beta $ git push origin :refs/tags/v0.1-beta # Force push (rewrite remote history — use with extreme caution) $ git push --force # Safer alternative: fails if someone else has pushed since your last fetch $ git push --force-with-lease
When Push Fails
# Push rejected because remote has commits you don't: $ git push # error: failed to push some refs to 'origin' # hint: Updates were rejected because the remote contains work that you do not have locally. # Fix: fetch and integrate, then push $ git fetch origin $ git rebase origin/main # or: git merge origin/main $ git push
git ls-remote
Lists references (branches, tags) in a remote repository without cloning or fetching it.
# List all refs on a remote $ git ls-remote origin # List only branches (heads) $ git ls-remote --heads origin # List only tags $ git ls-remote --tags origin # Filter by pattern $ git ls-remote origin 'refs/heads/feature-*' # Check if a specific branch exists on remote $ git ls-remote --heads origin feature-login # Empty output = branch doesn't exist on remote # Use with any URL (without adding a remote) $ git ls-remote https://github.com/user/repo.git
Tracking Branches
# See which local branches track which remote branches $ git branch -vv # main abc1234 [origin/main] Latest commit message # feat def5678 [origin/feat: ahead 2] More commits # "ahead N" = N local commits not yet pushed # "behind N" = N remote commits not yet fetched/merged # "ahead N, behind M" = diverged — both have new commits # Set up tracking for an existing local branch $ git branch -u origin/main main $ git branch --set-upstream-to=origin/develop develop
dispelled