Git and GitHub from the Terminal on Mac and Windows

Table of contents

Introduction

If you write code, notes, configs, or scripts, you will want two things sooner or later:

  1. A history of what changed on your computer
  2. A copy of that work online

Git does the first part. It lives on your machine and remembers versions of your files.

GitHub does the second part. It stores Git projects on the internet so you can back them up, share them, or work with other people.

This guide walks you from nothing to a project on GitHub, using only the terminal. The Git commands are the same on Mac and Windows. What changes is how you install Git and which terminal you open.

By the end you should be able to:

  1. Install Git
  2. Put your name and email into Git
  3. Sign in to GitHub
  4. Build a small sample project called notes-cli
  5. Save changes, upload them, use branches, and merge work when it is ready

What you will use

Paths look a bit different. On Mac you often see /Users/yourname/.... On Windows you might see C:\Users\yourname\..., or in Git Bash /c/Users/yourname/.... The Git commands stay the same.

Install Git

Mac

If you use Homebrew:

brew install git

If you do not use Homebrew, Apple’s Command Line Tools also install Git:

xcode-select --install

Then check:

git --version

You should see a line that starts with git version.

Windows

  1. Download the installer from git-scm.com/download/win
  2. Run it
  3. For a first install, the default options are fine for most people
  4. After it finishes, open Git Bash from the Start menu

Check:

git --version

This guide uses Git Bash on Windows. If you use PowerShell instead, the Git commands still work. Some small shell helpers like ls or touch may differ.

Open a terminal

Mac

Press Cmd + Space, type Terminal, press Enter. Or open Applications → Utilities → Terminal.

Windows

Open Git Bash from the Start menu.

Go to a folder where you keep projects:

# Mac example
cd ~/Developer

# Windows Git Bash example
cd ~/Documents

If the folder is not there yet:

mkdir -p ~/Developer
cd ~/Developer

In PowerShell on Windows you can use:

mkdir $HOME\Developer
cd $HOME\Developer

First-time setup

Do this once on each computer.

Tell Git who you are

Every save (commit) stores a name and email. Use the email on your GitHub account, or the noreply email GitHub shows you in your email settings.

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

A few useful defaults

git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global core.editor "nano"

What those do, in plain words:

On Windows, if you prefer Notepad or VS Code:

git config --global core.editor notepad

# only if the `code` command works in your terminal
git config --global core.editor "code --wait"

Check your settings

git config --global --list

Sign in to GitHub

You need a GitHub account first. Then pick one way to prove who you are when you upload (git push) or download updates (git pull / git fetch).

Option A — GitHub CLI (often the easiest)

Install the gh tool:

# Mac with Homebrew
brew install gh

# Windows PowerShell with winget
winget install --id GitHub.cli

You can also download it from cli.github.com.

Log in:

gh auth login

Answer the questions on screen. A common path is:

  1. GitHub.com
  2. HTTPS
  3. Log in with a web browser
  4. Allow access when the browser asks

Check that it worked:

gh auth status

Option B — HTTPS with a Personal Access Token

GitHub does not accept your normal account password for Git over HTTPS. If you are not using gh, you create a Personal Access Token and use that when Git asks for a password.

  1. On GitHub go to Settings → Developer settings → Personal access tokens
  2. Create a token with permission to work with your repositories
  3. When git push asks for a password, paste the token

Option C — SSH keys

This is another common long-term setup. You make a key pair on your computer, add the public key to GitHub, then use SSH URLs like git@github.com:USER/REPO.git.

ssh-keygen -t ed25519 -C "you@example.com"

Press Enter to accept the default file location unless you know you want something else.

Then (Mac / Git Bash):

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Mac: copy the public key
pbcopy < ~/.ssh/id_ed25519.pub

# Windows Git Bash: copy the public key
clip < ~/.ssh/id_ed25519.pub

On GitHub: Settings → SSH and GPG keys → New SSH key → paste → save.

Test:

ssh -T git@github.com

GitHub should reply with a message that includes your username.

For the sample project below, this guide uses HTTPS with GitHub CLI, because that is usually the shortest path for beginners on both Mac and Windows.

Commands you will use a lot

You do not need to memorize everything. Learn this loop first:

