In the previous lesson Ana turned her folder into a repository and created the project's first commit. She has worked on it for a few more days since then, and the history of task-manager already holds several commits. The team has also published the repository on an internal server so that it can be shared.

Today Bruno joins, and he works on macOS. Bruno needs the project on his laptop, but not just any copy: he needs the files and the whole history, so that he can look up why each change was made, compare versions and, later on, contribute his own. Downloading a .zip would give him today's files and nothing else: no history, no context, no ability to collaborate.

The right tool is git clone. In this lesson we will see what it really does — which is quite a bit more than copying files — which protocols exist for reaching a remote repository and how they differ, the options that come up most in daily work (--branch, --depth, --single-branch) and, above all, when to use clone and when to use init, a classic beginner's doubt.

Contents

  1. Bruno's situation
  2. git clone in its simplest form
  3. What git clone really does, step by step
  4. Protocols: HTTPS, SSH and a local path
  5. Cloning into a directory with a different name
  6. Cloning a specific branch with --branch
  7. Shallow clones with --depth
  8. --single-branch and other useful options
  9. init versus clone: the conceptual difference
  10. Checks to run after cloning

  1. Bruno's situation

The task-manager repository is published on the company's internal server. Bruno has three possible addresses for reaching it:

https://git.example.com/team/task-manager.git         (HTTPS)
[email protected]:team/task-manager.git             (SSH)
/Volumes/shared/repos/task-manager.git                (local path, shared disk)

All three point at the same repository: a bare repository — no working tree, as we saw at the end of the previous lesson — acting as the team's central point. How Ana's repository got there, and how these addresses are managed, is the subject of module 4; here we focus on the other side of the operation: bringing it home.

Bruno already has Git installed and configured with his identity, following what we saw in module 1:

git config --global user.name
# → Bruno Salas
git config --global user.email
# → [email protected]

  1. git clone in its simplest form

Bruno moves into the folder where he keeps his projects and runs:

cd ~/Projects
git clone https://git.example.com/team/task-manager.git
Cloning into 'task-manager'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 24 (delta 6), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (24/24), 4.21 KiB | 4.21 MiB/s, done.
Resolving deltas: 100% (6/6), done.

And that is it: in a few seconds he has the complete project.

cd task-manager
ls -a
.  ..  .git  app.js  index.html  README.md  styles.css
git log --oneline
c5d9b1e (HEAD -> main, origin/main, origin/HEAD) Document installation in the README
4e7f2a9 Add task deletion to the list
8b6d3c2 Add base styles for the list
1a4c8d6 Add initial task manager structure

There is Ana's complete history, including the initial commit we created in the previous lesson and the recurring commit "Add task deletion to the list" touching app.js. Bruno has not received a photograph of the project: he has received the project and its memory.

And the working tree is clean from the very first moment:

git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

Decoding the clone output

The lines that scroll past during the download are not noise; they describe what the server is doing:

Line What it means
Enumerating objects The server works out which objects need sending
Counting objects It counts them and prepares the transfer
Compressing objects It compresses them into a packfile so that fewer bytes go over the wire
Total 24 (delta 6) 24 objects, 6 of which travel as differences against others
Receiving objects Download progress on your machine
Resolving deltas Your Git rebuilds the complete objects from those differences

That (delta 6) connects with something we mentioned in The Git Data Model: conceptually Git stores snapshots, but to store and transmit them it uses packfiles, which do compress some objects against others. It is an invisible optimisation: once Resolving deltas finishes, Bruno's disk holds exactly the same objects as Ana's.

  1. What git clone really does, step by step

A clone looks like a simple "download the folder", but it is five chained operations. Understanding them heads off an enormous amount of later confusion.

graph TD
    A["1 · Create the directory<br/>task-manager/"] --> B["2 · Create .git/ inside it<br/>(like a git init)"]
    B --> C["3 · Download ALL the objects<br/>and references from the source"]
    C --> D["4 · Register the source<br/>as the remote 'origin'"]
    D --> E["5 · Create the local branch 'main'<br/>and write its files out to the<br/>working tree"]

Step 1: create the directory

Unless you say otherwise, Git uses the last segment of the URL without the .git suffix. From https://git.example.com/team/task-manager.git comes the folder task-manager. If that folder already exists and is not empty, the clone fails:

fatal: destination path 'task-manager' already exists and is not an empty directory.

This is a deliberate safeguard: git clone never overwrites existing work.

Step 2: initialise the repository

