Skip to content

Your first repository

docs.scrimba.com

There are two ways you usually end up here. Either you have a project folder already, a weather-app you have been building locally, and you want Git to start recording its history. Or someone else already built the project, it lives on GitHub, and you want your own working copy on your machine. Both start with three small commands, and by the end of this chapter you will have used all three for real. First, though, a check that takes ten seconds: making sure Git is on your machine at all.

Do you have Git installed?

Everything in this handbook happens in the terminal, so the first stop is getting one open. A terminal is an app where you type commands as text and programs reply in text. It is already on your computer:

  • macOS: the app is called Terminal. Press Cmd+Space, type "terminal", and press Enter.
  • Windows: open PowerShell for now (search "powershell" in the Start menu). Installing Git below also adds Git Bash, a terminal built for exactly this, and either one runs the same Git commands.
  • Linux: look for an app named Terminal or Console; Ctrl+Alt+T opens it on many distributions.

Git itself is a command-line program: it has no window of its own, and you use it by typing commands that start with the word git and reading what it prints back. That is also how to read every code block in this handbook: the line starting with $ is the command you type (without the $ itself), and the lines below it are Git's reply.

So, the check. Type this into your terminal and press Enter:

bash
$ git --version
git version 2.45.1

A version number back means Git is installed and you are set. Your number will likely differ from this one, and that is fine. If you instead see "command not found" or "git is not recognized", Git is not on your machine yet, and installing it is a one-time job:

  • macOS: running git --version usually opens a dialog offering to install Apple's Command Line Tools. Accept it, and macOS installs Git for you.
  • Windows: download Git for Windows from git-scm.com/downloads and run the installer. The defaults are all reasonable choices, and it installs Git Bash along the way.
  • Linux: install the git package with your distribution's package manager, for example sudo apt install git on Ubuntu and Debian.

Once the install finishes, close your terminal, open a fresh one, and run git --version again. A version number means you are done with setup for good; nothing in the rest of this handbook needs installing.

The version number matters a little more than it looks. This handbook writes the modern verbs git switch and git restore, which arrived in Git 2.23 in 2019, so a machine with a very old preinstalled Git can hit "not a git command" on examples that are correct. Any Git from the last few years has them; if yours is older than 2.23, update it from the same places listed above.

You will also meet graphical Git tools: GitHub Desktop, the Git panel in VS Code, the built-in support in most editors. All of them are front ends that run this same Git program underneath. Learning the commands first pays off there too, because every button in those tools maps onto a command you already understand.

Git is a single self-contained program, not a service. Nothing runs in the background, nothing watches your folders, and there is no account to sign into: every command starts, reads or writes files inside the repository, prints its answer, and exits. That is also why all of it works offline. Run which git (or where git on Windows) to see exactly where the program lives on disk.

One platform quirk worth knowing: on macOS, Apple ships its own build of Git with the Command Line Tools, usually a version or two behind the latest release on git-scm.com. For everything in this handbook, and nearly everything in daily work, that gap does not matter.

JunoDo you have Git installed? Git is a program you talk to by typing commands into a terminal, and git --version tells you whether it is on your machine: a version number means you are set, and "command not found" means install it from git-scm.com or your system's installer. You only ever do this part once. Setup is the least fun part of any handbook, so well done getting through it!
JunoDo you have Git installed?git --version settles the install question in one line. Anything reasonably recent works, though the switch and restore verbs this handbook uses need Git 2.23 or newer, so update if you are behind that. GUI tools like GitHub Desktop run this same program underneath, which means everything you learn here transfers to them for free.
JunoDo you have Git installed? Git is one local program with no daemon and no account: it runs when you type, touches files in the repository, and exits, which is why every bit of it works offline. which git shows you the binary. Apple's bundled build trails the latest release by a version or two, and in fourteen years that gap has cost me nothing.

Turning a folder into a repository

Open a terminal and move into your project folder with cd (short for "change directory"), then run one command, git init:

bash
$ cd weather-app
$ git init
Initialized empty Git repository in /Users/mara/projects/weather-app/.git/

