skip to content

Remotes and Collaboration

You will learn what a remote-tracking ref is, how fetch, pull and push actually update it, and why pull --rebase produces different history than plain pull. This is where interviewers probe your understanding of the fork-and-pull-request model most teams work in.

part ofGitoverview, primer and where to startread it →
on this pageshow

questions

page 1 of 2

In Git, what does cloning with --depth 1 actually download, and what is missing?

level: juniorimportance: must knowfreq 72%

answer

  1. Think about how much of the graph arrives
  2. One branch, one commit, nothing older
  3. Git writes down where history stops
  4. A dotfile inside .git names the boundary
  5. --depth also implies --single-branch

basics

~20 s

git clone --depth 1 downloads only the tip commit of a single branch plus the trees and file contents needed to check it out. Older history and other branches are absent, so log and blame reach back one commit.

solid answer

~40 s

`git clone --depth 1 <url>` asks the server for a **shallow** clone: the tip commit of one branch, the trees and blobs needed to check it out, and nothing older. Git records the truncation boundary in `.git/shallow` and treats the commits listed there as if they had no parents, which is why `git log` shows a single entry. `--depth` also implies `--single-branch`, so only one branch is fetched and the `remote.origin.fetch` refspec written into `.git/config` is narrowed to it; `--branch <name>` picks which branch, and `--no-single-branch` asks for every branch's tip at that depth. It is the standard trick for CI jobs that only need to build the current tree, because it turns a multi-minute clone into seconds.

code

bash · 8 lines
bash
git clone --depth 1 https://example.com/big/repo.git
cd repo
git log --oneline
# 9f1c2ab (grafted, HEAD -> main, origin/main) Fix login redirect
cat .git/shallow
# 9f1c2ab3e0d5b7c8f2a1d4e6b9c0a3f5d7e8b1c2
git config --get remote.origin.fetch
# +refs/heads/main:refs/remotes/origin/main

go deeper

for a junior

Be ready to say what --depth 1 gives you: one commit on one branch, enough to build. Know that git log will show a single entry and that this is expected, not a broken clone.

for a middle

Explain the mechanics: the shallow boundary file, commits treated as parentless, and that --depth implies --single-branch and narrows the fetch refspec written into the config.

for a senior

Show judgment about which pipeline steps a shallow checkout breaks — tag-based versioning, merge-base diffs, blame — and how you would detect that failure mode before it reaches a release job.

for a principal

Own the policy: a default clone depth for the whole CI estate, with a documented escape hatch for jobs that legitimately need history, so teams do not each rediscover the breakage.