Internally, a clone starts by doing the equivalent of git init in the destination directory. That is why the result has exactly the same anatomy we studied yesterday:

ls -F .git
branches/  config  description  FETCH_HEAD  HEAD  hooks/  index  info/  logs/  objects/  packed-refs  refs/

A few items show up that a plain git init did not produce — index, logs/, packed-refs, FETCH_HEAD — simply because here there is actual content: there are staged files, there are references to pack and a network operation has taken place.

Step 3: download the objects

This is where the important part happens. Git downloads the entire object database: every blob, every tree, every commit and every tag in the source repository, together with its references.

This is what makes Git a distributed system, as we saw in What is Git?: after the clone, Bruno's laptop holds a complete, fully functional copy of the project. He can browse the history, compare versions from a year ago or create commits with no network connection. In a centralised system such as SVN, almost any of those operations would require talking to the server.

We can verify it:

git count-objects -v
count: 0
size: 0
in-pack: 24
packed: 24
prune-packable: 0
garbage: 0
size-pack: 5

All 24 objects are there, inside a packfile (in-pack: 24).

Step 4: register the origin remote

The clone records where it came from, under the conventional name origin:

git remote -v
origin	https://git.example.com/team/task-manager.git (fetch)
origin	https://git.example.com/team/task-manager.git (push)

And it writes it into the repository's local configuration:

cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = https://git.example.com/team/task-manager.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main

origin is not a reserved word in Git: it is merely the default name clone gives the remote. You could call it central, upstream or server. The convention is so well established that it is worth sticking to.

The [branch "main"] section means the local branch main tracks origin/main. That is what lets git status tell you whether you are ahead of or behind the server. All of this — remotes, tracking branches, fetch, pull, push — is the content of module 4; here it is enough to know that the clone sets it up on its own.

Step 5: create the local branch and write out the files

Finally, Git creates a local branch matching the source's default branch (main), points HEAD at it and writes that commit's files to disk, populating the working tree and the staging area at the same time.

That last detail explains why git status comes out clean straight after a clone: all three areas — repository, staging area and working tree — hold the very same content.

  1. Protocols: HTTPS, SSH and a local path

The URL you hand to git clone determines how the data travels. These are the three cases you will meet in practice:

HTTPS SSH Local path
Form https://host/group/repo.git git@host:group/repo.git /path/to/repo.git or file:///path
Authentication Username + access token Public/private key pair Filesystem permissions
Usual port 443 22
Gets through firewalls Almost always Sometimes blocked
Asks for credentials when cloning Yes, unless the repository is public No, if the key is loaded No
Day-to-day convenience Medium (needs a credential helper) High, once set up Maximum
Typical use First contact, CI, restrictive networks A developer's daily work Backups, testing, shared disks

HTTPS

It is the most universal option because port 443 is open practically everywhere. Cloning a private repository will ask you for credentials:

git clone https://git.example.com/team/task-manager.git
Cloning into 'task-manager'...
Username for 'https://git.example.com': bruno.salas
Password for 'https://[email protected]':

One important warning: on modern platforms (GitHub, GitLab and the like) that "password" is not your account password but a personal access token. To avoid retyping it every time, use the credential.helper we configured in Initial Configuration.

SSH

Notice that the short SSH form has no :// and uses a colon to separate the host from the path:

git clone [email protected]:team/task-manager.git

It relies on a pair of cryptographic keys: the public one is registered on the server and the private one stays on your machine. Once it is set up, cloning and working never ask for a password again. It is the preferred option for daily work. Generating the keys and registering them is covered in Authenticating with Remote Repositories.

There is also an equivalent long form, which does carry :// and lets you specify a port:

git clone ssh://[email protected]:2222/team/task-manager.git

Local path

You can clone from a folder on your own disk or from a network-mounted share:

git clone /Volumes/shared/repos/task-manager.git
git clone ~/backups/task-manager.git working-copy

It is blindingly fast and needs neither network nor credentials. It has one useful quirk: when source and destination sit on the same filesystem, Git uses hard links for the objects instead of copying them, so the clone takes up almost no space. If you would rather have a genuinely independent copy:

git clone --no-hardlinks /Volumes/shared/repos/task-manager.git

And if you write the path with the file:// prefix, Git uses the same transfer machinery it would use against a remote server, which is handy for testing:

git clone file:///Volumes/shared/repos/task-manager.git