That folder is now a repository: a project Git watches, ready to record snapshots of it as you work. git init does the same thing every time. It looks for a hidden .git folder, creates one if it is missing, and from that point on the folder is under Git's watch.

A new repository's default branch is named main. If you land in an older tutorial, an older repository, or a course recorded a few years back, you will see master used for the exact same thing: it is the same first branch under an older name. This handbook always uses main.

What is a branch?

A branch is a separate line of history for your commits to land on, and main is the one every new repository starts with. Branches covers creating and switching between them.

git init does not care whether the folder is empty. Run it inside weather-app with an index.html and a src/ folder already sitting there, and Git starts tracking that project from wherever it stands; none of the existing files change. Running git init a second time in the same repository is harmless too. Git notices the .git folder already exists and reinitializes it in place without touching any history you already have, so running it again out of habit costs you nothing.

git init does one thing: it creates the .git folder, unpacked in detail later in this chapter. Everything about the repository, its history, its settings, its refs, lives inside that folder from the moment init creates it. The files you see and edit in the project are a working copy of what is tracked, and the .git folder is the repository itself.

JunoTurning a folder into a repositorygit init turns any folder into a Git repository, ready for Git to start tracking it. Run it once inside a project folder and you are set, and running it again later does no harm. New repositories default to a branch called main, though older ones you find out in the wild are often called master for the same thing.
JunoTurning a folder into a repositorygit init works in an empty folder or one already full of files, and running it again on a repo you already set up does no damage since Git recognizes the .git folder is already there. Default branch name is main; expect master in anything older.
JunoTurning a folder into a repositorygit init only creates the .git folder, which is the actual repository. Your working files are a checkout of what that folder tracks. Hold onto that split between your working files and the .git folder that tracks them.

Telling Git who you are

Before your first commit, Git wants to know who is making it. Set two values once, and Git remembers them for every commit you make on this machine:

bash
$ git config --global user.name "Mara Chen"
$ git config --global user.email "[email protected]"

Every commit you create gets stamped with that name and email. Skip this step, and Git falls back to something guessed from your computer's username and hostname, so your commits carry an identity you never chose.

Set your name and email before your first commit. Commit first and set them after, and the mistake gets baked into that commit's history. Worse, some hosts (GitHub included) match commits to your account by email, so a commit made under the wrong address or a guessed one shows up as an anonymous stranger's work instead of yours.

The --global flag sets a config scope: --global applies everywhere on your machine, while --local applies only to the repository you are standing in when you run it. That lets you layer settings. Your global email covers every repository by default, and a --local override in one specific repo takes priority over it there and nowhere else, useful when a work project needs a different address than your personal projects:

bash
$ cd weather-app
$ git config --local user.email "[email protected]"
$ git config user.email
[email protected]

Running git config user.email with no scope flag reads whichever value actually applies here: the local one if you set it, the global one otherwise.

Both scopes are text files Git reads in a fixed order. The global one lives in your home folder at ~/.gitconfig; the local one lives inside the repository's own .git folder, at .git/config. Git reads local settings first and lets them override global ones, which is the whole layering mechanic, laid out in plain text files you can open and read yourself.

JunoTelling Git who you aregit config --global user.name and git config --global user.email set the name and email Git stamps on every commit you make. Set them before your first commit, because a commit made before you set your email gets attributed to a guessed identity, and a host like GitHub may not connect it to your account at all. Do it once and every repository on your machine remembers it.
JunoTelling Git who you are--global applies to every repository on your machine, and --local overrides it for the current repo only, useful for splitting a personal email from a work one. Local settings win when both are set, and git config user.email tells you which value is actually active in a given repo.
JunoTelling Git who you are Config scopes are layered text files: global lives at ~/.gitconfig, local lives at .git/config inside the repo, and local wins whenever both set a value. Skip setting your email and Git falls back to a guessed identity built from your username and machine name, which is why a stray commit under a strange name almost always traces back to a missing user.email.

Copying an existing project with git clone

Sometimes the project already exists somewhere else, and you want a working copy of it on your machine. git clone does that in one command:

