1. Courses
  2. Developer Foundations
  3. GitHub for Teams
  4. Stop 1

35 minBeginner

GitHub: remotes, clone, push, pull and authentication

A repository on one laptop helps one person. GitHub gives your team one shared copy, and Git keeps yours and the shared one in step with a few commands. This lesson shows what a remote really is, what fetch, pull and push each move, how to log in safely, and how to handle the most common error: a rejected push.

By the end you can

  • Explain the difference between Git and GitHub, and what origin and origin/main are
  • Say exactly what fetch, pull and push change, and set pull.rebase
  • Set up SSH keys or HTTPS login on Windows and macOS, and log in with gh
  • Create a repo with gh repo create, push it, and clone it as a teammate
  • Fix "rejected (fetch first)" with fetch and rebase

The everyday picture

Head office keeps the master stock ledger. Each store keeps its own copy of the ledger in the back office and writes the day's entries there first, even when the internet is down during a power cut. In the evening, the store sends its new entries to head office, and collects the entries other stores sent, so its copy is up to date.

Two rules make this work. Head office never accepts a batch that would wipe out entries it already has from another store: if Store 12 sent entries since Store 48 last synced, Store 48 must first collect them and line its own entries up after them. And reading head office's ledger never changes the store's own pages until the manager decides to copy entries across. Those two rules are exactly git push being rejected, and the difference between git fetch and git pull.

Git, GitHub and remotes

Git is the tool on your machine. GitHub is a website that hosts Git repositories and adds things around them: pull requests, reviews, issues and Actions, which the rest of this course covers, starting with Pull requests and code review. The repository on GitHub is a normal Git repository without a working folder, called a . Your clone is a complete, independent repository with every commit. You can commit, branch, merge and read history with no network at all.

A is a saved name for another copy's URL. git clone creates one called automatically. There is nothing special about the name; it is a convention. With forks (below), a second remote called upstream is common.

For every branch on the remote, your repository keeps a such as origin/main. It is a ref under .git/refs/remotes/ (see Inside the .git folder) that records where main on GitHub pointed the last time you talked to GitHub. It is a photo, not a live view. It moves only when you fetch, pull or push. Your own main is separate. Its setting links it to origin/main, which is what lets git status say "Your branch is ahead of 'origin/main' by 1 commit".

Quick check

Your laptop has no internet for a whole day. Which of these can you still do?

Fetch, pull and push: what each one moves

git fetch downloads commits you do not have from the remote and moves your remote-tracking branches (origin/main) to match. It never touches your own branches, your staging area or your files. It is always safe. After a fetch, you can look before you decide: git log --oneline main..origin/main lists commits on GitHub that you do not have yet.

git pull is git fetch followed by integrating origin/main into your current branch. If you have no local commits, that is a fast-forward (see Branches and merging). If you have local commits and so does GitHub, the histories have diverged, and Git needs to know how to combine them. In current Git, a plain git pull on diverged branches stops with "Need to specify how to reconcile divergent branches" until you choose. Set it once:

  • git config --global pull.rebase true: replay your local commits on top of origin/main (see Rewriting history safely). Straight history; your unpushed commits get new IDs, which is fine because nobody else has them. Most teams choose this.
  • git config --global pull.rebase false: create a merge commit. True history, but every pull can add a "Merge branch 'main' of github.com:..." commit.
  • git config --global pull.ff only: only fast-forward, otherwise refuse, and you decide each time.

git push sends your commits to the remote and asks it to move its branch to your commit. The remote agrees only if that is a fast-forward for its branch: your commit must already contain everything the remote branch has. That rule is what stops one person from wiping out another's work, and it is why the rejected push below exists. The first push of a new branch needs git push -u origin branch-name; -u sets the upstream so later you can type plain git push and git pull. (Or set git config --global push.autoSetupRemote true once.)

Quick check

You want to see what your teammates pushed this morning without changing any of your own branches or files. Which command?