Careful when cloning from a non-bare repository. You can clone from a normal repository (straight from Ana's ~/projects/task-manager, for instance), and it works: you get the whole history. But you only get what has been committed: any changes Ana has left uncommitted in her working tree or staging area do not travel. This is a reliable source of surprises — "I cloned your repo and your last change is missing" almost always means "you had not committed it".

  1. Cloning into a directory with a different name

Just add the name you want as a second argument:

git clone https://git.example.com/team/task-manager.git manager
Cloning into 'manager'...

The repository is identical; only the folder holding it changes. This helps in three situations:

  • Avoiding collisions: you already have a task-manager folder belonging to another project.
  • Keeping two copies of the same repository, one to work in and another to consult an old version without disturbing the first. (For this particular case there is a purpose-built tool, git worktree, which you will meet in module 6.)
  • Unhelpful names: if the repository is called web, you might prefer web-client-acme.

If you want to clone into the current directory rather than a new one, use . as the destination. The directory must be empty:

mkdir task-manager && cd task-manager
git clone https://git.example.com/team/task-manager.git .

  1. Cloning a specific branch with --branch

By default a clone leaves you sitting on the source's default branch (main). With --branch (or -b) you pick another one:

git clone --branch develop https://git.example.com/team/task-manager.git
git branch --show-current
develop

Two important clarifications:

  1. The whole repository is downloaded anyway. --branch does not filter what arrives; it only decides which branch you land on. The others are still there, still reachable.
  2. It accepts tags too. Hand it a tag name and you will get the exact content of that version, but in detached HEAD state (you will not be on any branch):
git clone --branch v1.0 https://git.example.com/team/task-manager.git manager-v1
Note: switching to 'v1.0'.
You are in 'detached HEAD' state...

That is perfectly fine for inspecting a released version. Exactly what that state means and how to leave it belongs to Understanding Branches and Tagging Commits.

  1. Shallow clones with --depth

On a project with years of history, cloning the lot can mean downloading hundreds of megabytes you may not need. --depth limits how many commits come across:

git clone --depth 1 https://git.example.com/team/task-manager.git
Cloning into 'task-manager'...
remote: Enumerating objects: 6, done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), 1.83 KiB | 1.83 MiB/s, done.

Compare that with the full clone in section 2: 6 objects instead of 24. Only the latest commit has arrived.

git log --oneline
c5d9b1e (grafted, HEAD -> main, origin/main) Document installation in the README

The word grafted marks the point where the history is cut off artificially. That commit appears to have no parent, even though it does have one in the original repository.

What a shallow clone costs you

Operation Full clone --depth 1
Seeing the current files Yes Yes
Building / running the project Yes Yes
Creating new commits Yes Yes
Complete git log Yes No, only the latest
Reliable git blame Yes No
git bisect to hunt down a bug Yes No
Comparing against old versions Yes No
Download size 100 % Minimal

When to use it and when not to

Yes:

  • Continuous integration. A CI server builds and throws the copy away; the history is dead weight to it. This is by far the most common use.
  • Containers and deployment images, where every megabyte counts.
  • A one-off look at an enormous project when all you want is today's code.

No:

  • Your daily working copy. You lose blame, you lose bisect and you lose any comparison with the past — three of the reasons to use Git in the first place.

Turning a shallow clone into a full one

If you change your mind, there is no need to clone again:

git fetch --unshallow

Or fetch more depth than you currently have:

git fetch --deepen 50

Both commands belong to module 4; we mention them here so that you know the decision is reversible.

A modern note. Recent versions of Git offer partial clones (--filter=blob:none), which download the whole commit graph but fetch file contents only when they are needed. They keep log, blame and bisect working and are usually a better choice than --depth for large repositories. We will look at them in Scaling Git for Large Projects.

  1. --single-branch and other useful options

--single-branch downloads only the branch you name, ignoring the rest:

git clone --single-branch --branch main https://git.example.com/team/task-manager.git

Unlike --depth, it keeps the entire history of that branch; what it avoids is dragging in branches you do not care about. In a repository with two hundred working branches, the difference is noticeable.

An important note: --depth implies --single-branch automatically, unless you add --no-single-branch.

A round-up of the most frequent options:

Option Effect Typical use
-b, --branch <name> Lands you on that branch or tag Working on develop from minute one
--depth <n> Only the last n commits Continuous integration
--single-branch One branch only, with all its history Repositories with many branches
--no-checkout, -n Downloads but does not write out the files Preparing the repository before populating it
--bare A clone with no working tree Creating a replica to serve from
--mirror Like --bare, but an exact replica of every reference Backups, migrations
--recurse-submodules Clones the submodules as well Projects with submodules
--origin <name>, -o Gives the remote a different name When origin already means something else
--quiet, -q No progress bars Scripts