Command Plain meaning
git status Show what changed and what is ready to save
git add <file> Mark a file to include in the next save
git add . Mark everything in this folder
git commit -m "message" Save a snapshot on your computer
git push Upload your commits to GitHub
git pull Download updates from GitHub and bring them into your current branch
git log --oneline Show a short list of past saves
git branch List branches
git switch -c name Create a branch and move to it
git switch name Move to an existing branch
git clone <url> Download an existing project

You may also see git checkout -b name. That older form also creates a branch and switches to it. Both are real. This guide mostly uses git switch.

Other useful checks:

git diff                 # changes not marked with git add yet
git diff --staged        # changes already marked with git add
git restore file.txt     # throw away local edits to a tracked file
git restore --staged file.txt   # unmark a file, but keep your edits

Be careful with git restore file.txt. It can discard work you have not committed.

Sample project: notes-cli

We will make a tiny project from scratch, put it on GitHub, then practice a feature branch.

The project is a small shell script that saves dated notes into a file. It is small on purpose, so you can finish the Git steps in one sitting.

1. Make the folder

cd ~/Developer   # or any folder you use for code
mkdir notes-cli
cd notes-cli

2. Start Git in that folder

git init

Git should say it created a repository. That means this folder now has history tracking.

3. Create the files

Create README.md:

cat > README.md << 'EOF'
# notes-cli

A tiny command-line notes helper.

## Usage

```bash
./note.sh "Buy milk"
./note.sh "Ship the blog draft"
```

Notes are appended to `notes.txt`.
EOF

Create note.sh:

cat > note.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

NOTE="${*:-}"
if [ -z "$NOTE" ]; then
  echo "Usage: ./note.sh \"your note\""
  exit 1
fi

STAMP="$(date '+%Y-%m-%d %H:%M:%S')"
echo "[$STAMP] $NOTE" >> notes.txt
echo "Saved: $NOTE"
EOF

On Mac and in Git Bash, make the script runnable:

chmod +x note.sh

Create .gitignore so common junk files are not saved:

cat > .gitignore << 'EOF'
.DS_Store
Thumbs.db
*.tmp
EOF

Windows note: if the cat ... << 'EOF' style feels awkward in PowerShell, create the same files in an editor with the same names and contents, then continue with the Git commands.

4. Make your first commit

git status
git add README.md note.sh .gitignore
git status
git commit -m "Initial commit: notes-cli script and README"

If Git says it does not know who you are, go back to First-time setup.

See the history:

git log --oneline

5. Put the project on GitHub

From inside notes-cli, if you installed gh and signed in:

gh repo create notes-cli --public --source=. --remote=origin --push

That command:

If you prefer the website:

  1. On GitHub click New repository
  2. Name it notes-cli
  3. Do not add a README or .gitignore there, because you already have them locally
  4. Then run:
git remote add origin https://github.com/YOUR_USERNAME/notes-cli.git
git push -u origin main

Replace YOUR_USERNAME with your real GitHub username.

Open it in the browser:

gh repo view --web

Or visit https://github.com/YOUR_USERNAME/notes-cli.

6. Try the script once

./note.sh "First note from my machine"
./note.sh "Learning Git on the terminal"
cat notes.txt

The script creates notes.txt. For this sample we will track that file too:

git add notes.txt
git commit -m "Add sample notes file from first runs"
git push

7. Practice a feature branch

A branch is a separate line of work. You can change files there without changing main until you merge.

git switch -c feature/list-command

Now update note.sh so ./note.sh --list prints the notes:

cat > note.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

if [ "${1:-}" = "--list" ] || [ "${1:-}" = "-l" ]; then
  if [ ! -f notes.txt ]; then
    echo "No notes yet."
    exit 0
  fi
  cat notes.txt
  exit 0
fi

NOTE="${*:-}"
if [ -z "$NOTE" ]; then
  echo "Usage: ./note.sh \"your note\""
  echo "       ./note.sh --list"
  exit 1
fi

STAMP="$(date '+%Y-%m-%d %H:%M:%S')"
echo "[$STAMP] $NOTE" >> notes.txt
echo "Saved: $NOTE"
EOF
chmod +x note.sh
./note.sh --list

Save and upload the branch:

git add note.sh
git commit -m "Add --list flag to print saved notes"
git push -u origin feature/list-command

Open a pull request:

gh pr create --title "Add list command" --body "Adds ./note.sh --list to print notes.txt"

Or on GitHub, after the push, click Compare & pull request.