## What "shallow" means A normal clone copies the complete commit graph: every commit reachable from the remote's refs, plus all the trees (directory listings) and blobs (file contents) those commits reference. For a long-lived project that is often hundreds of megabytes of history nobody on the machine will ever read. `git clone --depth <n> <url>` asks the server to send only the last `<n>` commits of the branch being cloned, plus the objects needed to check that state out. The result is a **shallow repository**: an ordinary Git repository in every other respect, but with a deliberately truncated history. ## How Git records the truncation The file `.git/shallow` holds the commit IDs that sit on the boundary. Git treats each of those commits as if it had no parents, so history simply stops there. Nothing is corrupt and nothing is lying about content — the commits you do have are byte-for-byte the real ones, with their real IDs. Only the ancestry beyond the boundary is unavailable, because those objects were never transferred. This is why `git log --oneline` in a `--depth 1` clone prints exactly one line, and why `git log --graph` shows no ancestry. ## What --depth implies about branches `--depth` turns on `--single-branch` automatically. The practical consequences: - Only one branch is fetched — the one given with `--branch <name>`, or the remote's default branch if you did not say. - The `remote.origin.fetch` line in `.git/config` is narrowed to that single branch instead of the usual `+refs/heads/*:refs/remotes/origin/*`, so later `git fetch` calls keep fetching only that branch until you widen it. - Only tags that point into the history you received come along; `--no-tags` skips even those. If you want the tips of all branches but still no deep history, `git clone --depth 1 --no-single-branch <url>` does that. ## Variants of the depth request `--depth <n>` is a commit count, but Git can also truncate by other criteria: `--shallow-since=<date>` keeps commits newer than a date, and `--shallow-exclude=<ref>` keeps history that is not already reachable from the named ref or tag. All three produce the same kind of shallow repository with a `.git/shallow` boundary. ## What it costs Anything that needs ancestry degrades. `git log` and `git blame` stop at the boundary. `git describe` cannot find a tag if the tag is older than the boundary. `git merge-base` may not find a common ancestor with another branch, so merges, rebases and "diff against the target branch" style commands can fail or produce nonsense. `git bisect` can only search the commits present. A shallow clone is also not a substitute for a **partial clone**. Shallow truncates the *history* (fewer commits); a partial clone (`--filter=blob:none`) keeps the whole commit graph but omits *file contents* until something asks for them. They solve different problems and can be combined. ## When to use it Use `--depth 1` when the job only needs the current source tree: compiling, running a linter over the checkout, building a container image, publishing a static site. Avoid it when the job needs history: tag-derived version numbers, changed-file detection against a base branch, blame-driven ownership checks, or anything that merges or rebases. The shallowness is not permanent — `git fetch --unshallow` refills the history later, at the cost of the download you were trying to avoid.

  • Does --depth 1 also limit which branches you get?
    Yes. `--depth` implies `--single-branch`, so Git fetches only the branch you named with `--branch` (or the remote's default) and narrows `remote.origin.fetch` to it. Later fetches keep that narrow refspec. Pass `--no-single-branch` if you want every branch's tip at the same depth.
  • Can you commit and push from a shallow clone?
    Yes — recent Git allows both fetching and pushing from a shallow repository, and the client tells the server where its history stops. The risk is not the transport but the graph: new commits sit on top of a truncated ancestry, so anything needing a real merge base with an older branch can still misbehave.
  • What exactly is in .git/shallow?
    A list of commit IDs that Git treats as parentless. They form the boundary of the truncated history; `git log` renders them with the marker `grafted`. Deepening or unshallowing rewrites this file as more ancestry arrives.

It is like buying only the latest issue of a magazine instead of the bound archive: the issue is genuine and complete, but you cannot look up what happened three years ago.

saying these in an interview costs you the question

  • Thinks --depth 1 only drops old file versions, keeping commits
  • Says a shallow clone repairs its own history over time
  • Assumes --depth 1 still fetches every branch
  • Believes git log is just faster, not truncated
  • Uses shallow and partial clone as synonyms

context

open as a page

What is the difference between git fetch and git pull?

level: juniorimportance: must knowfreq 88%

basics

~20 s

git fetch downloads new objects and updates remote-tracking refs such as origin/main, leaving your branch and working tree untouched. git pull runs that same fetch and then immediately integrates the result into your current branch by merging or rebasing.

open as a page

In a forked repository, what do the Git remotes named origin and upstream conventionally point to?

level: juniorimportance: must knowfreq 68%

basics

~10 s

By convention origin is your own fork, the copy you can push to, and upstream is the original project you forked from and normally only fetch from. Git gives neither name any special meaning.

open as a page

In Git, how do you delete a remote branch, and what does git push origin :feature mean?

level: juniorimportance: must knowfreq 65%

basics

~20 s

Use git push origin --delete feature. The older equivalent, git push origin :feature, is a refspec with an empty source: pushing nothing onto the destination ref deletes it. Both remove only the remote branch, never your local one.

open as a page

In Git, what does git remote add origin <url> actually change in your repository?

level: juniorimportance: must knowfreq 55%

basics

~20 s

It only edits .git/config, adding a remote section with a url and a default fetch refspec. No network call happens and no objects arrive until you run git fetch, and the name origin is purely local.

open as a page

In Git, what does the -u flag do in git push -u origin main?

level: juniorimportance: must knowfreq 70%

basics

~20 s

-u (--set-upstream) records origin/main as the upstream of the local branch main in the repository's own config, so later bare git push, git pull and git status know which remote branch to use and compare against.

open as a page

In Git, how do https:// and ssh:// remote URLs differ in how they authenticate?

level: juniorimportance: must knowfreq 74%

basics

~20 s

An https:// remote authenticates per request with a username and a token, supplied by a credential helper over a TLS connection. An ssh:// remote shells out to ssh, which authenticates with a key pair; the server then runs git-upload-pack or git-receive-pack over that channel.

open as a page

Why does git pull sometimes create a merge commit you did not ask for?

level: middleimportance: must knowfreq 62%

basics

~20 s

Because pull's second half is a merge by default. If you have local commits and the remote branch has moved on, the histories have diverged, so instead of fast-forwarding Git joins them with a merge commit. Setting pull.rebase or pull.ff=only changes that.

open as a page

How do you bring your fork's main branch up to date with the upstream repository in Git?

level: middleimportance: must knowfreq 66%

basics

~10 s

Fetch the upstream remote, switch to your local main, fast-forward it onto upstream/main, then push that to your fork. Keeping main free of your own commits is what makes the fast-forward always succeed.

open as a page

In Git, why is a push rejected as non-fast-forward, and what should you do about it?

level: middleimportance: must knowfreq 85%

basics

~20 s

The remote refuses because the branch's current commit is not an ancestor of the commit you are pushing, so accepting it would drop commits. Fetch, integrate the remote work with a merge or rebase, then push again.

open as a page

What does the refspec +refs/heads/*:refs/remotes/origin/* mean in Git?

level: middleimportance: must knowfreq 42%

basics

~20 s

It is the default fetch rule: take every branch under refs/heads/ on the remote and store it locally under refs/remotes/origin/, with the leading plus allowing those local copies to be updated even when the change is not a fast-forward.

open as a page

In Git, what is git status comparing when it says your branch is ahead of origin/main?

level: middleimportance: must knowfreq 80%

basics

~20 s

git status compares your branch tip with the locally stored remote-tracking ref refs/remotes/origin/main, the branch's configured upstream. Ahead and behind are commit counts on either side of their merge base, computed offline from a snapshot last refreshed by fetch.

open as a page

What does Git's credential.helper do, and how do the store, cache, and keychain helpers differ?

level: middleimportance: must knowfreq 56%

basics

~20 s

credential.helper names a program Git asks for a username and secret before prompting. store writes them in plaintext to ~/.git-credentials, cache keeps them in a short-lived in-memory daemon, and osxkeychain or manager delegate to an OS-backed secure store.

open as a page

A CI job cannot clone a private repository over SSH. How do you diagnose it at the Git level?

level: seniorimportance: must knowfreq 50%

basics

~20 s

Reproduce the exact command with verbose SSH via GIT_SSH_COMMAND="ssh -v", then check in order: which key was offered, whether the agent is reachable, key file permissions and passphrase, the host key in known_hosts, and whether the key has write as well as read access.

open as a page

How does a Git partial clone with --filter=blob:none differ from a shallow clone?

level: middleimportance: should knowfreq 42%

basics

~20 s

A shallow clone truncates history to a few commits. A partial clone with --filter=blob:none keeps the entire commit and tree graph but omits file contents, downloading each blob lazily from the remote the first time something actually needs it.

open as a page

Which Git operations break in a shallow clone, and how do you restore the full history?

level: middleimportance: should knowfreq 52%

basics

~20 s

Anything needing ancestry degrades in a shallow clone: log, blame, describe, bisect and merge-base against a long-diverged branch. Run git fetch --unshallow to download the missing history, or git fetch --deepen=N to extend it gradually.

open as a page

In Git, what is FETCH_HEAD and when would you use it directly?

level: middleimportance: should knowfreq 42%

basics

~20 s

FETCH_HEAD is a file in the .git directory that records the refs downloaded by the most recent git fetch, one line per ref, with the branch fetched for merging marked first. It lets you merge or inspect a fetch that has no remote-tracking ref of its own.

open as a page

What does git fetch --prune do, and why do deleted branches linger without it?

level: middleimportance: should knowfreq 40%

basics

~20 s

git fetch --prune deletes remote-tracking refs under refs/remotes/origin whose branch no longer exists on the remote. Without it a plain fetch only creates and updates those refs, never removes them, so branches deleted upstream keep showing up locally forever.

open as a page

In Git, why don't tags travel with a normal git push, and what does --follow-tags do?

level: middleimportance: should knowfreq 40%

basics

~20 s

A push updates only the refs named by its refspec, which for a branch push means refs/heads/… — refs/tags/… is never implied. git push --follow-tags additionally sends annotated tags that are reachable from the pushed commits and missing on the remote.

open as a page

In Git, what does push.default=simple do differently from current and upstream?

level: middleimportance: should knowfreq 42%

basics

~20 s

push.default decides what a bare git push sends. simple, the default, pushes the current branch to a same-named remote branch and refuses when the upstream has a different name; upstream pushes to the upstream whatever it is called; current ignores names entirely.

open as a page

In Git, what does git push origin HEAD:refs/heads/release do?

level: middleimportance: should knowfreq 40%

basics

~10 s

It pushes the commit your HEAD points at to the branch release on origin, creating it if absent, regardless of what your local branch is called. HEAD is the source, refs/heads/release the destination ref.

open as a page

In Git, what is a stale remote-tracking branch and what does git remote prune do?

level: middleimportance: should knowfreq 28%

basics

~10 s

A stale remote-tracking ref is one like origin/feature whose branch no longer exists on the remote; fetching never deletes it. git remote prune origin removes those refs, leaving your local branches and commits untouched.

open as a page

In Git, what does git rev-list --left-right --count HEAD...@{u} print?

level: middleimportance: should knowfreq 35%

basics

~20 s

It prints two tab-separated numbers: commits reachable from HEAD but not from the upstream, then commits reachable from the upstream but not from HEAD — the ahead and behind counts, in the order the two endpoints appear.

open as a page

What does Git's url.<base>.insteadOf config do, and when would you use it?

level: middleimportance: should knowfreq 30%

basics

~20 s

url.<base>.insteadOf rewrites a URL prefix before Git contacts a remote, so any URL starting with the given prefix is transparently replaced. It lets you redirect hardcoded remote or submodule URLs to a transport you actually have credentials for.

open as a page

What does Git's sparse-checkout cone mode do, and how does it pair with a partial clone?

level: seniorimportance: should knowfreq 28%

basics

~20 s

git sparse-checkout limits which directories are materialized in the working tree, marking the rest skip-worktree in the index. Cone mode restricts patterns to whole directory prefixes so matching stays fast. It shrinks the checkout, not the download; a partial clone shrinks the download.

open as a page

Why is git pull risky in an unattended deploy script, and what should it run instead?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Because pull's integration step can fail in ways a script cannot handle: it can create a merge commit, stop mid-conflict with markers in deployed files, or abort on divergence. A fetch followed by an explicit, deterministic update to the fetched tip is predictable.

open as a page

Should you rebase a fork topic branch onto upstream/main or merge upstream/main into it before review?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Rebasing replays your commits on the new base and yields a clean linear series, but rewrites their SHAs so republishing to your fork needs a force-push. Merging keeps existing SHAs and adds a merge commit. Prefer rebase for branches only you push.

open as a page

What does git clone --mirror give you that a plain bare clone does not?

level: seniorimportance: should knowfreq 20%

basics

~20 s

A mirror clone is bare and additionally maps every ref with +refs/:refs/, recording remote.origin.mirror, so an update overwrites all local refs with the remote's. A plain bare clone copies branch heads once and sets up no such tracking.

open as a page

In Git, why does git branch -vv mark a branch's upstream as gone, and how do you clean up?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Gone means the branch still has upstream configuration pointing at a remote-tracking ref that no longer exists locally — the remote branch was deleted and your clone pruned it. Clean up by deleting the local branch or running git branch --unset-upstream.

open as a page

For CI on a multi-gigabyte Git repository, how do you choose between shallow, partial, and full clones?

level: principalimportance: should knowfreq 34%

basics

~20 s

Start from what each job needs from history, not from clone speed. Build-only jobs take a shallow single-branch clone; jobs needing tags, blame or merge-base take a partial clone; jobs needing both take a full clone warmed from a local mirror or cache.

open as a page

showing 1–30 of 35