GitHub main: A B C C from a teammate fetch copies C pull fetch, then merge or rebase push sends D, only as a fast-forward Your clone origin/main GitHub at last fetch main your new commit D upstream link pull also moves main
GitHub's main has a teammate's commit C; your main has your new commit D. fetch downloads C and moves only origin/main, your record of GitHub. pull fetches and then moves your own main by merging or rebasing. push sends your commits and asks GitHub to move its main, which it does only as a fast-forward.

Logging in: SSH keys, HTTPS tokens and gh

GitHub no longer accepts your account password for Git. You have two choices, and either is fine.

SSH. You make a key pair on your machine: a private key that never leaves it and a public key you give GitHub. Remote URLs look like git@github.com:your-name/partner-api.git. Generate the key with ssh-keygen -t ed25519 -C "you@example.com" (the same in Git Bash, PowerShell and macOS Terminal), give it a passphrase, and load it into the SSH agent so you type the passphrase once per session. Add the public key in GitHub under Settings, SSH and GPG keys, or with gh ssh-key add. Test with ssh -T git@github.com, which says "Hi your-name! You've successfully authenticated, but GitHub does not provide shell access." If an office or store network blocks port 22, GitHub accepts SSH on port 443 at ssh.github.com.

HTTPS. URLs look like https://github.com/your-name/partner-api.git. When Git asks for a password, it wants a (PAT), and GitHub recommends fine-grained tokens limited to the repositories you need. A stores it so you do not paste it every time. Git for Windows includes Git Credential Manager, which can log you in through the browser. On macOS, install it with brew install --cask git-credential-manager, or use the next option.

GitHub CLI. gh auth login walks you through it: choose GitHub.com, then HTTPS or SSH as your Git protocol. With HTTPS it offers to authenticate Git for you and stores the credentials; with SSH it can generate a key and upload it. Then it logs in through the browser with a one-time code. gh auth status shows who you are logged in as and which protocol is set. This is the simplest path, and you need gh for the rest of this course anyway.

Quick check

A teammate on HTTPS keeps typing a token every time she pushes. What is the safe fix?

When your push is rejected

The most common GitHub error is not a bug. You and a teammate both started from the same main. They pushed a commit first. Now your push would move GitHub's main to a commit that does not contain theirs, which would delete their work, so GitHub refuses with ! [rejected] main -> main (fetch first).

