Creating and Cloning Repositories
git init turns an ordinary directory into a repository by creating a .git/ folder; git clone <url> copies an existing remote repository plus its full history onto your machine. Between them they cover the only two ways a project ever starts for you: from nothing, or from someone else's repo.
The two paths leave you in different states. A cloned repo already knows where it came from — the remote is wired up and named origin. A freshly initialized repo knows nothing about any remote until you tell it, which is the single step people most often forget before their first push fails.
Initializing a New Repository
git init writes a .git/ directory holding the object database, the refs, an empty index, and a config file. Nothing else changes — your files are untracked until you stage and commit them. The repository exists, but its history is empty until the first git add and git commit create the root commit, the one commit with no parent.
Where you run git init matters. It applies to the current directory and everything beneath it, so run it at the top of the project, not inside a subfolder you happen to be sitting in. The branch you land on is whatever init.defaultBranch is set to; on older Git that is master, which is why setting it to main globally avoids a mismatch with the remote later.
Cloning an Existing Repository
git clone <url> does several things in one command: it creates the directory, downloads the entire object database including all history and branches, checks out the default branch into a working tree, and records the source under the remote name origin. That last part is the difference between clone and a manual setup — the remote and the remote-tracking branches are configured for you.
Because clone copies all history by default, a repository with a long or binary-heavy past can take minutes and gigabytes. When you only need the current tip — a CI build, a one-off inspection — git clone --depth 1 grabs just the latest commit and skips the rest, trading away the ability to browse history for a much faster, smaller checkout.
Remotes and Origin
A remote is a named URL Git can fetch from and push to. Clone creates one called origin automatically; git remote -v prints the names and URLs so you can confirm what you are actually pointed at. For a repo you started with git init, there is no remote until you add one: create the empty repository on the host, then git remote add origin <url> and git push -u origin main to publish and set up tracking in one move.
HTTPS vs SSH URLs
The protocol in the URL decides how you authenticate. HTTPS URLs (https://github.com/owner/repo.git) authenticate with a personal access token, usually cached by a credential manager. SSH URLs (git@github.com:owner/repo.git) authenticate with a key pair you have registered with the host. They reach the same repository; what differs is what must be configured, and mixing them up — adding an SSH remote with no key loaded, or an HTTPS remote with no token — is the usual cause of an auth failure on the first push.
Bare vs Working Repositories
An ordinary repository has a working tree you edit. A bare repository, created with git clone --bare or git init --bare, has no working tree at all — it is just the .git contents, meant to be pushed to and pulled from rather than worked in. Servers host bare repos for exactly this reason: there is no checked-out copy to get out of sync with the refs people are pushing.
- Running
git initinside a directory that is already part of a repository, creating a nested repo that confuses every later command about which.gitapplies. - Cloning a multi-gigabyte repository with full history over a slow link for a CI build when
--depth 1would have fetched only the tip and finished in seconds. - Adding a remote with the wrong protocol — an HTTPS URL when only an SSH key is configured — and hitting an authentication failure on every push.
- Initializing a repo on
masterwhile the remote defaults tomain, then fighting branch mismatches the first time you push. - Assuming a fresh
git initrepo already has a remote and runninggit pushwith nothing configured, getting "No configured push destination."
- Set
git config --global init.defaultBranch mainsogit initand the remote agree on the branch name from the start. - Use
git clone --depth 1for CI and throwaway builds to cut clone time and disk when history is not needed. - Run
git remote -vimmediately after cloning or adding a remote, before your first push, to confirm the URL and protocol. - Prefer SSH URLs with a registered key for repositories you push to often, to avoid repeated token prompts.
- For a new local repo, create the matching empty remote first, then
git remote add origin <url>andgit push -u origin mainto set upstream tracking in one step.
hg init / hg clone, near-identical semanticsSubversion svnadmin create server-side plus svn checkout, not a full-history copyPerforce p4 clone (DVCS-style) or workspace mappingFossil fossil init / fossil clone into a single SQLite fileKnowledge Check
What does git clone set up that git init followed by git remote add does not do for you automatically?
- Downloads the full history and checks out the default branch, with
originand remote-tracking branches already configured - Nothing — the two paths leave the repository in an identical state, with the same objects and the same checked-out branch
- Compresses the working tree into a packed format to save disk space on the freshly created clone
- Creates the matching empty repository on the remote host for you before the first push
A CI job needs only the latest commit to run a build. What does git clone --depth 1 trade away to be faster?
- Access to the repository's history — you get only the tip, so
git logand history-based operations are unavailable - The checked-out working tree, leaving a bare repository with no files on disk that a build step could compile from
- The configured
originremote, so you cannot fetch updates or pull later from the server - Nothing — a shallow clone holds the identical history, just stored compressed
Your first push fails with an authentication error right after adding a remote. What is the likely cause?
- The remote's protocol does not match what is configured — an SSH URL with no key loaded, or an HTTPS URL with no token
- The repository was cloned shallow with
--depth 1, so it is not allowed to push any of its commits back to the server - Git always requires a discarded second push to authenticate the rejected first one
- The local default branch is named
mainwhile the remote was initialized expectingmasterinstead
Why do servers host a bare repository (--bare) rather than an ordinary one?
- It has no working tree to fall out of sync with the refs people push, so it is safe to receive pushes
- A bare repo stores its history as plain line-by-line diffs rather than objects, which takes far less room on a server
- Only bare repositories can be configured with more than one remote at a time
- Bare repositories skip authentication checks entirely, simplifying server setup
You got correct