Git vs GitHub vs GitHub Actions: What Each One Does

One of my students asked me a question recently that I think a lot of people are too embarrassed to ask: "What's actually the difference between Git, GitHub and GitHub Actions? Aren't they the same thing?"
It's a fair question. The names overlap, they show up in the same tutorials, and most courses throw all three at you in the first week without separating them. So here's the short answer before we get into it:
- Git tracks changes to your files. It's a program that runs on your computer.
- GitHub is a website that stores Git repositories online, so you can share them and work on them with other people.
- GitHub Actions is a feature of GitHub that runs automation, like tests or deployments, whenever something changes in a repository.
Git can live without GitHub. GitHub is built on Git. Actions only exists inside GitHub. The rest of this post builds one small project, step by step, so you can see exactly where each one starts and stops.
Git: Version Control on Your Own Machine
Git is a version control system. It records snapshots of your files over time, so you can see what changed, when, and why, and go back if something breaks. It was created in 2005 by Linus Torvalds for Linux kernel development, years before GitHub existed.
The important thing to understand is that Git runs entirely on your computer. You don't need an account, a website or even an internet connection.
Install Git for your operating system:
- macOS: run
xcode-select --install. Git comes with Apple's Command Line Tools. - Windows: run
winget install --id Git.Git -e, or download the installer from git-scm.com. - Linux: use your package manager, for example
sudo apt install giton Ubuntu. - Check it worked: run
git --version.
Then create a folder with a tiny script:
mkdir git-github-actions-demo && cd git-github-actions-demo
cat > greet.sh <<'EOF'
#!/usr/bin/env bash
# greet.sh - prints a greeting for the name you pass in
name="${1:-world}"
echo "Hello, ${name}!"
EOF
chmod +x greet.sh
Now turn the folder into a Git repository and save your first snapshot, which Git calls a commit:
git init -b main
git add greet.sh
git status --short
git commit -m "Add greeting script"
Initialized empty Git repository in /Users/you/git-github-actions-demo/.git/
A greet.sh
git init created a hidden .git folder, and that folder is the repository. Every commit, every branch and the entire history lives in there. git add marks a file to be included in the next commit, and git commit saves the snapshot with a message.
Add a README and commit again, then look at the history:
echo "# git-github-actions-demo" > README.md
git add README.md
git commit -m "Add README"
git log --oneline
f87f6ae Add README
aa0c861 Add greeting script
Now make a change and ask Git what's different:
sed -i '' 's/Hello, /Hi there, /' greet.sh # on Linux, use sed -i without the ''
git diff
diff --git a/greet.sh b/greet.sh
index a3179de..f992b60 100755
--- a/greet.sh
+++ b/greet.sh
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
# greet.sh - prints a greeting for the name you pass in
name="${1:-world}"
-echo "Hello, ${name}!"
+echo "Hi there, ${name}!"
Decided you don't like the change? Throw it away and go back to the last commit:
git restore greet.sh
./greet.sh Student
Hello, Student!
Finally, check where this repository is connected to:
git remote -v
It prints nothing. This repository has a full history and you can undo changes, but it exists only on your laptop. That's Git on its own: complete version control, with no website involved at all.
Pro tip: Every Git tutorial uses
git addandgit commitconstantly, so it helps to know the three places a change can be. It's either modified in your folder, staged withgit add, or committed into the history.git statusalways tells you which.
GitHub: Where Your Repositories Live Online
A repository on your laptop has two problems. Nobody else can work on it, and if your laptop dies, so does the history. That's what GitHub solves. It's a website owned by Microsoft that hosts Git repositories, so you can push your history to it, share it, and collaborate on it.
GitHub doesn't replace Git. You still use Git commands; GitHub is just another copy of the repository that lives on a server. You can create the GitHub side from the website, or from your terminal with the GitHub CLI:
gh auth login # one-time sign in
gh repo create git-github-actions-demo --public --source=. --remote=origin --push
git remote -v
That one command creates an empty repository on GitHub, adds it to your local repository as a remote called origin, and pushes your commits to it. Run git remote -v again and you'll now see the GitHub URL listed for origin.
To do the same thing by hand, which is worth doing once so you know what happened:
- Create an empty repository on github.com, without a README or license.
- Connect your local repository to it and push:
git remote add origin https://github.com/YOUR-USERNAME/git-github-actions-demo.git
git push -u origin main
From now on, the workflow is: change files, commit with Git, and git push to send the commits to GitHub. When someone else pushes changes, git pull brings them down to you.
GitHub adds these features on top of plain Git. None of them are part of Git itself:
| GitHub feature | What it gives you |
|---|---|
| Remote hosting | A backed-up copy of every repository, reachable from anywhere |
| Pull requests | A way to propose changes, discuss them and review the code before it's merged |
| Issues and Projects | Bug tracking and planning tied to your code |
| Access control | Who can read, write or administer each repository |
| Branch protection | Rules like "every change needs a review and passing tests" |
| GitHub Actions | Automation that runs on your code (the next section) |
| GitHub Pages, Codespaces, Copilot | Hosting, cloud dev environments and AI assistance |
GitHub also isn't the only place to host Git repositories. GitLab, Bitbucket and Azure Repos do the same core job. The Git commands are identical on every one of them, because they're all hosting the same Git. If you learn Git properly, you can move between them in an afternoon.
Gotcha: Deleting a repository on GitHub doesn't delete the copy on your laptop, and deleting the folder on your laptop doesn't delete it from GitHub. They're two separate copies that you keep in sync with
pushandpull. That's exactly why GitHub works as a backup.
GitHub Actions: Automation That Runs on GitHub
GitHub Actions is GitHub's built-in automation. You describe a workflow in a YAML file inside your repository, and GitHub runs it on its own servers whenever something happens, such as a push, a pull request or a schedule.
Teams use it for CI/CD: continuous integration, which means automatically testing every change, and continuous deployment, which means automatically releasing changes that pass. But it can run almost anything, from linting your code to resizing images to posting a message in Teams.
The workflow below checks that the script still prints the right greeting on every push. Create the file .github/workflows/check.yml:
name: check
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Get the code
uses: actions/checkout@v7
- name: Check the greeting
run: |
output="$(./greet.sh Student)"
echo "$output"
[[ "$output" == "Hello, Student!" ]]
These terms show up in every workflow you'll read:
onis the trigger. This workflow runs on every push and every pull request.- A job is a group of steps that run on one machine. This workflow has one job,
test. runs-onpicks the machine, called a runner.ubuntu-latestis a fresh Linux virtual machine that GitHub creates for the job and throws away afterwards.- Steps run in order. A step either
usesa ready-made action, likeactions/checkout, which copies your repository onto the runner, or itruns shell commands. - The exit code decides the result. The last line is a Bash test. If the output matches, it returns 0 and the job passes. If it doesn't, it returns 1 and the job fails. (If that line looks unfamiliar, my Bash scripting guide explains exit codes and
[[ ]]tests.)
Commit the workflow and push it:
mkdir -p .github/workflows
# create check.yml with the content above, then:
git add .github/workflows/check.yml
git commit -m "Add greeting check workflow"
git push
To see the run:
- Open your repository on GitHub and select the Actions tab.
- Select the run called "Add greeting check workflow". It starts within a few seconds of the push.
- Open the
testjob to see each step's log, including theHello, Student!line printed by your script. - Wait for the green check mark, which means the job passed.
You can also follow it from your terminal:
gh run watch # pick the run and stream its progress
gh run list # recent runs and whether they passed
Pro tip: Look at the
uses: actions/checkout@v7line. Actions are versioned, and the version after the@matters. Pinning to a major version likev7gets you fixes without surprise breaking changes. Teams that care about supply-chain security go further and pin to a full commit SHA.
Seeing All Three Work Together
To see the three tools work together, break the script on purpose and push the change:
sed -i '' 's/Hello, /Hi there, /' greet.sh # on Linux, use sed -i without the ''
git commit -am "Change greeting wording" # Git records the change locally
git push # GitHub receives the commit
Within a few seconds, the workflow runs again. This time the output is Hi there, Student!, the test on the last line returns 1, and the run fails with a red cross. GitHub shows the failure next to the commit, emails you about it, and if this had been a pull request, it would show the failure on the pull request before anyone merged it.
Follow that chain once more, because it's the whole answer to the original question:
| Step | Tool | Where it happens |
|---|---|---|
You edit the file and run git commit | Git | Your laptop |
You run git push and the commit appears online | GitHub | GitHub's servers |
| The push triggers the workflow, which runs the test and reports the result | GitHub Actions | A runner that GitHub creates |
Fix it the same way you'd fix any change:
git restore --source=HEAD~1 greet.sh # bring back the previous version of the file
git commit -am "Restore original greeting"
git push
The next run goes green again.
Other Names That Cause the Same Confusion
Once you've separated those three, a few other names tend to get mixed in. Here's where each one fits:
| Name | What it actually is |
|---|---|
| GitHub Desktop | A graphical app that runs Git commands for you. Still Git underneath. |
GitHub CLI (gh) | A terminal tool for GitHub features like repos, pull requests and Actions runs. It doesn't replace the git command. |
| GitLab / Bitbucket / Azure Repos | Other websites that host Git repositories, like GitHub does |
| GitLab CI / Azure Pipelines / Jenkins | Other CI/CD tools that do the same job as GitHub Actions |
| GitHub Copilot | An AI coding assistant made by GitHub. Unrelated to version control. |
If you work in a Microsoft shop, you'll often meet Azure DevOps, which bundles Azure Repos (Git hosting, like GitHub) and Azure Pipelines (automation, like GitHub Actions) in one product. Same ideas, different website. I walked through building a pipeline there in Building CI/CD pipelines using Azure DevOps.
Common Beginner Mistakes
Committing secrets. Passwords, API keys and connection strings don't belong in Git. Once something is in the history, deleting the file in a later commit doesn't remove it from earlier commits, and anyone who clones the repository can find it. For workflows, store secrets under Settings > Secrets and variables > Actions and reference them as ${{ secrets.NAME }}.
Committing files that shouldn't be shared. Build output, node_modules, .env files and editor settings should be ignored. Create a .gitignore file at the root of the repository:
# .gitignore
.env
node_modules/
*.log
.DS_Store
Git will then stop offering those files in git status. Note that .gitignore only affects files that aren't committed yet. If you already committed one, remove it from Git with git rm --cached filename and commit that change.
Thinking GitHub is your only backup. It's a good off-site copy, but if you force-push over history or delete a repository, the history goes with it. For anything important, keep a second copy.
Ignoring Actions minutes on private repositories. Actions are free for public repositories on GitHub's standard runners. Private repositories get a monthly allowance of included minutes, 2,000 on the Free plan at the time of writing, and anything beyond that is billed. A workflow that runs on every push of a busy private repo can use that up faster than you'd expect. Check your usage under Settings > Billing, and see GitHub's Actions billing page for current numbers.
Learning GitHub's buttons instead of Git. The website hides a lot of what's happening. If you only ever click "Commit" in the browser, you'll be stuck the first time you hit a merge conflict on your laptop. Learn the handful of Git commands in this post first, and the website will make much more sense.
Where to Go Next
Here's the order I'd suggest to my own students:
- Get comfortable with Git locally:
init,add,commit,log,diff,restore. Do it in a scratch folder until it's boring. - Push to GitHub and work with branches and pull requests. Open a pull request against your own repository, even when you're working alone, just to practise the flow.
- Add one small GitHub Actions workflow to a project you care about, such as running its tests or a linter on every push.
- Then learn deployment: use Actions to deploy something real, like a static website or an Azure resource.
The short version stays the same, though. Git tracks changes, GitHub stores and shares them, and GitHub Actions runs automation when they change. Once you can say which one is doing the work at each step, the rest is practice.