A couple of worked examples:

# Full backup of the team repository
git clone --mirror https://git.example.com/team/task-manager.git task-manager-backup.git

This creates a bare repository holding every reference from the source, not just the branches. It is the usual way to migrate a repository from one server to another.

# Cloning with the remote named "central" instead of "origin"
git clone --origin central https://git.example.com/team/task-manager.git
git remote -v
# → central	https://git.example.com/team/task-manager.git (fetch)
# → central	https://git.example.com/team/task-manager.git (push)

  1. init versus clone: the conceptual difference

This is the most common confusion at the start, and one question settles it: does the project already exist somewhere?

git init git clone
Starting point Nothing, or a folder with your own files A repository that already exists
Resulting history Empty: zero commits Complete, identical to the source's
Remote configured None origin, automatically
Initial branch The one in init.defaultBranch, not existing yet The source's default branch, already created
Working tree Whatever you already had Populated with the source's files
Needs a network No Yes (except for a local path)
One-line summary "I am starting a project" "I am joining a project"

Ana used init because the project was born with her. Bruno uses clone because the project already existed. Every person on the team will run clone once per project and per machine; init is run exactly once in the life of a project.

graph TD
    Q{"Does the project already exist<br/>in a Git repository?"}
    Q -->|No| I["git init<br/>Empty history<br/>No remote"]
    Q -->|Yes| C["git clone URL<br/>Complete history<br/>Remote 'origin' ready"]
    I --> P["First commit"]
    C --> W["Start working<br/>straight away"]

One frequent mistake deserves a mention of its own: running git init in an empty folder with the intention of "downloading" a project that already exists, and then trying to wire it up by hand. It is possible — add the remote and fetch, as we will see in module 4 — but it takes three steps where git clone takes one, and it is easy to end up misconfigured. If the project already exists, clone it.

  1. Checks to run after cloning

These four checks take ten seconds and prevent misunderstandings:

# 1. Where did this repository come from?
git remote -v
# → origin	https://git.example.com/team/task-manager.git (fetch)
# → origin	https://git.example.com/team/task-manager.git (push)

# 2. Which branch am I on?
git branch --show-current
# → main

# 3. Do I have the full history, or is this a shallow clone?
git rev-parse --is-shallow-repository
# → false

# 4. How many commits did I receive?
git rev-list --count HEAD
# → 4

And a fifth one, which matters most on a team using conditional profiles (includeIf) like the one we set up in Configuring Git:

git config user.email
# → [email protected]

Checking this before the first commit is far cheaper than fixing the authorship afterwards, which means rewriting the history.