The fix has three steps. Fetch to see what arrived. Rebase your commits on top of origin/main (or merge it, if that is your team's choice). Push again, now a fast-forward. If you set pull.rebase true, git pull does the first two in one go. Run the tests between the rebase and the push if their commit touched anything near yours, because the combination is new (see Merge conflicts without panic).

Never "fix" this with git push --force. That replaces GitHub's main with yours and deletes your teammate's commit. A branch ruleset can forbid it on main (see Branching strategies, releases and versions). Force-pushing is only for your own branch after a rebase, and then with --force-with-lease, which refuses if someone pushed since your last fetch (see Rewriting history safely).

1. Teammate pushes T B T GitHub main Y your main (local) parent B 2. git push rejected (fetch first) Y lacks T: moving main to Y would drop T 3. fetch, then rebase origin/main B T Y' Y replayed on T, new ID; test it 4. git push accepted main moves T to Y' nothing lost
Your commit Y and your teammate's T both have parent B. GitHub rejects Y because accepting it would drop T. After git fetch and git rebase origin/main, your change sits on top of T as Y', and the next push is a fast-forward.

Forks, and the repository basics

A is a copy of a repository under your own account. You need one when you cannot push to the original, for example to contribute to an open-source library such as a NestJS package. You push branches to your fork (origin) and open a pull request to the original (upstream). gh repo fork --clone sets this up: your fork becomes origin and the original becomes upstream. To catch up with the original, git fetch upstream and merge or rebase upstream/main. Inside your own team, do not fork. Everyone pushes branches to the one shared repository, and protection rules decide what reaches main.

Every repository should open with a useful README.md: what it is, how to run it locally, how to run the tests, where it is deployed and who owns it. GitHub shows it on the repository's front page. In Settings, check three things early: the visibility (private for company code), the default branch (main), and under General, Pull Requests, "Automatically delete head branches". Access is granted to people or teams with roles such as Read, Write and Admin; give the smallest role that works.

Build it

Log in, create a private repo for partner-api, push it, clone it into a second folder to act as a teammate, and cause and fix a rejected push. Commands work in Git Bash on Windows and Terminal on macOS unless shown separately. Outputs below are from a real session; your names and IDs will differ. To check the ahead-and-behind logic without a GitHub account, try the exercise in the Practice section: it runs in your browser.

  1. Install gh and log in

    Install the GitHub CLI: winget install --id GitHub.cli --source winget on Windows, brew install gh on macOS. Then log in and answer the questions: GitHub.com, SSH or HTTPS, and "Login with a web browser".

    Terminal
    gh auth login
    gh auth status

    gh auth status lists the account you are logged in as, whether it is active, the Git operations protocol and the token's scopes. With HTTPS, answer yes to "Authenticate Git with your GitHub credentials?" and you can skip step 2.

  2. Or set up an SSH key by hand

    Accept the default file and choose a passphrase. Then add the key to the agent. The agent setup differs by system:

    Terminal
    ssh-keygen -t ed25519 -C "you@example.com"
    Terminal
    eval "$(ssh-agent -s)"
    # create ~/.ssh/config with these lines once:
    #   Host github.com
    #     AddKeysToAgent yes
    #     UseKeychain yes
    #     IdentityFile ~/.ssh/id_ed25519
    ssh-add --apple-use-keychain ~/.ssh/id_ed25519

    Upload the public key and test it. The test exits with code 1 even when it works, because GitHub gives no shell.

    Terminal
    gh ssh-key add ~/.ssh/id_ed25519.pub --title "work laptop"
    ssh -T git@github.com
    Output
    Hi your-name! You've successfully authenticated, but GitHub does not provide shell access.

    The first time, SSH asks whether you trust github.com. Compare the fingerprint it shows with the one published in GitHub's docs before you type yes.

  3. Create the repo on GitHub from your local folder

    Make a local repo with one commit (a README and a .gitignore with node_modules/ and .env), then create a private GitHub repo from it. --source=. uses this folder, --remote=origin names the remote, and --push pushes the current branch with upstream set.

    Terminal
    gh repo create partner-api --private --source=. --remote=origin --push
    git remote -v
    git branch -vv
    git status
    Output
    origin	git@github.com:your-name/partner-api.git (fetch)
    origin	git@github.com:your-name/partner-api.git (push)
    * main e736c79 [origin/main] chore: initial commit
    On branch main
    Your branch is up to date with 'origin/main'.
    
    nothing to commit, working tree clean

    gh also prints "Created repository" and "Added remote" lines. [origin/main] in git branch -vv is the upstream link.

  4. Clone it again as a "teammate"

    From the parent folder, clone into a second folder. Each clone is a full repository.

    Terminal
    cd ..
    git clone git@github.com:your-name/partner-api.git teammate-copy
    cd teammate-copy
    git branch -a
    Output
    Cloning into 'teammate-copy'...
    * main
      remotes/origin/HEAD -> origin/main
      remotes/origin/main
  5. The teammate pushes first

    In teammate-copy, add src/limits.js, commit and push.

    Terminal
    git add src/limits.js
    git commit -m "feat: limit cart lines to 100"
    git push
    Output
    [main 48bd735] feat: limit cart lines to 100
     1 file changed, 1 insertion(+)
     create mode 100644 src/limits.js
    To github.com:your-name/partner-api.git
       e736c79..48bd735  main -> main
  6. You commit and push, and get rejected

    Back in partner-api, commit timeout.js. Your origin/main is still the old photo, so Git thinks you are only ahead.

    Terminal
    git commit -m "feat: add partner API timeout"
    git status
    git push
    Output
    On branch main
    Your branch is ahead of 'origin/main' by 1 commit.
      (use "git push" to publish your local commits)
    
    nothing to commit, working tree clean
    To github.com:your-name/partner-api.git
     ! [rejected]        main -> main (fetch first)
    error: failed to push some refs to 'github.com:your-name/partner-api.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.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  7. Fetch and look before you act

    Terminal
    git fetch
    git status
    git log --oneline --graph --all
    Output
    From github.com:your-name/partner-api
       e736c79..48bd735  main       -> origin/main
    On branch main
    Your branch and 'origin/main' have diverged,
    and have 1 and 1 different commits each, respectively.
      (use "git pull" if you want to integrate the remote branch with yours)
    
    nothing to commit, working tree clean
    * b6fb041 (HEAD -> main) feat: add partner API timeout
    | * 48bd735 (origin/main) feat: limit cart lines to 100
    |/
    * e736c79 chore: initial commit

    Now the photo is fresh. Fetch changed only origin/main; your main and your files are untouched.

  8. Rebase onto origin/main and push

    Terminal
    git rebase origin/main
    git log --oneline --graph --all
    git push
    git status -sb
    Output
    Successfully rebased and updated refs/heads/main.
    * b332bc5 (HEAD -> main) feat: add partner API timeout
    * 48bd735 (origin/main) feat: limit cart lines to 100
    * e736c79 chore: initial commit
    To github.com:your-name/partner-api.git
       48bd735..b332bc5  main -> main
    ## main...origin/main

    Your commit got a new ID (b6fb041 became b332bc5) because its parent changed, and the push is a plain fast-forward.

  9. See what plain git pull does, and set your default

    If you had run git pull at step 7 without a setting, Git would fetch and then stop:

    Output
    hint: You have divergent branches and need to specify how to reconcile them.
    hint: You can do so by running one of the following commands sometime before
    hint: your next pull:
    hint:
    hint:   git config pull.rebase false  # merge
    hint:   git config pull.rebase true   # rebase
    hint:   git config pull.ff only       # fast-forward only
    ...
    fatal: Need to specify how to reconcile divergent branches.
    Terminal
    git config --global pull.rebase true
    git config --global push.autoSetupRemote true

    From now on git pull fetches and rebases, and the first git push of a new branch sets its upstream by itself.

  10. Push a branch, then clean up deleted remote branches

    Without push.autoSetupRemote, a new branch's first plain push fails; -u fixes it. When a branch is deleted on GitHub, other clones keep a stale origin/... until they prune.

    Terminal
    git switch -c feature/partner-sync
    git push -u origin feature/partner-sync
    git push origin --delete feature/partner-sync
    # in teammate-copy, which had fetched the branch earlier:
    git branch -r
    git fetch --prune
    git branch -r
    Output
    To github.com:your-name/partner-api.git
     * [new branch]      feature/partner-sync -> feature/partner-sync
    branch 'feature/partner-sync' set up to track 'origin/feature/partner-sync'.
    To github.com:your-name/partner-api.git
     - [deleted]         feature/partner-sync
      origin/HEAD -> origin/main
      origin/feature/partner-sync
      origin/main
    From github.com:your-name/partner-api
     - [deleted]         (none)     -> origin/feature/partner-sync
      origin/HEAD -> origin/main
      origin/main

    git config --global fetch.prune true makes every fetch prune.

CommandMoves origin/main?Moves your main?Changes GitHub?
git fetchYesNoNo
git pullYesYes (merge or rebase)No
git pushYes, to what you pushedNoYes, fast-forward only
git push --force-with-leaseYesNoYes, replaces it if nobody pushed since your fetch

Bring it to your team

These questions surface access risks and daily friction.

  • Who has Admin and Write access to each repo, and when did we last review the list? Are people who left removed?
  • Do we use SSH keys or HTTPS with a credential manager? Are any tokens shared between people or saved in scripts?
  • What is our pull.rebase setting, and is it in our onboarding notes so every new laptop is set up the same?
  • Is pushing straight to main blocked, and are force-pushes to main blocked?
  • Can a new developer clone, install and run the tests on day one from the README alone?

Red flags

  • A personal access token pasted into a remote URL, a .env committed to the repo, or a token sent in chat.
  • One shared GitHub account or SSH key used by several people or by a server.
  • "My push was rejected, so I used --force."
  • Forks of the team's own repo used instead of branches, so work is scattered across personal accounts.
  • A repo with no README, or a README that still says "TODO".

Practice

Ahead, behind, or rejected?

git status and git push both compare two sets of commits: the ones your branch contains and the ones the remote branch contains. Write pushCheck(local, remote). Each argument is an array of the commit IDs reachable from that branch, in any order. Return an object with ahead (commits only you have), behind (commits only the remote has) and result: "rejected" if the remote has anything you lack, "up to date" if there is nothing to send, and "accepted" otherwise.

JavaScript exerciseRuns in your browser with tests
function pushCheck(local, remote) {
  // ahead: IDs in local but not in remote
  // behind: IDs in remote but not in local
  // result: "rejected" | "up to date" | "accepted"
}
Ctrl + Enter runs
Show a solution
JavaScript
function pushCheck(local, remote) {
  const mine = new Set(local);
  const theirs = new Set(remote);
  const ahead = [...mine].filter((id) => !theirs.has(id)).length;
  const behind = [...theirs].filter((id) => !mine.has(id)).length;
  let result = 'accepted';
  if (behind > 0) result = 'rejected';       // not a fast-forward
  else if (ahead === 0) result = 'up to date'; // nothing to send
  return { ahead, behind, result };
}
Pass the exercise to finish this task.

Talk a teammate out of --force

A teammate pastes the "rejected (fetch first)" output from step 6 into the team chat and writes: "GitHub is being weird, I'll force push." Write your reply: the commands to run, in order, and two sentences on why force-pushing would hurt.

  • Your first command downloads and inspects (git fetch, then git status or git log --graph --all) before changing anything
  • You integrate with git rebase origin/main or git pull --rebase (or a merge, if that is the team's rule)
  • You run the tests before pushing again, because the combination of both commits is new
  • You explain that --force would move main to a commit without the other person's work, deleting it from GitHub
  • The tone is helpful: you explain what the message means, not only what to type
Show a model answer

"Not weird, it means someone pushed to main after you last fetched. Run git fetch, then git log --oneline --graph --all to see their commit, then git rebase origin/main, run npm test, and git push. A force push would make GitHub's main point at your commit, which does not contain theirs, so their work would vanish from main and we might not notice until something breaks."

Check yourself

You run git fetch, and a teammate's new commit arrives. What changed in your repository?

Your push to main is rejected with "(fetch first)". What is the right fix?

What does git push -u origin feature/partner-sync add, compared with a push without -u?

Flashcards

Open my review

Key takeaways

  • Git is the tool; GitHub hosts a shared bare copy. origin is only the default name for it.
  • origin/main is a local photo of GitHub's main, updated only by fetch, pull and push.
  • fetch is always safe; pull is fetch plus merge or rebase (set pull.rebase); push only succeeds as a fast-forward.
  • Log in with SSH keys or HTTPS plus a credential helper, most easily through gh auth login. Never share keys or paste tokens into URLs.
  • A rejected push means someone pushed first: fetch, rebase, test, push. Never --force on a shared branch.

Sources

Episode transcriptHead office ledger, store copies · about 10 minutes · tap any line to play from there
  1. NadiaThursday afternoon, Imran. Release day for the Partner app API. Two developers push to main within five minutes of each other. The second one gets an error that says rejected. What does he do next?
  2. ImranOn a bad day? Searches the error, finds a forum answer that says add the force option, and pushes again.
  3. NadiaAnd the first developer's timeout fix silently disappears from GitHub. Partner shops on weak mobile data start failing again the next morning. Today is about why that error exists, and the two-minute fix that doesn't lose anyone's work.
  4. NadiaStart with a picture you know. Head office keeps the master stock ledger. Each store keeps its own copy in the back office and writes the day's entries there first, even when the internet is down during a power cut.
  5. ImranAnd in the evening, the store sends its new entries to head office, and collects what other stores sent.
  6. NadiaRight. And two rules. Head office never accepts a batch that would wipe out entries it already has. If store twelve sent entries since store forty-eight last synced, store forty-eight must collect them first and line its own up after them.
  7. ImranAnd the second rule?
  8. NadiaReading head office's ledger never changes the store's own pages, until the manager decides to copy entries across. Those two rules are the rejected push, and the difference between fetch and pull.
  9. ImranFirst, let me get the words straight. Git and GitHub. People use them as if they're the same.
  10. NadiaGit is the tool on your laptop. GitHub is a website that hosts Git repositories and adds pull requests, reviews, issues and Actions. The copy on GitHub is a normal Git repository without a working folder. And your clone is complete. Every commit, all of history. You can work for a week with no internet.
  11. ImranAnd origin?
  12. NadiaJust a saved name for GitHub's URL. Clone creates it for you. There's nothing magic about the word. With forks you often see a second one called upstream.
  13. ImranThen what's origin slash main? It shows up in every log.
  14. NadiaThat's the most important idea in this episode. Origin slash main is a branch in your own repository that records where main on GitHub was the last time you talked to GitHub. It's a photo, not a live view.
  15. ImranSo if a teammate pushed ten minutes ago and I haven't fetched, my photo is old.
  16. NadiaExactly. And your own main is a separate branch. It's linked to origin slash main, which is called its upstream. That's how git status can say your branch is ahead by one commit.
  17. ImranEven when GitHub has moved on and I'm actually behind.
  18. NadiaYes. Status compares with the photo. Now the three commands. Fetch downloads commits you don't have and moves the photo. Origin slash main. That's all it does. Your branch, your staging area, your files: untouched.
  19. ImranSo fetch is always safe.
  20. NadiaAlways. Pull is fetch, then it combines origin slash main into your current branch, by merging or by rebasing. And push sends your commits and asks GitHub to move its main to your commit.
  21. NadiaIf you can see your screen, the first diagram puts GitHub at the top and your clone at the bottom, with two boxes: origin slash main and main. The fetch arrow goes only to origin slash main. The pull arrow goes to your main. The green push arrow goes back up.
  22. ImranAnd GitHub accepts the push only if...
  23. NadiaOnly if it's a fast-forward for GitHub. Your commit must already contain everything GitHub's main has. That one rule is what stops one person from wiping out another's work.
  24. ImranSo back to Thursday. My teammate pushed T. My commit Y also sits on the old commit B. Y doesn't contain T.
  25. NadiaSo moving GitHub's main to Y would drop T. GitHub refuses, and the message says rejected, fetch first.
  26. NadiaThe second diagram walks through the fix in four steps. One, the teammate's commit T is on GitHub and your Y points back to B. Two, the red rejected box. Three, after fetch and rebase, your change sits after T, as Y prime. Four, a green accepted box.
  27. ImranSo the fix is fetch, rebase onto origin slash main, run the tests, push.
  28. NadiaThat's it. Two minutes. Your commit gets a new ID because its parent changed, and the push is an ordinary fast-forward. And never force push to main. Force push is only for your own branch after a rebase, with the lease option, as the rebase lesson in Git from the Inside showed.
  29. ImranCan't I just type git pull? That does fetch and combine.
  30. NadiaYou can, once you've told Git how to combine. In current Git, a plain pull on diverged branches stops and says you need to specify how to reconcile divergent branches. You set pull dot rebase to true once, and from then on pull means fetch and rebase.
  31. ImranWhy rebase and not merge?
  32. NadiaRebase keeps main a straight line, and it only rewrites your own unpushed commits, which nobody else has. Merge works too, but every pull can add a merge commit that says merge branch main. Most teams choose rebase. The point is to choose once, together.
  33. ImranNow logging in. My developers use different things and I don't know which is right.
  34. NadiaFirst, GitHub no longer accepts your account password for Git. There are two good options. SSH: you make a key pair on your laptop. The private key never leaves it. You give GitHub the public key.
  35. NadiaThe other option is HTTPS. When Git asks for a password, you give it a personal access token instead, ideally a fine-grained one limited to the repos you need. A credential helper stores it safely, like Git Credential Manager, which comes with Git for Windows.
  36. ImranAnd the GitHub CLI?
  37. NadiaThat's the easiest path. Gh auth login asks a few questions: GitHub dot com, HTTPS or SSH, and log in with a web browser. With HTTPS it offers to set Git up for you. With SSH it can create a key and upload it. You'll need gh for the rest of the course anyway.
  38. ImranWhat should I worry about as a PM?
  39. NadiaTokens pasted into a remote URL, a script or a chat message. One shared GitHub account or SSH key used by several people or a server. And access lists nobody has reviewed since people left.
  40. ImranAnd forks? I see people fork our own repos sometimes.
  41. NadiaA fork is a copy under your own account. You need it when you can't push to the original, like contributing to an open-source library. Inside your own team, don't fork. Everyone pushes branches to the one shared repo, and protection rules decide what reaches main.
  42. NadiaThe Build-it does the whole thing for real. You install gh and log in, or set up an SSH key by hand, with separate steps for macOS, PowerShell and Git Bash. Then gh repo create makes a private repo from your folder and pushes it.
  43. ImranThen I clone it into a second folder and pretend to be a teammate. The teammate pushes first, my push is rejected, I fetch, look at the graph, rebase, and push again.
  44. NadiaThen you see the message a plain pull gives, set pull dot rebase, push a new branch with the u option, and clean up a branch deleted on GitHub with fetch and prune. Every output is shown.
  45. NadiaAnd if you want to practise without a GitHub account, the practice section has a small exercise that runs in your browser. You count which commits are only yours and which are only on the remote, and decide whether the push is accepted.
  46. ImranSo the code does what git status does in its head. Ahead by one, behind by one, rejected.
  47. ImranFor my team. Who has admin and write access to each repo, and when did we last check? Are people who left removed?
  48. ImranDo we use SSH or HTTPS with a credential manager, and are any tokens shared or saved in scripts? And is everyone's pull dot rebase the same?
  49. NadiaGood. And one more: is pushing straight to main blocked? That's the lesson on branching strategies and releases, and it makes the Thursday story impossible.
  50. NadiaOne to think about. You run git fetch, and a teammate's new commit arrives. Did your main change? Did your files change? Take a second.
  51. ImranNeither. Only origin slash main moved. My branch and files stay the same until I merge or rebase.
  52. NadiaExactly right.
  53. ImranMy summary. One: Git is the tool, GitHub hosts the shared copy, and origin is just the name for it.
  54. ImranTwo: origin slash main is my photo of GitHub's main. Fetch updates the photo. Pull also moves my branch. Push only works as a fast-forward.
  55. ImranThree: a rejected push means someone pushed first. Fetch, rebase, test, push. Never force on main.
  56. NadiaOne addition to the first point. Your clone isn't a thin copy. It has all of history, so most Git work never needs the internet. That's why stores and laptops on bad connections can keep working.
  57. ImranLike the store ledger during a power cut.
  58. NadiaExactly. Next time: pull requests and code review. The second pair of eyes before a change reaches the stores.
Finished reading?Mark it complete to fill in its stop on your course line.

Use it at work

Runbook

Symptoms, first checks with commands, fixes and when to escalate, for one alert.

Open in the DevOps & TechOps Lab
Next stopPull requests and code review
Was this lesson helpful?
Questions and discussion

Loading the discussion…