bash
$ git clone https://github.com/octocat/Hello-World.git
Cloning into 'Hello-World'...
remote: Enumerating objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Receiving objects: 100% (13/13), done.

Git creates a new folder named Hello-World, downloads the project's full history into it, and places its files in the folder so you can start reading or editing right away. There is no separate git init step needed. Cloning sets up the repository for you as part of downloading it.

Reach for git clone when the project already exists somewhere and you want a connected copy of it. Reach for git init when you are starting something brand new that does not exist anywhere yet. Cloning also wires up a connection back to where you cloned from, under the name origin, something init alone never does; that connection is what later chapters use to send and receive commits.

Cloning brings down the project's entire history, every commit it has ever had, and populates the whole .git folder on your machine, where git init would leave it empty. A clone of a project with years of history can take a moment for exactly this reason, even though what you see afterward looks like a snapshot of the newest files.

JunoCopying an existing project with git clonegit clone <url> downloads someone else's repository, whole history included, into a new folder named after the project. Reach for it when the project already exists somewhere; reach for git init when you are starting one from scratch. Once cloning finishes you have a full working copy, ready to look through or add to.
JunoCopying an existing project with git clone Clone when a project already lives somewhere and you want a connected copy; init when nothing exists yet. Cloning wires up the connection back to where you cloned from automatically, under the name origin, which init on its own never sets up.
JunoCopying an existing project with git clone Clone recreates the whole .git folder with every commit the project has ever had. That includes the full history, which is why an older project can take a moment to clone even though you only see its current files afterward.

What's inside the hidden .git folder

Every repository, whether you got there with git init or git clone, has a hidden folder named .git sitting at its root. It is hidden by default, so ask the terminal for the full listing with ls -a (ls lists a folder's contents, and -a includes hidden entries) to see it sit alongside your normal project files:

bash
$ ls -a
.  ..  .git  README.md  src

That folder is the real repository. It holds every commit you have made, your branches, and the config settings from the section above. Delete the .git folder and the project loses its whole history, turning back into an ordinary folder Git no longer tracks. Everything else in the project is a working copy of what .git holds.

Look inside and you will find a few recognizable pieces: a config file (the local settings from the section above), a HEAD file, and folders named objects and refs. You do not need to open or edit any of these by hand, but recognizing the names helps when one of them turns up in an error message or a search result.

A few of those names are worth knowing properly. The objects folder is the repository's object database: every version of every file and every commit you have made, compressed and stored by the content itself rather than a filename. The refs folder holds your branches, each one a small file pointing at a commit id. HEAD is a single file recording which branch you currently have checked out. config is the local settings file covered above.

None of this is something you edit by hand day to day. Seeing your whole history sitting there as ordinary files, rather than hidden away on a server somewhere, explains why a clone gives you full history offline, and why deleting .git does not tidy anything up: it erases every commit the project ever had.

JunoWhat's inside the hidden .git folder Every repository has a hidden .git folder at its root, and that folder is the real repository: your whole history and its settings live there. Run ls -a inside a project to see it, since it is hidden by default. Never delete it unless you actually want to erase the project's whole history, since deleting it turns the folder back into a plain folder Git no longer tracks.
JunoWhat's inside the hidden .git folder Inside .git you will recognize a config file (your local settings), a HEAD file, and objects and refs folders. You will not touch these by hand day to day, but the names show up in error messages and Git documentation. Cloning copies this entire folder, which is why a clone arrives with full history rather than only the newest files.
JunoWhat's inside the hidden .git folderobjects is the repository's object database, holding every version of every file and commit, addressed by content rather than filename. refs holds your branches as plain files pointing at a commit id, and HEAD records which one you have checked out. Nothing there needs hand editing, but seeing it as ordinary files on disk is the reason cloning gives you full offline history, and the reason deleting .git erases everything instead of merely cleaning up.

If the terms repository and commit still feel fuzzy, What is Git covers the mental model these commands build on, and the Glossary has a short definition for every piece of vocabulary in this chapter. Once your identity is set and you have a repository to work in, The commit loop covers the everyday cycle of editing, staging, and committing you will use constantly from here on.