Git Course 0%

Level 2 — Basic Git with a remote

Beginner Git CLI GitLab UI GitHub UI ≈ 40 min

What you will learn

  • Add a remote to an existing repository and push it for the first time
  • See a change made on the web arrive locally with fetch and pull
  • Recognize and fix "rejected (fetch first)" and authentication errors

After this lesson you can

  • My playground lives on GitLab or GitHub and I can sync it in both directions

Objective

Turn the local playground into a shared repository: connect it to a private project of your own on GitLab (or GitHub), push, make a change in the browser, bring it back with fetch and pull, and push a second local commit. By the end, all four areas of the mental model are real, and the everyday loop runs end to end.

Starting state

  • The playground repository from Set up a safe playground, with at least the initial commit (git log --oneline shows it).
  • An empty private project named trailguide on GitLab or GitHub, created without a README (the playground page shows how). If you created it with a README, the "Common mistakes" section fixes it.
  • Git configured with your name and email (lesson 3.3).
  • A personal access token ready, or ten minutes to create one in step 3.

The lab shows GitLab; each step notes the GitHub difference.

Instructions

  1. Copy the project's HTTPS URL. On GitLab, open the project, click Code (top right) → copy Clone with HTTPS: it looks like https://gitlab.com/you/trailguide.git. On GitHub, the Code button above the file list → HTTPS tab.

  2. Tell your repository where the remote is.

    Terminal
    $ cd ~/git-practice/trailguide
    $ git remote add origin https://gitlab.com/you/trailguide.git
    $ git remote -v
    origin	https://gitlab.com/you/trailguide.git (fetch)
    origin	https://gitlab.com/you/trailguide.git (push)

    origin is now a name for that URL. Nothing has been sent yet.

  3. Push for the first time. The -u links your main to the remote's main so that future pushes and pulls need no arguments.

    Terminal
    $ git push -u origin main
    To https://gitlab.com/you/trailguide.git
     * [new branch]      main -> main
    branch 'main' set up to track 'origin/main'.

    Git first asks for credentials: your platform username, and as the password a personal access token, not your website password. To create one: GitLab avatar → Edit profile → Access → Personal access tokens → Generate token (older versions: Add new token), scopes read_repository and write_repository, an expiry date, then create it and copy it once. GitHub: avatar → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token, repository access to trailguide, permission Contents: Read and write. Your credential helper stores it, so this happens once. Lesson 8.3 explains tokens in depth.

    Checkpoint: refresh the project page in the browser. Your files are there.

  4. Confirm the link.

    Terminal
    $ git status
    On branch main
    Your branch is up to date with 'origin/main'.
    
    nothing to commit, working tree clean

    The second line is new: your branch now tracks origin/main.

  5. Edit a file in the browser. On GitLab: open docs/faq.md, click Edit → Edit single file, add a question at the end, keep the commit message (Update faq.md), leave the target branch as main, click Commit changes. On GitHub: open the file, click the pencil, edit, Commit changes…, choose Commit directly to the main branch, confirm. Your project now has a commit that your computer does not.

  6. See it arrive, without changing your files.

    Terminal
    $ git fetch
    From https://gitlab.com/you/trailguide
       216f956..01268bf  main       -> origin/main
    Terminal
    $ git status
    On branch main
    Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
      (use "git pull" to update your local branch)
    
    nothing to commit, working tree clean

    git fetch updated your bookmark origin/main; your own main and your files are unchanged. That is the difference between fetch and pull.

  7. Pull the change in.

    Terminal
    $ git pull
    Updating 216f956..01268bf
    Fast-forward
     docs/faq.md | 4 ++++
     1 file changed, 4 insertions(+)
    Terminal
    $ git log --oneline -3
    01268bf Update faq.md
    216f956 Initial import of trailguide

    "Fast-forward": your main simply moved up to the remote's commit, because you had nothing new locally. Open docs/faq.md in your editor: the browser edit is there.

  8. Make a local change and push it. No -u this time; the link exists.

    Terminal
    $ printf '\nLocal line after pull.\n' >> README.md
    $ git commit -am "docs: add local line"
    $ git push
    To https://gitlab.com/you/trailguide.git
       01268bf..127f39e  main -> main

    Checkpoint: the project page shows your commit as the latest.

  9. (Optional) Clone it somewhere else. This is what a colleague, or you on another computer, would do:

    Terminal
    $ cd ~/git-practice
    $ git clone https://gitlab.com/you/trailguide.git trailguide-clone
    To https://gitlab.com/you/trailguide.git
     ! [rejected]        main -> main (fetch first)
    error: failed to push some refs to 'https://gitlab.com/you/trailguide.git'
    hint: Updates were rejected because the remote contains work that you do not
    hint: have locally. This is usually caused by another repository pushing to
    hint: the same ref. If you want to integrate the remote changes, use
    hint: 'git pull' before pushing again.

    The clone has every commit and origin already set. Delete it afterwards: rm -rf ~/git-practice/trailguide-clone.

Expected result

  • git remote -v shows origin with your URL; git status says "up to date with 'origin/main'".
  • The project page on GitLab or GitHub shows the playground files and three commits: the import, the web edit, and your local line.
  • You have pushed twice, fetched once, pulled once, and understood each.

Common mistakes

  • ! [rejected] main -> main (fetch first) on the first push. The project was created with a README, so the server has a commit you do not have:

    A plain git pull then says fatal: refusing to merge unrelated histories, because the two histories share no commit. Two fixes: the clean one is to delete the project and recreate it empty; the quick one is git pull origin main --allow-unrelated-histories (an editor opens for the merge message; save and close), resolve the README conflict if any, then git push -u origin main.

  • Authentication failed or HTTP Basic: Access denied. You typed your website password, or a token without the write_repository scope, or an expired token. Create a new token and try again; if the helper stored a wrong one, lesson 8.4 shows how to remove it.

  • error: remote origin already exists. A remote was added earlier (perhaps with a typo). git remote set-url origin <correct url>.
  • error: src refspec main does not match any. Either the repository has no commits yet, or your branch is called master. git log --oneline and git branch tell you which; git branch -m main renames.
  • Your local changes … would be overwritten by merge on pull:

    Output
    error: Your local changes to the following files would be overwritten by merge:
    	README.md
    Please commit your changes or stash them before you merge.
    Aborting

    You edited a file that the incoming commit also changes. Commit or stash (lesson 5.7), then pull again.

Show solution

Terminal
$ cd ~/git-practice/trailguide
$ git remote add origin https://gitlab.com/you/trailguide.git
$ git push -u origin main
$ git status
# … edit docs/faq.md in the browser and commit it there …
$ git fetch
$ git status
$ git pull
$ git log --oneline -3
$ printf '\nLocal line after pull.\n' >> README.md
$ git commit -am "docs: add local line"
$ git push
The browser step cannot be scripted; everything else is these commands in order.

What happened and why

You added the fourth area. git remote add recorded a name for a URL; git push -u copied your commits there and linked the branches. The browser edit created a commit on the remote that only existed there until git fetch downloaded it into your local repository as origin/main — files untouched — and git pull merged it into your main, which, having no commits of its own, simply fast-forwarded. Your next commit and push closed the loop. From now on, every lesson that says "push" or "pull" refers to this exact movement between your main and origin/main.

Next: Level 3 adds branches, so that work in progress no longer lands on main.

Key terms

Remote origin Push Fetch Pull Clone