Merge it on GitHub, or with:

gh pr merge --merge

Then update main on your computer:

git switch main
git pull origin main

That is the basic loop: work locally → commit → push → open a pull request → merge → pull.

Using a dev branch so main stays safe

On many projects, main is the branch you want to keep stable. That means: finished work only. If you build half-done features straight on main, it gets messy. Your own unfinished edits can get mixed with work you wanted to keep clean.

A common pattern is:

Some teams name that middle branch develop instead of dev. Same idea.

Branch Usual job
main Stable copy
dev Place where you build features
feature/... Optional short branch for one change, often merged into dev first

This does not make merge conflicts impossible. Conflicts can still happen when two branches change the same lines. What it does do is keep unfinished work off main until you choose to bring it in.

Create dev once

git switch main
git pull origin main
git switch -c dev
git push -u origin dev

Do new work on dev

Example: stay on dev, make a small change, commit, and push dev only.

git switch dev
git pull origin dev

Edit a file. For a concrete example, add one line to README.md, then:

git status
git add README.md
git commit -m "Note that development happens on the dev branch"
git push origin dev

main still has the older version until you merge.

Optional: make a feature branch from dev

If the change is bigger, create a feature branch from dev:

git switch dev
git pull origin dev
git switch -c feature/readme-note
# edit, then:
git add .
git commit -m "Explain the dev branch in the README"
git push -u origin feature/readme-note
gh pr create --base dev --title "Explain dev branch" --body "Adds a short note to the README"

--base dev means the pull request goes into dev, not main.

When dev is ready, merge it into main

Do this when the work on dev is in good shape.

With GitHub CLI:

gh pr create --base main --head dev --title "Merge dev into main" --body "Ready set of notes-cli updates"
gh pr merge --merge

Or on the website: Pull requests → New → base main, compare dev → create → merge.

Or merge on your computer:

git switch main
git pull origin main
git merge dev
git push origin main

After that, it is often useful to update dev so it includes what is now on main:

git switch dev
git merge main
git push origin dev

If Git reports a merge conflict

Git stops and marks the files. Open them and look for markers like:

<<<<<<<
your change
=======
the other change
>>>>>>>

Keep the right code, delete the markers, then:

git add .
git commit
git push

If you are in the middle of a merge and Git already prepared a merge commit message, git commit with no -m is enough after you fix the files.

A simple rule

  1. Keep main clean
  2. Create dev
  3. Build on dev (or on a feature branch that merges into dev)
  4. When ready, merge dev into main

That is what people usually mean by “don’t do all your work on main.”

A normal day of work

After the repo exists, a calm day often looks like this:

cd ~/Developer/notes-cli
git switch dev
git pull origin dev
# edit files
git status
git add .
git commit -m "Say why you made the change"
git push origin dev

When a batch of work is ready, merge dev into main using the steps in the section above.

If you do not have a dev branch yet and only need a tiny fix on main:

git switch main
git pull
# make the small fix
git add .
git commit -m "Say why you made the change"
git push

Commit messages are easier to read later if they explain why:

If you are joining someone else’s project instead of creating your own:

git clone https://github.com/SOMEUSER/SOME-REPO.git
cd SOME-REPO

Handy extras

See where origin points

git remote -v

Throw away uncommitted edits in one tracked file

git restore note.sh

Unmark a file, but keep your edits

git restore --staged note.sh

Set work aside for a moment

git stash
git pull
git stash pop

git stash saves uncommitted work temporarily. git stash pop brings it back. If pop causes conflicts, fix those files the same way you fix merge conflicts.

Mac and Windows reminders

Task Mac / Git Bash Windows PowerShell
Go home cd ~ cd $HOME
List files ls ls or dir
Make a bash script runnable chmod +x note.sh use Git Bash for that script style
Copy an SSH public key pbcopy < ~/.ssh/id_ed25519.pub in Git Bash: clip < ~/.ssh/id_ed25519.pub

Common errors

Wrapping up

You do not need every Git command on day one. You need a loop you trust:

status → add → commit → push

and enough comfort with pull, branches, and remotes that the terminal is not scary.

On Mac and Windows, Git’s words are the same. Install Git, set your name, sign in to GitHub, then walk a real folder like notes-cli from git init to a merge.

A useful habit after that: keep unfinished work on dev or a feature branch, and only merge into main when you mean to.