Git remembers. Platforms coordinate. You decide what ships.
GIT · GITHUB · GITLAB
Understand the machinery behind modern software, not just the commands that happen to work.
From a snapshot on your laptop to a reviewed release in production. The history, the boundaries, and the decisions a senior developer should be able to explain.
Edit. Edit the working copy. Local and remote each begin with three commits. The index still holds the prior snapshot; no new change is staged. Status: staged 0 · local 3 · remote 3 · main OLD · deploy OFF.
Stage. Select the change for the next snapshot with git add. The press seats one pending-change card. Later working-copy edits would remain unstaged until added again. Status: staged 1 · local 3 · remote 3 · main OLD · deploy OFF.
Commit. Commit the staged snapshot on a topic branch: local history grows to four commits. Pending staged changes return to zero because index and HEAD now match, not because the index was deleted. Status: staged 0 · local 4 · remote 3 · main OLD · deploy OFF.
Push. Push the topic branch. Missing objects are copied to the remote, which now has four commits too. Local history remains intact. Remote main has not moved. Status: staged 0 · local 4 · remote 4 · main OLD · deploy OFF.
Review. In this scenario, the required checks and review approve the proposal. The gate opens, but main still has not moved. Approval is a platform record, not a Git commit. Status: staged 0 · local 4 · remote 4 · main OLD · deploy OFF.
Merge. Fast-forward remote main to the approved topic tip. This example needs no extra commit. A merge-commit or squash strategy would produce a different history; your local main still needs synchronization. Status: staged 0 · local 4 · remote 4 · main NEW · deploy OFF.
Deploy. A separate delivery job publishes a build from the merged revision. Deployment changes the running environment, not the repository's commit count. Merge alone did not deploy anything. Status: staged 0 · local 4 · remote 4 · main NEW · deploy ON.
This model starts with three shared commits and uses a topic branch followed by a fast-forward merge. Each archive card represents one commit, not one file. The platen counts pending staged changes, not all index entries. The index persists after commit. Push preserves local history; review and deployment are separate platform operations. Tour timing is teaching pace, not execution time.
Git is an independent, distributed version control system. An ordinary full clone keeps the fetched project history locally, so most work does not need a network connection. GitHub and GitLab add shared hosting, collaboration, policy and automation. They do not replace your shell, and neither owns the Git project.
That split is the difference between “I changed history” and “I asked a website to record a review.” Git's job is content-addressed snapshots, named references (refs), and the protocols that move objects between repositories (Pro Git: What is Git?). A host adds accounts, permissions, issues, reviews, packages and continuous integration and delivery (CI/CD). A green check on a pull request is not a Git object, and a successful git push is not a deployment.
Layer
What it owns
What it does not own
Terminal / shell / prompt
The terminal displays input and output; the shell interprets commands and controls environment, PATH, aliases and prompt
Repository objects, host policy, CI results
Git
Working tree, index, object database, local and remote-tracking refs, fetch/push protocol
User accounts, PR/MR records, runner fleets, production deploys
Host API (GitHub / GitLab)
Authorization, repository settings, issues, review records, webhooks and package registries, exposed through an application programming interface (API)
Your local uncommitted edits; the exact process model of your laptop
Runner
Ephemeral (or long-lived) compute that executes pipeline jobs against a checkout
Authoritative Git history; production traffic unless you wire it that way
Whether a commit "should" ship; that is policy you encode in pipelines and gates
Platform record vs Git object. A pull request (PR) on GitHub or merge request (MR) on GitLab is a host-side proposal: description, discussion, CI status, approvals and source/target branches (GitLab: Merge requests). Merging it may create commits or update refs on the server. Closing it without merging only changes the workflow record. The PR/MR itself is not a blob, tree, commit or tag, and git clone will not reconstruct its discussion.
The repository page in a browser is more than a local clone. The host combines a server-side Git repository with database records for issues, checks and access control. Your normal checkout has a working tree and index backed by a local Git directory. Remote-tracking refs such as origin/main are local notes, normally refreshed by fetch, not live views of the server (Working with Remotes). Until you fetch, your laptop can have stale knowledge. Until you push, the server may not know your new commits exist.
02 / History
Design pressure that still shows up in daily commands
Git's shape comes from a concrete break with a proprietary tool, not from abstract elegance. Hosts later wrapped the same object model in social and automated collaboration. Dates below are ones that primary sources state directly.
BitKeeper, then Git (2005)
Early Linux kernel work moved as patches and archives. In 2002 the project adopted BitKeeper, a proprietary distributed VCS. In 2005 the relationship between the kernel community and BitKeeper's vendor broke down, and the free-of-charge status was revoked. That forced the community, and Linus Torvalds in particular, to build a replacement aimed at speed, simple design, strong non-linear branching, full distribution, and efficiency on kernel-scale trees (Pro Git: A Short History of Git). Those goals explain why Git prefers local operation, cheap branches as pointers, and content-addressed objects over a central checkout server.
The canonical git.git tree on kernel.org presents the core plumbing under long-running maintenance associated with Junio C. Hamano (git.git about). The consequence for readers: Git evolved as infrastructure for parallel maintainer workflows, which is why rebases, merges, remotes, and reflogs feel first-class rather than bolted on.
GitHub: from social coding to a development platform
GitHub grew from work begun in 2007 by a small team including Tom Preston-Werner, Chris Wanstrath, PJ Hyett and Scott Chacon (GitHub Turns One!). Chris Wanstrath's “We Launched” announcement on 10 April 2008 marks the public launch. It highlighted commit comments, network graphs and integrations. The lasting design bet was that identity, discovery and conversation could make distributed version control a social workflow without replacing Git's object model.
Microsoft announced an acquisition agreement on 4 June 2018 (Microsoft + GitHub) and completed the acquisition on 26 October 2018. Keep announcement and completion dates separate. Ownership of the hosting business changed; Git itself remained an independent open-source project.
GitLab: self-hosted open source, then an integrated company product
Dmitriy Zaporozhets writes that he started the GitLab open-source project in October 2011 with Valery Sizov because there was no modern open-source tool to run on your own server for day-to-day version control collaboration. In 2012 Sid (Sytse) Sijbrandij emailed that he had started GitLab.com. Zaporozhets joined full time in 2013 (GitLab Blog: farewell from Dmitriy Zaporozhets). A later shareholder letter from Zaporozhets and Sijbrandij frames GitLab B.V. as the commercial entity that releases GitLab, offers paid services, and runs GitLab.com, with an explicit open-source stance toward the tools needed to deliver software (Letter from the shareholders).
The lasting design consequence is vertical integration: Git hosting, merge requests, and CI/CD live in one product surface whose exact stages and tiers depend on edition and plan (GitLab CI/CD docs). Where GitHub historically grew a broad marketplace around Actions and apps, GitLab's early pitch was "run the collaboration stack yourself," then "run more of the delivery stack in the same place." Feature availability still varies by Self-Managed versus GitLab.com versus Dedicated, and by subscription tier.
Hosting grew into delivery
GitLab's former standalone CI repository documents its integration into GitLab 8.0; 7.14 was the last standalone CI version (Original migration README). GitHub's 8 August 2019 announcement added native CI/CD to Actions. Both histories explain today's overlap: a repository host is also a control plane for executing code. Choosing one no longer means choosing whether you get CI at all.
03 / Git model
Snapshots, addresses, and refs you can draw by hand
Git stores snapshots, not a permanent textual diff database. Deltas appear later as pack compression. If you keep that straight, merge, rebase, shallow clones, and LFS stop sounding like magic.
Snapshots first; packs later
Pro Git's core claim is blunt: Git thinks in snapshots of a mini filesystem, with unchanged files stored by reference to prior identical content, and nearly every operation adding data rather than rewriting it in place (Pro Git: What is Git?). Objects begin life "loose." Later, git gc, push paths, or object count pressure can pack them into packfiles that store some objects as deltas against others for space, without changing the logical snapshot model (Pro Git: Packfiles).
Four object types and content addressing
At the bottom, Git is a content-addressable key-value store: an object's identifier hashes its type/length header and content (Git Objects). SHA-1 is the traditional default; Git also supports SHA-256 repositories where enabled. Do not assume every host or tool interoperates with both formats (git-init). A hash identifies content; it is not an access-control decision.
Blob: file contents only (no path).
Tree: directory entries mapping names and modes to blobs or trees.
Commit: pointer to a root tree, zero or more parent commits, author/committer identity strings and timestamps, and a message.
Tag object: an annotated tag points at another object, often a commit, with tagger metadata, message and an optional signature. A lightweight tag is just a ref and creates no tag object.
A commit therefore captures a full tree snapshot plus ancestry links and attribution metadata. Author name and email are fields inside that object. They are not login credentials. Cryptographic proof that a commit came from a trusted key is a separate signing and verification step (Pro Git: Signing Your Work).
Commit ancestry: a topic branch, then a merge commit M
A---B---C-------M <- main (branch ref)
\ /
D---E---F <- feature (branch ref)
Each letter is a commit. Parent links point backward.
M has two parents, C and F. Branches are movable names,
not copied folders. A tag can name a release point.
Branches, HEAD, and detached HEAD
A branch is a lightweight movable pointer to a commit; HEAD usually names which branch tip advances when you commit (Pro Git: Branches in a Nutshell). Checking out a raw commit points HEAD at that commit ID instead of a branch: a detached HEAD. New commits can be created there, but no branch name remembers them until you create or update a ref (git-checkout: DETACHED HEAD).
Index as staging intent
The working tree is your editable checkout. The staging area (index) records the complete proposed next snapshot, including unchanged tracked files; it is not just a bag of changed filenames. git add updates selected entries to the content at that moment. Later edits stay unstaged until you add them again. An ordinary git commit writes the index snapshot, not whatever happens to be visible in the editor (The three states).
Local refs, remote-tracking refs, fetch/pull/push
origin is a conventional remote nickname, not a special central server. Fetch obtains remote objects and normally updates remote-tracking refs without integrating them into your current branch. Pull fetches and then integrates using the configured merge/rebase behavior; git pull --ff-only refuses a divergent integration. Push transfers missing objects and asks the remote to update allowed refs. None uploads uncommitted working-tree edits (Working with Remotes).
Merge, rebase, cherry-pick, squash
Merge combines histories. A fast-forward only advances a ref when the old tip is an ancestor of the new one; a divergent merge can create a commit with multiple parents. Rebase replays commits on a new base, normally changing their identifiers (Rebasing). Cherry-pick applies a commit's change on the current branch and normally creates a new commit (Maintaining a Project). Squashing combines several changes into one commit, whether through interactive rebase or a host's merge strategy (Rewriting History). Rewriting shared commits makes collaborators reconcile new IDs. Preserving ancestry and keeping a concise review history are different goals.
Conflict resolution is a design decision. Git can mechanically combine many edits using a common ancestor, but a clean merge does not prove the combined behavior is correct. A text conflict marks a place it cannot resolve automatically. Inspect both intentions, edit the result, stage it, and run the relevant checks. “Keep ours” or “keep theirs” is not a substitute for understanding.
Reflog limits, shallow/partial clones, LFS, and backup myths
Reflogs record where HEAD and branch tips moved in this local repository for a limited window (Pro Git describes "the last few months" as the practical horizon) and can be pruned with expire policies during maintenance (Pro Git: Revision Selection; git-reflog). They are local safety nets, not cluster-wide audit logs.
git clone --depth=<n> creates a shallow clone with truncated history; --filter requests partial clone object filtering such as omitting blobs until needed (git-clone). Useful for CI speed; incomplete as a sole archival strategy.
Git LFS replaces large files with text pointers inside Git and stores contents on a separate LFS endpoint (Git LFS). A plain git clone without LFS smudge/fetch is not a full backup of those assets. Platform metadata (issues, PR/MR threads, permissions, packages, runner registration) also stays outside the object database. Backup Git, LFS, and host exports as separate concerns.
04 / Choose your platform
Choose a host for the work, not a tribe
Git stores history. GitHub and GitLab host collaboration: permissions, reviews, issues, CI, packages, and policy. Both support public and private repositories. Feature tiers and deployment options vary by plan and version, so treat marketing pages as secondary to the product docs for your actual plan.
GitHub Enterprise gives access to both GitHub Enterprise Cloud (hosted by GitHub on github.com or a GHE.com subdomain) and GitHub Enterprise Server (a self-hosted appliance you operate on your infrastructure or a public cloud). See About GitHub for enterprises.
GitLab offers three offerings: GitLab.com (multi-tenant SaaS), GitLab Self-Managed (you install and operate), and GitLab Dedicated (single-tenant SaaS hosted by GitLab). Subscriptions do not transfer between GitLab.com and Self-Managed. See GitLab plans.
Best-fit lens. Start with GitHub when contributors already work there and its public collaboration network or Actions and Apps ecosystem solves your integration needs. Start with GitLab when its integrated planning, CI/CD, registry and governance model fits your organization, or you want its Self-Managed offering. These are evaluation signals, not exclusive capabilities: both offer integrated automation, security features and third-party extensions. Compare the actual plan, migration cost and operational burden, not “public versus private.”
Low on .com/Dedicated; Self-Managed is full-stack ops
Portability
Git history moves; issues/PRs/Actions/LFS do not as one unit
Git history moves; issues/MRs/CI/LFS do not as one unit
Portability limits matter. A git clone retrieves Git objects and configured refs, not every server-side record. It does not move pull requests, merge requests, issue comments, check runs, protected-branch settings, or runner registration. Git LFS stores large file contents on a separate remote and leaves pointer files in Git (Git LFS). An installed LFS client can download content automatically during checkout; otherwise configure it and fetch the assets separately. Even an ordinary LFS checkout is not an archive of every historical LFS object. Plan migrations as Git plus platform export/import plus LFS plus deliberately recreated CI credentials.
05 / A change, end to end
Small-branch review that actually protects main
A practical default: short-lived topic branches, pull or merge requests into a protected default branch, required reviews, and required checks. Policy lives on the host. Mechanisms live in Git.
Protect the default branch
On GitHub, branch protection can require pull request reviews, required status checks (loose or strict “up to date”), conversation resolution, signed commits, linear history, a merge queue, and more. Admins can bypass unless you disallow bypass. See About protected branches.
On GitLab, protected branches control who may merge versus who may push and merge, and can require Code Owner approval. Setting “Allowed to push and merge” to No one while allowing Maintainers to merge forces changes through merge requests. See Protected branches. Required approvals are a tiered feature: Free treats approvals as optional; Premium and Ultimate can require counts and types of approvers (Merge request approvals).
Review the effective rule set, not just one checkbox. Overlapping GitLab rules can permit the more permissive push setting. An impossible approval rule can be auto-approved; policy-created rules behave differently. Keep eligible approvers available, prevent self-approval where appropriate, and test the policy with a low-privilege account before relying on it.
Stale base nuance. Strict required checks demand the head branch be up to date with the base before merge, which catches integration failures early and burns more CI. A merge queue (GitHub) or merge train (GitLab) retests each change against the latest target plus earlier queued changes so authors need not race-update. Availability and exact options vary by plan and version. See Managing a merge queue and Merge trains.
Choose squash, merge, or rebase intentionally
GitHub documents three PR merge strategies: merge commit (preserves branch commits plus an explicit merge point), squash and merge (one commit on the base), and rebase and merge (linear history, new commit SHAs). Squash fits short-lived branches that represent one logical change; long-running branches after squash often replay already-merged history. See About pull request merges.
GitLab project merge methods include merge commit, merge commit with semi-linear history, and fast-forward merge, with separate squash defaults from Do not allow through Require. Semi-linear and fast-forward require the source to be up to date (or rebased) before merge. See Merge methods.
Trunk-based
Default when releases are continuous or tagged from main, feature flags gate incomplete work, and branches live hours to a few days. Protect main hard. Prefer squash or short merge commits.
Release branches
Default when you must support parallel supported versions, hotfix older lines, or freeze code while main keeps moving. Cherry-pick fixes carefully. Document which branch is the integration trunk.
Minimal daily review loop
Branch from an up-to-date default: git fetch origin && git switch -c topic/short-name origin/main
Commit small reviewable units; open a PR/MR early as draft if useful.
Keep CI green on the tip; rebase or merge main when required checks demand freshness.
Require at least one human approval; require CODEOWNERS where ownership is real.
Merge with the team’s chosen method; delete the topic branch.
06 / The command line
Shell, Git, and host CLIs are three different tools
Your terminal prompt is not Git. Git is not the hosting API. Host CLIs talk to HTTP APIs with their own credentials.
Three different “prompts” get confused. A shell prompt (a leading $, or Starship/zsh branch and dirty markers) is your shell’s display, not a server command: copy only the command text after it. Ahead/behind markers normally compare local refs, so they can be stale until fetch. A CLI command is what git, gh, or glab actually run. An AI natural-language prompt is model context, not an access-control rule. GitHub and GitLab do not generally control your interactive terminal; CI runners launch shells from job configuration. AI assistants invoke tools under their execution environment’s granted permissions, not authority conferred by a prompt file.
Config scopes, author, auth, signing
Git reads configuration from system, global, local, and optionally worktree scopes, with later values generally overriding earlier ones; command-scoped git -c key=value settings can override those too (git-config). Author identity (user.name / user.email) stamps commits. It is not authentication. Authentication uses SSH keys or HTTPS credentials, often managed by a credential helper. A personal access token (PAT) is a scoped credential, not your commit identity. Signing with GPG, SSH or S/MIME provides evidence that a key signed the commit; it does not prove the code is safe or every attribution field is truthful (Commit signature verification).
Tool
Talks to
Typical auth
git
Remotes via SSH/HTTPS
SSH agent, PAT + credential helper, SSO-aware helpers
glab auth login, GITLAB_TOKEN, host via GITLAB_HOST
gh authentication is independent of Git until you opt into using it as a credential helper (Authenticating with GitHub CLI). glab targets gitlab.com by default outside a repo, follows the Git remote host inside a repo, and can be overridden with GITLAB_HOST (Connect to your GitLab instance). Always name the host when you use Enterprise Server, Self-Managed, or Dedicated.
Safe copyable snippets
Replace the example URL and directory with a repository you may contribute to. These commands assume its default branch is main and a clean starting checkout. Run them deliberately, not as a blind script. They are examples, not claims of a successful network operation.
# Clone once, then enter the new repository
git clone https://github.com/EXAMPLE-ORG/EXAMPLE-REPO.git
cd EXAMPLE-REPO
git fetch origin
git switch -c topic/explain-change --no-track origin/main
# Edit files in your editor, then inspect and select changes
git status
git diff
git add -p
# For a new, untracked file, use: git add path/to/file
git diff --cached
git commit -m "Explain the reason for this change"
# Rebase only your unpublished topic work; resolve or abort conflicts
git fetch origin
git rebase origin/main
# Run the project's checks on the integrated result
git push -u origin HEAD
git diff shows unstaged changes; git diff --cached shows the next commit relative to HEAD. If you edit a file after staging it, those later edits are not automatically included. Avoid rebasing a branch that other people are using.
These inspect local state; they do not fetch fresh server state. An ahead/behind count measures commits, not file differences. Inspect remote URLs privately: poorly configured URLs can contain credentials. Aliases, credential helpers, SSH host aliases and URL rewrites can explain why the effective command behaves differently from the one you typed.
Choose the block for your host. Open a proposal first; merge only after reviewing the diff, required approvals and checks. These commands do not bypass server policy. See the GitHub PR commands, GitLab MR commands and GitLab pipeline status.
# GitHub: in the topic branch's repository
gh auth status
gh pr create --fill
gh pr checks
# After review; if squash is the project's chosen policy:
gh pr merge --squash
# GitLab: in the topic branch's repository
glab auth status
glab mr create --fill
glab ci status --compact
# After review; honors project merge settings:
glab mr merge
Destructive near misses.--force-with-lease is safer than bare --force, not harmless: it still replaces remote history, and background fetches can update the tracking ref its default lease relies on. Agree on any published-history rewrite and preserve recovery refs first. git reset --hard can discard tracked edits; git clean -fdx can delete untracked and ignored files, including local secrets. Neither is routine troubleshooting. Never paste tokens into shell history; use OS keyrings, host CLI login flows or short-lived CI credentials.
Diagnose common failures
Non-fast-forward rejected: remote has commits you lack. git fetch, then rebase or merge, then push. Do not force unless rewriting a private branch.
Permission denied / 403: wrong account, missing SSO authorization, expired PAT, or branch protection blocking direct push.
Merge conflicts: resolve files, git add them, continue rebase or commit the merge. Abort with git rebase --abort / git merge --abort if needed.
Detached HEAD: you checked out a commit, not a branch. Create or switch to a branch before committing work you care about: git switch -c recover/topic.
Secret in history: rotate the credential at the provider first, then remove it from Git history and caches. Rotation before rewrite.
07 / From code to delivery
CI YAML runs arbitrary code on runners
GitHub Actions workflows live under .github/workflows/ and react to on: events (Workflow syntax). GitLab CI uses .gitlab-ci.yml with stages, jobs, script, rules, artifacts, and cache (CI/CD YAML syntax reference). In both systems, a runner executes the job as defined: treat pipeline config as production code.
Continuous integration (CI) tests integrated changes early. Continuous delivery keeps a releasable result ready for an approval; continuous deployment automatically promotes qualifying changes. “CD” can mean either, so state which. A green pipeline proves only the jobs that actually ran against the revision they tested.
Hosted runners reduce machine administration, but you still control workflow privileges and dependency trust. Self-hosted runners add control and expose your own network: isolate untrusted jobs, prefer disposable execution environments, and keep privileged deploy runners separate. A container alone is not a complete security boundary.
Surface
Purpose
Senior-level rule
Artifact
A job's output: report, binary or built site
Attach it to a known commit and run. Retention is not permanent by default.
Cache
Reusable downloads or build intermediates
Disposable acceleration, never the authoritative release or secret store.
Registry
Versioned packages or container images
Promote an immutable version or digest; mutable tags can move.
Release
Version announcement and associated assets
A Git tag names a version; host release notes and uploads are separate records.
Environment
A named deployment destination and history
Protect production credentials and approvals independently of merge permission.
Build once and promote the same artifact where practical. Record the source commit, build identity and deployed artifact digest. Merge rollback and deployment rollback are different: reverting a commit does not by itself replace a running service, and older binaries may be incompatible with newer database migrations.
Two minimal CI examples with a real build contract
These examples build this guide's checked-in source with Node.js 22 and npm run build. This project has no package-install step or runtime dependencies. Save only the template for your chosen host. They build the site; they do not deploy it, run a test suite, or create required-check policies. The hosted pipeline examples have not been executed for this publication.
The checkout action is pinned to a verified v6 commit, not a movable version tag. For strict reproducibility, also pin reviewed runner/container images by digest and maintain those pins. GitHub's merge_group event lets this check run for a merge queue. Configure GitLab merged-results pipelines or merge trains separately when integration testing is required.
OIDC and untrusted contributions
Prefer short-lived cloud credentials through OpenID Connect (OIDC) rather than long-lived cloud keys in repository secrets. The job obtains a signed identity token; the cloud validates it and issues limited credentials. GitHub Actions supports OIDC federation; GitLab exposes id_tokens. Constrain issuer, audience, repository/project and allowed branch or environment in the cloud trust policy. A short-lived token with an overbroad trust policy is still dangerous.
Fork contributions are untrusted. Prefer ordinary pull_request workflows with restricted permissions. pull_request_target runs in a more privileged base-repository context and can access base secrets and write-capable tokens, subject to configured permissions and event policies. Checking out and executing the contributor's code there is a “pwn request” hazard. Do not build untrusted code with those privileges. Treat downloaded artifacts and interpolated issue/PR text as untrusted too (Securely using pull_request_target).
08 / Trust & recovery
Ownership, secrets, backups, and adjacent tools
Mechanisms enforce what policy intends. If bypass paths exist for bots or admins, document them as deliberate exceptions.
CODEOWNERS maps paths to reviewers. On GitHub, place CODEOWNERS in .github/, root, or docs/; combine with “Require review from Code Owners” on protected branches (About code owners). On GitLab, search order differs (root, docs/, then .gitlab/), and Code Owner approval must be enabled on the protected target branch (Code Owners). Own the CODEOWNERS file itself.
Protect the files that control trust: CI configuration, dependency manifests, deployment scripts and CODEOWNERS. Use least-privilege job tokens, scoped service identities and environment-specific credentials. Masking a secret in logs does not prevent a malicious job from sending it elsewhere. Separate untrusted build execution from trusted publication.
Backups beyond Git: preserve required Git refs, export supported issue/PR/MR metadata, and back up LFS, packages, settings and recoverable credentials according to the host's supported procedure. An export can omit fields or references; rehearse restoration, not just file creation. A laptop clone is not a disaster-recovery plan for the whole platform.
To undo a shared change, usually create a reviewed git revert commit rather than erasing the branch's history. Reverting a merge requires choosing its mainline parent and affects future merges, so inspect the graph first. Reflog recovery helps only while the relevant local records and objects still exist.
Related tools stay outside the trust boundary
Editors and graphical Git clients operate on the same objects and refs, but automation may fetch or stage on your behalf. Hooks can enforce local checks, yet local hooks are normally not transferred by clone and can be bypassed; enforce critical rules on the server too. A fork is a separate server repository; a branch is a ref within one repository; a worktree is another checkout sharing a local repository's objects. Submodules refer to a commit in a separate repository and need separate retrieval and credentials.
Webhooks notify external services of events; consumers must verify authenticity, tolerate retries and avoid trusting payload text as code. REST and GraphQL APIs expose platform records that Git cannot transport. Terraform and GitOps controllers apply configured desired state from trusted revisions; a merge has impact only where that automation is wired. AI assistant output remains an untrusted draft: review diffs and run the same checks as for human commits. Never paste secrets into prompts.
09 / Explain it to someone
Teach it back in ninety seconds
Use this script aloud, then expand with the questions below.
“Git is a local history engine. It stores file snapshots linked by commits; branches are names pointing to commits. You can inspect and commit without the internet. The staging area selects exactly what the next commit will contain. Fetch learns remote history, push shares it, and neither is automatically a deployment.
GitHub and GitLab add the shared workspace: identities, issues, reviews, permissions and automation. A pull request or merge request is a proposal with discussion and checks, not a special Git object. Protect the main branch, keep changes small, and validate what will actually be merged.
Your shell prompt is just a display. Git moves history; gh and glab operate the host's APIs. A name on a commit is not proof of who authenticated. CI executes code on a runner, so treat its permissions as seriously as production access. Deploy a known build with a deliberate recovery plan. Back up the collaboration data separately from Git history.”
Why isn’t “GitHub vs GitLab” a useful binary?
Both host public and private code. Both have SaaS and self-managed enterprise options. The real tradeoff is ecosystem extensibility versus integrated governance and how much platform ops you accept. Feature tiers vary.
When do I require “up to date” checks versus a merge queue or train?
Strict up-to-date checks are simple and noisy under load. Queues and trains serialize integration testing when many MRs land daily. Enable them when broken main costs more than queue latency, and only if your plan supports them.
What do I do first if a secret was committed?
Rotate or revoke the secret at the provider immediately. Then remove it from history and purge caches. History rewrite without rotation leaves the credential usable.
Checklist
Done when
Default branch protected
No direct push for humans; reviews + checks required
Merge method chosen
Team agrees squash vs merge vs rebase and why
CLI auth mapped
Git remote auth and gh/glab host auth verified separately
CI least privilege
Token permissions minimal; no untrusted code on privileged triggers
Mechanism: what the tool can enforce (protection rule, required check, OIDC trust).
Policy: what your team requires humans and bots to do, including documented bypasses.
PR/MR: platform review record; not a Git object.
Runner: machine that executes CI jobs as arbitrary code under that job’s credentials.
OIDC: short-lived federated identity for cloud access without long-lived static keys.
10 / FOLLOW THE EVIDENCE
The source library.
Primary documentation, original announcements and first-party histories. The guide synthesizes these sources; workflow recommendations are engineering judgments, not vendor guarantees.
Sources checked for this edition. Features, names, editions and entitlements can change. Check your host version and plan before adopting a control.