Skip to main content
    Courses/Git/Working with Remote Repositories

    Lesson 4 • Intermediate

    Working with Remote Repositories 🌿

    By the end of this lesson you'll be able to connect a local repo to GitHub, push your commits to the cloud, pull your teammates' work, and tell fetch from pull for good — the collaboration skills every developer needs.

    What You'll Learn

    • Connect a local repo to a remote with git remote add origin
    • Copy an existing project down with git clone
    • Upload your work with git push (and -u for tracking branches)
    • Tell git fetch apart from git pull — and when to use each
    • Understand what origin is and work with GitHub / GitLab
    • Choose between SSH and HTTPS for authentication

    Real-World Analogy

    A remote is the shared cloud copy of your project — think of a Google Drive folder the whole team shares. Your laptop has its own copy you edit offline. git push uploads your changes to the shared copy; git pull downloads everyone else's. GitHub, GitLab, and Bitbucket are just companies that host that shared copy for you. The nickname for your main shared copy is almost always origin — like having "Home" saved in your sat-nav so you don't retype the address every time.

    1. Remotes & origin

    A remote is a version of your repository that lives on a server. It is the bridge between your machine and everyone else's. The default remote — the one git clone sets up automatically — is named origin. "origin" is simply a short nickname for a long URL so you never have to retype it. You can add as many remotes as you like; a second one named upstream is common when you've forked a project. Read this worked example, run it, then you'll wire up a remote yourself.

    Worked example: listing and adding remotes
    # A REMOTE is a copy of your repo on a server (GitHub, GitLab, Bitbucket).
    # The default remote that 'git clone' creates for you is called 'origin'.
    # "origin" is just a NICKNAME for a long URL so you don't retype it.
    
    # List the remotes this repo knows about (and their URLs)
    git remote -v
    
    # Add a remote: give it a name and the URL of an EMPTY repo you made online
    git remote add origin https://github.com/you/project.git
    
    # You can have several. 'upstream' is the usual name for a repo you forked from.
    git remote add upstream https://github.com/original/project.git
    
    # Rename or remove a remote if you got it wrong:
    # git remote rename origin github
    # git remote remove origin
    Output
    origin    https://github.com/you/project.git (fetch)
    origin    https://github.com/you/project.git (push)
    upstream  https://github.com/original/project.git (fetch)
    upstream  https://github.com/original/project.git (push)
    Run these in a real Git repository in your own terminal. The output shows what git remote -v prints once both remotes exist.

    Your turn. You've just made an empty repo on GitHub and want to link your local project to it. Fill in the two blanks marked ___ using the hints, then run it.

    🎯 Your turn: link a local repo to GitHub
    # 🎯 YOUR TURN — you just created an EMPTY repo on GitHub at
    #   https://github.com/sam/notes.git  and you want to link your local repo to it.
    
    # 1) Add it as the 'origin' remote
    git remote add ___ https://github.com/sam/notes.git   # 👉 the standard name is 'origin'
    
    # 2) Confirm it worked by listing your remotes
    git ___ -v                                             # 👉 the command that shows remotes
    
    # ✅ Expected output:
    #    origin  https://github.com/sam/notes.git (fetch)
    #    origin  https://github.com/sam/notes.git (push)
    Output
    origin  https://github.com/sam/notes.git (fetch)
    origin  https://github.com/sam/notes.git (push)
    Replace each ___, run it in your own terminal, and check your output matches the expected lines.

    2. Cloning a Repository

    When a project already exists on a server, you don't build the link by hand — you clone it. git clone downloads the entire history, checks out the default branch, and creates the origin remote for you in one command. This is how you start working on any existing project, whether it's yours or a team's.

    Worked example: clone an existing project
    # git clone DOWNLOADS an existing remote repo to your machine in one step.
    # It copies every commit, checks out the default branch, and AUTO-CREATES
    # a remote called 'origin' pointing back at the URL you cloned from.
    
    git clone https://github.com/you/project.git
    
    # That gives you a 'project' folder. Move into it and you're ready to work:
    cd project
    
    # Proof that origin was set up for you — no 'git remote add' needed:
    git remote -v
    Output
    Cloning into 'project'...
    remote: Enumerating objects: 42, done.
    remote: Counting objects: 100% (42/42), done.
    remote: Compressing objects: 100% (30/30), done.
    Receiving objects: 100% (42/42), 18.21 KiB | 9.10 MiB/s, done.
    Resolving deltas: 100% (12/12), done.
    
    origin  https://github.com/you/project.git (fetch)
    origin  https://github.com/you/project.git (push)
    Try this with any public repo URL in your own terminal — notice you never ran git remote add yet origin is already there.

    3. Pushing & Tracking Branches

    git push uploads your local commits to the remote. The very first time you push a new branch, add -u (short for --set-upstream). This sets up a tracking branch — a permanent link between your local branch and its twin on the remote. After that, a bare git push and git pull automatically know where to go, so you can drop the origin branch-name part.

    Worked example: git push and -u tracking
    # git push — UPLOAD your local commits to the remote.
    git push origin main
    
    # FIRST push of a NEW branch: add -u (short for --set-upstream). This links your
    # local branch to the remote one ("tracking"), so from then on a bare
    # 'git push' and 'git pull' know where to go — no need to name origin/branch.
    git push -u origin feature-login
    
    # After -u, these just work on that branch:
    git push          # uploads to origin/feature-login
    git pull          # downloads from origin/feature-login
    
    # See which local branch tracks which remote branch:
    git branch -vv
    Output
    Enumerating objects: 5, done.
    Counting objects: 100% (5/5), done.
    Delta compression using up to 8 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (3/3), 412 bytes | 412.00 KiB/s, done.
    Total 3 (delta 1), reused 0 (delta 0)
    To https://github.com/you/project.git
       a1b2c3d..d4e5f6g  main -> main
    Run these against a real remote (e.g. a GitHub repo) from your own terminal. The output is what a successful push to main looks like.

    Now you try. You've made a new branch and want to push it for the first time with tracking, so future pushes are just git push. Fill in the two blanks:

    🎯 Your turn: first push with tracking
    # 🎯 YOUR TURN — you created a NEW branch and want to push it for the first time
    # AND set up tracking so future pushes are just 'git push'.
    
    # You're on a branch called 'add-dark-mode'. Push it to origin with tracking:
    git push ___ origin add-dark-mode   # 👉 the flag that sets upstream tracking (two letters: -?)
    
    # From now on this single command uploads further commits on this branch:
    git ___                             # 👉 the bare upload command (no arguments needed)
    
    # ✅ Expected (first push):
    #    * [new branch]      add-dark-mode -> add-dark-mode
    #    branch 'add-dark-mode' set up to track 'origin/add-dark-mode'.
    Output
    Enumerating objects: 4, done.
    Writing objects: 100% (3/3), 298 bytes | 298.00 KiB/s, done.
    To https://github.com/you/project.git
     * [new branch]      add-dark-mode -> add-dark-mode
    branch 'add-dark-mode' set up to track 'origin/add-dark-mode'.
    Fill in the ___ blanks, then run it. The expected output shows the new branch being created and set up to track.

    4. fetch vs pull

    This is the pair beginners mix up most. Both download new commits from the remote — the difference is what happens next. git fetch downloads the commits but leaves your files untouched, so you can inspect them first. git pull downloads and merges them into your current branch — it is literally git fetch followed by git merge. Use pull when you trust the changes; use fetch when you want to look before you leap.

    Worked example: fetch then merge, vs pull
    # This is the most-confused pair in Git. Both DOWNLOAD remote commits.
    # The difference is what they do AFTER downloading.
    
    # git fetch — download new commits but DON'T touch your files.
    # Your working tree is unchanged; you can inspect first, merge when ready.
    git fetch origin
    git log origin/main --oneline      # what's new on the server
    git diff main origin/main          # how it differs from your branch
    git merge origin/main              # NOW fold it into your branch (when happy)
    
    # git pull — download AND merge in one shot. It is literally:
    #   git fetch   +   git merge
    git pull origin main
    
    # Rule of thumb: 'pull' when you trust the changes and want them now;
    # 'fetch' when you want to look before you leap.
    Output
    remote: Enumerating objects: 8, done.
    remote: Counting objects: 100% (8/8), done.
    Unpacking objects: 100% (5/5), 1.02 KiB | 1.02 MiB/s, done.
    From https://github.com/you/project
       d4e5f6g..h7i8j9k  main       -> origin/main
    9f3a1c2 Add search box
    2b7e4d8 Fix header spacing
    Run these against a remote with new commits in your own terminal to see how fetch updates origin/main without changing your working files.

    Deep Dive: SSH vs HTTPS

    When you connect to GitHub or GitLab, the remote URL comes in two flavours — and they only differ in how you prove who you are:

    HTTPShttps://github.com/you/repo.git. The easiest to start with: you sign in with a Personal Access Token, and it works through almost any company firewall.

    SSHgit@github.com:you/repo.git. You set up a key pair once, then never type credentials again. This is the usual choice once you push often.

    You can switch an existing repo between them at any time — the commits don't care: git remote set-url origin git@github.com:you/repo.git.

    Putting It Together: a Day of Collaboration

    Here's the whole loop, using every command from this lesson — clone, branch, pull, push. A Pull Request (GitLab calls it a "Merge Request") is the request to merge your branch into the main one; it's where review and automated tests happen before your code lands.

    Worked example: clone → branch → pull → push → PR
    # === A full day collaborating on GitHub — every command from this lesson ===
    
    # 1. Clone the team repo (creates 'origin' automatically)
    git clone https://github.com/team/app.git
    cd app
    
    # 2. Start a feature branch and do your work
    git checkout -b feature-profile
    git commit -m "Add user profile page"
    
    # 3. Before pushing, get any new work teammates pushed while you coded
    git pull origin main          # download + merge their commits
    
    # 4. Push YOUR branch (first time -> set tracking with -u)
    git push -u origin feature-profile
    
    # 5. Open a Pull Request on GitHub: it shows a
    #    "Compare & pull request" button for the branch you just pushed.
    #    Teammates review, CI runs, then it's merged into main.
    Run the git commands in your own terminal, then open the Pull Request on GitHub in your browser.

    Why pull (step 3) before you push? So your branch already includes any work teammates pushed while you were coding — that's what keeps your push from being rejected.

    Pro Tips

    • 💡 Pull before you push. Habitually run git pull before pushing so your branch is up to date and the push isn't rejected.
    • 💡 Use git pull --rebase instead of plain git pull to keep a cleaner, straight-line history when pulling remote changes.
    • 💡 Don't push straight to main. Use a feature branch and a Pull Request so your work gets reviewed before it's merged.
    • 💡 git branch -vv shows which local branch tracks which remote branch — handy when a bare git push goes somewhere unexpected.

    Common Errors (and the fix)

    • "Updates were rejected because the remote contains work that you do not have" — someone pushed before you. Run git pull (or git pull --rebase) to bring their commits down, resolve any conflicts, then push again. Never reach for --force on a shared branch — it deletes their work.
    • "Expected new commits after git fetch but my files didn't change" — that's fetch working as designed: it updates origin/main but not your files. Run git merge origin/main (or use git pull next time) to actually integrate them.
    • "fatal: repository '…' not found" / "Could not read from remote" — the remote URL is wrong or you lack access. Check it with git remote -v and fix it with git remote set-url origin <correct-url>.
    • "You are in 'detached HEAD' state" — you checked out a commit or origin/main directly instead of a branch, so new commits won't belong to any branch. Get back on a branch with git checkout main, or keep your work with git switch -c new-branch.
    • "src refspec main does not match any" — you tried to push before making your first commit, or the branch name is misspelled. Commit at least once, then git push -u origin main.

    Quick Reference

    CommandPurpose
    git remote -vList remotes and their URLs
    git remote add origin <url>Add a remote named origin
    git clone <url>Download a repo (sets up origin)
    git push origin mainUpload commits to the remote
    git push -u origin <branch>First push + set tracking
    git fetch originDownload commits, don't merge
    git pull origin mainDownload and merge (fetch + merge)
    git remote set-url origin <url>Change a remote's URL (SSH ↔ HTTPS)

    Frequently Asked Questions

    Q: What is the difference between git fetch and git pull?

    Both download new commits from the remote. git fetch stops there — it updates your remote-tracking branches (like origin/main) but leaves your working files untouched, so you can inspect the changes first. git pull goes one step further: it is exactly git fetch followed by git merge, so it downloads AND merges the changes into your current branch in one command.

    Q: What does 'origin' actually mean in Git?

    origin is just the default nickname Git gives to the remote you cloned from, so you can type 'origin' instead of the full URL. There is nothing magic about the word — you could rename it with 'git remote rename origin github'. By convention, 'origin' is your own copy and 'upstream' is the original project you forked from.

    Q: Why does my git push get rejected?

    A push is rejected ('failed to push some refs') when the remote branch has commits you do not have locally — someone pushed before you. Git refuses to overwrite their work. The fix is to run 'git pull' (or 'git pull --rebase') to bring those commits down and merge them, resolve any conflicts, then push again.

    Q: What does the -u flag in 'git push -u' do?

    -u (short for --set-upstream) links your local branch to the remote branch so they 'track' each other. You only need it the first time you push a new branch. After that, a bare 'git push' and 'git pull' on that branch automatically know which remote branch to use, so you can drop the 'origin branch-name' part.

    Q: Should I use SSH or HTTPS to connect to GitHub?

    Both work. HTTPS URLs (https://github.com/you/repo.git) are the easiest to start with — you authenticate with a Personal Access Token, and they work through almost any firewall. SSH URLs (git@github.com:you/repo.git) use a key pair you set up once, so you never type credentials again; they are the usual choice once you push often. You can switch a repo between them with 'git remote set-url origin <new-url>'.

    Mini-Challenge: Contribute to Open Source

    No blanks this time — just a brief and an outline. This is the real open-source workflow: fork, clone, add an upstream remote, branch, commit, push, and open a Pull Request. Work through it against any public repo and check your remotes with git remote -v.

    🎯 Mini-Challenge: fork → clone → upstream → PR
    # 🎯 MINI-CHALLENGE: contribute a fix to an open-source project
    # A 'fork' is YOUR copy of someone else's repo on GitHub.
    #
    # 1. On GitHub, click "Fork" on  github.com/cool/library  to copy it to your account.
    # 2. Clone YOUR fork (use your username in the URL).
    # 3. Add the ORIGINAL repo as a second remote named 'upstream'.
    # 4. Create a branch called 'fix-readme-typo', make a commit on it.
    # 5. Push that branch to 'origin' (your fork), then open a PR to the original.
    #
    # ✅ After step 3, 'git remote -v' should list BOTH:
    #    origin    https://github.com/YOU/library.git (fetch/push)
    #    upstream  https://github.com/cool/library.git (fetch/push)
    
    # your commands here
    Run these commands in your own terminal after forking a repo on GitHub. Check your work with git remote -v — you should see both origin and upstream.

    🎉 Lesson Complete

    • ✅ A remote is the shared cloud copy of your repo; origin is its default nickname
    • git clone downloads a repo and sets up origin for you
    • git push uploads commits; add -u the first time to set up a tracking branch
    • git fetch downloads only; git pull = fetch + merge
    • ✅ Pull before you push so your push isn't rejected; use branches + Pull Requests
    • ✅ HTTPS and SSH are two ways to authenticate — switch any time with git remote set-url
    • Next lesson: Resolving Merge Conflicts — the most feared Git topic, made simple

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service