EduFlow
Git & GitHub
0%

Section 3 · Collaborating on GitHub

Remotes: Push, Fetch, Pull and Tracking Branches

16 min4 min readFill in the blanks

Lesson at a glance

Connect your portfolio to a GitHub repository, push branches with upstream tracking, and keep in sync using fetch and pull while understanding what origin/main really is.

  1. 1Put the portfolio on GitHub
  2. 2Remote-tracking branches: Git’s memory of the remote
  3. 3Upstreams and git push -u
  4. 4Fetch, then pull
  5. 5A daily rhythm
  6. 6When push is rejected

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

So far the portfolio exists in one place, your laptop. If the disk dies, it’s gone, and nobody else can see or review it. A remote is another copy of the repository somewhere else, usually on GitHub. Git’s job is to keep the two in sync, and it does that with four main commands: clone, fetch, pull and push.

Put the portfolio on GitHub

On github.com, create a new repository named portfolio. Leave “Add a README” and the other initialisation options unticked: your local repository already has history, and an extra commit on GitHub would give you two unrelated histories to reconcile. GitHub then shows the commands to connect an existing repository. They boil down to:

Terminal
git remote add origin https://github.com/maya-okafor/portfolio.git
git remote -v
git push -u origin main

git remote add gives a URL a short name. origin is only a convention, the name Git uses automatically when you clone, but everyone uses it, so do too. The push uploads your commits and creates main on GitHub. The first time, Git will ask you to authenticate; the next lesson covers setting that up properly with SSH keys or a credential manager.

If you use the GitHub CLI, gh repo create portfolio --public --source=. --remote=origin --push does the whole thing in one go.

Starting from the other side, with a repository that already exists on GitHub, you clone it instead:

Terminal
git clone https://github.com/maya-okafor/portfolio.git

Clone creates the folder, downloads every commit, adds a remote called origin and checks out main with tracking already set up.

Remote-tracking branches: Git’s memory of the remote

After the push, git branch -a shows something new:

Text
* main
  remotes/origin/main

origin/main is a remote-tracking branch: your repository’s note of where main was on origin the last time you talked to it. You never commit to it. It moves only when you fetch, pull or push. That’s why git status can say “Your branch is up to date with ‘origin/main’” while a teammate pushed five minutes ago: Git hasn’t asked GitHub since.

Left, your laptop: main points at c3; origin/main, your last-known copy, points at b2. Right, GitHub: main points at d4, a commit a teammate pushed. git fetch downloads d4 and moves origin/main; git pull then also integrates it into your main; git push sends your commits and moves GitHub's main. Your laptop b2 c3 main origin/main origin/main: last seen at b2 GitHub (origin) b2 d4 main d4: a teammate's push fetch push
Your branch, your note about the remote, and the remote itself

Upstreams and git push -u

The -u in git push -u origin main (long form --set-upstream) records that your local main tracks origin/main. From then on:

  • a bare git push or git pull on main knows where to go;
  • git status reports “ahead 2” or “behind 1” against origin/main;
  • git branch -vv lists each branch with its upstream and ahead/behind counts.

Every new branch needs it once, on its first push: git push -u origin footer.

Fetch, then pull

git fetch asks the remote what’s new, downloads the commits and moves your remote-tracking branches. It never touches your own branches or files, so it’s always safe:

Terminal
git fetch
git status                       # "Your branch is behind 'origin/main' by 1 commit"
git log --oneline main..origin/main   # what's new over there

git pull is git fetch followed by integrating the upstream into your current branch. If you have no local commits of your own, that’s a fast-forward. If both sides have new commits, Git has to merge or rebase, and recent Git versions refuse to guess:

Text
fatal: Need to specify how to reconcile divergent branches.

Make the choice once:

Terminal
git config --global pull.rebase true    # replay my unpushed commits on top (my default)
# or: git config --global pull.rebase false   (create a merge commit)
# or: git config --global pull.ff only        (refuse unless it's a fast-forward)

I recommend pull.rebase true. It only rewrites your own unpushed commits, which the golden rule allows, and it keeps history free of “Merge branch ‘main’ of github.com:…” commits that say nothing.

A daily rhythm

Put these together and a working session on the portfolio looks the same every time. Start by switching to main and pulling, so you begin from what’s actually on GitHub rather than what was there last week. Create a branch for the change. Commit as you go, and push the branch early, even unfinished: a pushed branch is a backup, and it’s visible to anyone helping you. Before you open it for review, fetch again and rebase onto the fresh origin/main if it has moved. That habit alone prevents most of the rejected pushes and surprise conflicts people blame on Git.

Terminal
git switch main && git pull
git switch -c projects-filter
# …work and commit…
git push -u origin projects-filter

When push is rejected

If someone pushed to main since your last fetch, your push is refused:

Text
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://github.com/maya-okafor/portfolio.git'

The remote has commits you don’t. Pull them in, resolve any conflict with the routine from section 2, run your checks, and push again.

Your first push asked for credentials. Next you’ll set up authentication properly, so Git stops asking and GitHub knows it’s really you.

Key takeaways

  • A remote is a named URL for another copy of the repository; origin is the conventional name for the one you cloned from or push to.
  • origin/main is your local record of where main was on the remote at your last fetch; it moves only when you fetch, pull or push.
  • git push -u origin <branch> uploads a branch and sets it as the upstream, so later a bare git push or git pull knows where to go.
  • git fetch downloads without touching your branches; git pull fetches and then merges or rebases.
  • A rejected push means the remote has commits you don’t; pull them in, then push again, never force.

Further reading

Check your understanding

4 questions

Question 1 of 4

You ran git fetch and it downloaded two new commits on main. What changed in your working tree?

Question 2 of 4

git push fails with: Updates were rejected because the remote contains work that you do not have locally. What’s the right fix?

Question 3 of 4

What does -u add to git push -u origin footer?

Question 4 of 4

Your local main has one commit you haven’t pushed, and origin/main has two you haven’t pulled. With pull.rebase set to true, what does git pull do?

Practice

Fill in the blanks

Connect and sync the portfolio

Fill in the blanks: register the GitHub repository as origin, push main for the first time so it tracks origin/main, and later check for new commits on GitHub without changing your branch or files.

git remote origin https://github.com/maya-okafor/portfolio.git git push origin main # first push: also set the upstream # later: see what's new on GitHub without touching my files git git log --oneline main..origin/main