Common Mistakes and Tips

  • Cloning inside an existing repository. Run git clone without paying attention while you are inside another project and you end up with a nested repository that confuses both Git and your colleagues. Check with pwd first, or with git rev-parse --show-toplevel.
  • Using --depth 1 for your daily working copy. You save a few seconds once and lose blame, bisect and every historical comparison for months. Keep it for CI and containers.
  • Mixing up the SSH URL with the HTTPS one. git@host:group/repo.git is SSH (no ://, with a colon); https://host/group/repo.git is HTTPS. Copy the SSH one without having keys set up and the clone will fail with Permission denied (publickey).
  • Believing that cloning also copies uncommitted work. A clone brings only what has been committed. If something is missing, it is almost always because it was never committed.
  • Expecting .gitignore to make files disappear when you clone. A clone reproduces what is in the history. If an unwanted file was committed back in the day, it will arrive all the same; ignoring it now does not take it out of the past.
  • Cloning a huge project over HTTPS on a slow network and assuming it has hung. Use git clone --progress, or add --depth if you genuinely do not need the history.
  • Tip: if a clone fails halfway through, delete the half-created folder before retrying; otherwise the second attempt fails with destination path already exists.
  • Tip: right after cloning, run git log --oneline -5 and skim the README. Two minutes there save you a round of questions to the team.

Exercises

Exercise 1: Simulate Bruno's clone with a local path

With no server and no network, reproduce the whole scenario. Starting from a repository with two commits standing in for Ana's:

  1. Create ~/practice/ana/task-manager with a README.md and an app.js, and initialise it with two commits.
  2. From it, create a bare repository at ~/practice/server/task-manager.git to act as the central point.
  3. Clone it into ~/practice/bruno/task-manager, playing the part of Bruno.
  4. Prove with commands that Bruno has: the two commits, the origin remote pointing at the bare repository, and the main branch tracking origin/main.

Exercise 2: Compare a full clone with a shallow one

Using the bare repository from the previous exercise (extend it to five commits first so that the difference shows), make two clones: one full and one with --depth 1. Then:

  1. Compare the number of objects in each.
  2. Compare the output of git log --oneline.
  3. Try running git log against a specific file in both and explain the difference.
  4. Turn the shallow clone into a full one and check that it now behaves like the other.

Exercise 3: Pick the right command

For each situation, state the exact command you would use and briefly justify why. There is a deliberate trap in the list.

  1. Carla starts today and needs task-manager on her Windows 11 machine, with the full history, for daily work.
  2. The continuous integration server must build the latest version of main on every change, as fast as possible.
  3. Ana wants to start a new project, monthly-reports, which does not exist anywhere yet.
  4. Bruno needs to look at what styles.css was like in the version tagged v1.0, without interrupting his work in his current copy.
  5. The team is moving to a new server and the whole repository must go with it, branches and tags included.
  6. Carla already has a task-manager folder holding the project as downloaded in a .zip from a colleague, and wants to "connect" it to the team repository.

Solutions

Solution to Exercise 1

Step 1 — Ana's repository:

mkdir -p ~/practice/ana/task-manager
cd ~/practice/ana/task-manager
git init
echo "# Task Manager" > README.md
git add README.md
git commit -m "Add initial task manager structure"
echo "const tasks = [];" > app.js
git add app.js
git commit -m "Add skeleton of the task logic"
git log --oneline
7d2f9a1 (HEAD -> main) Add skeleton of the task logic
1a4c8d6 Add initial task manager structure

Step 2 — the central bare repository:

mkdir -p ~/practice/server
cd ~/practice/server
git clone --bare ~/practice/ana/task-manager task-manager.git
Cloning into bare repository 'task-manager.git'...
done.

--bare creates the replica with no working tree, which is exactly what a central repository should be:

ls -F task-manager.git
# → config  description  HEAD  hooks/  info/  objects/  packed-refs  refs/

Step 3 — Bruno's clone:

mkdir -p ~/practice/bruno
cd ~/practice/bruno
git clone ~/practice/server/task-manager.git
cd task-manager

Step 4 — the three demonstrations:

# The two commits, with the same hashes as in Ana's repo
git log --oneline
# → 7d2f9a1 (HEAD -> main, origin/main, origin/HEAD) Add skeleton of the task logic
# → 1a4c8d6 Add initial task manager structure

# The origin remote points at the bare repository
git remote -v
# → origin	/home/ana/practice/server/task-manager.git (fetch)
# → origin	/home/ana/practice/server/task-manager.git (push)

# The main branch tracks origin/main
git status -sb
# → ## main...origin/main

git config branch.main.remote     # → origin
git config branch.main.merge      # → refs/heads/main

The hashes matching Ana's repository exactly is no coincidence: as we saw in The Git Data Model, the hash derives from the content, so copying objects between repositories preserves the identifiers. That is the foundation that lets Git synchronise different machines without ambiguity.

Solution to Exercise 2

First we extend Ana's history and carry it over to the bare repository (the mechanics of pushing changes belong to module 4, so here we solve it by cloning again):

cd ~/practice/ana/task-manager
for n in 3 4 5; do echo "line $n" >> app.js; git commit -am "Change number $n"; done
rm -rf ~/practice/server/task-manager.git
git clone --bare . ~/practice/server/task-manager.git

The two clones:

cd ~/practice
git clone ~/practice/server/task-manager.git full
git clone --depth 1 file://$HOME/practice/server/task-manager.git shallow

(We use file:// because --depth has no effect on a direct local path: Git optimises that case by copying or linking the objects whole.)

1. Number of objects:

git -C full count-objects -v | grep in-pack
# → in-pack: 17

git -C shallow count-objects -v | grep in-pack
# → in-pack: 4

2. The history:

git -C full log --oneline
# → e9a2c5f (HEAD -> main, origin/main, origin/HEAD) Change number 5
# → b3d7f1c Change number 4
# → 5a8e2b9 Change number 3
# → 7d2f9a1 Add skeleton of the task logic
# → 1a4c8d6 Add initial task manager structure

git -C shallow log --oneline
# → e9a2c5f (grafted, HEAD -> main, origin/main) Change number 5

3. History of a single file:

git -C full log --oneline -- app.js
# → e9a2c5f Change number 5
# → b3d7f1c Change number 4
# → 5a8e2b9 Change number 3
# → 7d2f9a1 Add skeleton of the task logic

git -C shallow log --oneline -- app.js
# → e9a2c5f Change number 5

The difference is not cosmetic: in the shallow clone the file appears to have sprung into existence, complete, in the last commit. Any investigation into when a line was introduced — git log, git blame or git bisect — will give a false answer. That is why --depth is for building, not for investigating.

4. Turning it into a full clone:

cd ~/practice/shallow
git rev-parse --is-shallow-repository      # → true
git fetch --unshallow
git rev-parse --is-shallow-repository      # → false
git log --oneline | wc -l                  # → 5

grafted is gone and the history matches that of the full clone.

Solution to Exercise 3

1. Carla joins:

git clone [email protected]:team/task-manager.git

A plain, full clone. This is her daily working copy, so no --depth: she will need blame and the history. SSH if she has keys set up; HTTPS if she does not yet.

2. Continuous integration server:

git clone --depth 1 --branch main https://git.example.com/team/task-manager.git

This is the textbook case for a shallow clone: it builds and discards, the history adds nothing and the download is kept to a minimum. HTTPS with a token is the norm in CI because it avoids managing SSH keys.

3. A new project:

cd ~/projects
git init monthly-reports

There is nothing to clone: the project is born here. git init <name> creates the folder into the bargain.

4. Inspecting version v1.0 without disturbing current work:

git clone --branch v1.0 https://git.example.com/team/task-manager.git ~/review-v1

A second clone in another folder under another name leaves his working copy untouched. It will sit in detached HEAD, which is fine for reading. (A neater alternative he will meet in module 6: git worktree add.)

5. Server migration:

git clone --mirror https://git.example.com/team/task-manager.git task-manager.git

--mirror is the right option here, not plain --bare: it replicates every reference — branches, tags and remote references — and not just the local branches. It is the standard way to move a repository wholesale between servers.

6. The trap. Here you must not clone over the existing folder, and in fact Git would not let you: git clone demands an empty or non-existent directory. But the underlying problem is a different one: Carla's folder came from a .zip, so it has no history and no relationship whatsoever with the team repository. Wiring it up by hand would only breed conflicts and confusion.

The right answer is to set that folder aside and clone properly:

mv task-manager task-manager-zip-old          # just in case
git clone [email protected]:team/task-manager.git

If Carla had made changes in the .zip copy, she copies them by hand into the fresh clone and commits them there as ordinary changes. The general rule: a folder downloaded as a .zip is not a repository and git init does not turn it into one; to join an existing project, you clone.

Conclusion

Bruno is now part of the project. In this lesson we have seen that:

  • git clone does five things, not one: it creates the directory, initialises it, downloads the whole object database, registers the source as the remote origin, and creates the local branch, writing its files out to the working tree.
  • A clone brings the complete history, and that is the essence of the distributed model: Bruno can browse, compare and commit with no network.
  • There are three common protocols: HTTPS (universal, with a token), SSH (comfortable day to day, with keys) and a local path (instant, for copies and testing). You can tell them apart at a glance from the shape of the URL.
  • You can choose the directory name, the target branch with --branch and how much history with --depth.
  • Shallow clones are excellent for CI and terrible for working, because they break log, blame and bisect. The decision is reversible with git fetch --unshallow.
  • init and clone answer different questions: init when the project is born with you, clone when you join one that already exists.
  • A clone brings only what has been committed. Anything left uncommitted at the source stays behind.

Ana and Bruno each have their own repository now: one created hers, the other cloned his. From here on, both of them do exactly the same thing every single day: edit files, decide which changes belong together and record them in the history.

That cycle — edit, stage, commit — is Git's heartbeat and the subject of the next lesson, The Basic Git Workflow. There we will set in motion the three areas you have known since module 1, follow the complete life cycle of a file from the moment Git knows nothing about it until it is committed, and learn to read git status — in both its long and its short form — as the compass that tells you, at any moment, where you stand.

Mastering Git: From Beginner to Advanced

Module 1: Introduction to Git

Module 2: Basic Git Operations

Module 3: Branching and Merging

Module 4: Working with Remote Repositories

Module 5: Advanced Git Operations

Module 6: Git Tools and Techniques

Module 7: Collaboration and Workflow Strategies

Module 8: Git Best Practices and Tips

Module 9: Troubleshooting and Debugging

Module 10: Git in the Real World

© Copyright 2026. All rights reserved