Learning Git as a developer and learning Git as an infrastructure person are two different jobs. The commands are the same. What changes is why you branch, what you are allowed to commit, and what happens if someone pushes straight to main. This reference is organized by what you are doing: set up, the daily loop, branching, reading history, recovering from mistakes, the pull request workflow, protecting main, laying out environments, and what never goes in the repo.
🧭 Why This Is Not the Beginner Version
Most Git guides teach you to save your own work. Infrastructure Git is about stopping two people from silently overwriting the same production network.
That difference is why an interviewer for a cloud role will ask how you handle a pull request instead of asking what git commit does. Even on a repo nobody else touches, you branch and you open a PR, because the role assumes it and the habit does not appear on the day you need it.
🚀 Setup and Authentication
Do this once per machine.
| Command | What it is for |
|---|---|
git config --global user.name "Your Name" | The name on every commit you make. |
git config --global user.email "you@example.com" | The email on every commit. Match the one on your GitHub or Azure DevOps account. |
git config --global init.defaultBranch main | New repos start on main instead of master. |
git config --global pull.ff only | git pull refuses to create a surprise merge commit. |
ssh-keygen -t ed25519 -C "you@example.com" | Creates an SSH key. Add the public half to your account. |
gh auth login | Signs in with the GitHub CLI, if you use it. |
Starting a repo:
| Command | What it is for |
|---|---|
git init | Turns the current folder into a repository. Once per project. |
git clone <url> | Copies an existing repo to your machine. This is how you start on a real team. |
git remote -v | Shows where push and pull actually go. Check it when a push lands somewhere unexpected. |
git remote add origin <url> | Points a new local repo at the remote you created. |
🔁 The Everyday Loop
Ten commands are most of your day.
| Command | What it is for |
|---|---|
git status | What changed, what is staged, which branch you are on. Run it constantly. |
git add <file> | Stages one file for the next commit. |
git add -p | Stages changes hunk by hunk, so you commit the fix without the debug line next to it. |
git commit -m "message" | Records the staged changes. One logical change per commit. |
git push | Sends your commits to the remote. |
git fetch | Downloads the remote's commits without touching your files. Safe any time. |
git pull | Fetches, then merges into your branch. With pull.ff only it refuses to guess. |
git log --oneline -10 | The last ten commits, one line each. The fastest way to see what happened. |
git diff | What you changed and have not staged. |
git diff --staged | What you are about to commit. Read this before every commit on an infrastructure repo. |
# the loop, start to finish
git status
git diff
git add main.tf
git commit -m "Add staging VNet with /16 address space"
git push🌿 Branching
| Command | What it is for |
|---|---|
git branch | Lists local branches and marks the one you are on. |
git branch -vv | Adds each branch's remote and whether it is ahead or behind. |
git switch -c <name> | Creates a branch and moves onto it. The modern form of git checkout -b. |
git switch <name> | Moves to an existing branch. |
git switch - | Back to the branch you were just on. |
git merge <name> | Brings another branch's commits into this one. |
git branch -d <name> | Deletes a branch once it is merged. Do this, or you will have forty. |
🔎 Reading History
Half of infrastructure Git is reading, not writing. When a firewall rule changed and nobody knows why, this is how you find out.
| Command | What it is for |
|---|---|
git log --oneline --graph --all | Branches and merges drawn as a graph. |
git log -p -- <file> | Every change to one file, with the diff. |
git log -S"<text>" --oneline | Commits that added or removed a string. Answers "when did this CIDR appear?" |
git blame <file> | Who last changed each line, and in which commit. |
git show <commit> | One commit in full: message, author, diff. |
git diff main...<branch> | What a branch changes compared with where it left main. This is what a reviewer sees in a PR. |
🛟 When Something Goes Wrong
| Command | What it is for |
|---|---|
git restore <file> | Throws away your uncommitted changes to that file. Unrecoverable, so be sure. |
git restore --staged <file> | Unstages a file and keeps the changes. The fix for git add . when you meant one file. |
git restore --source=<commit> <file> | Brings a file back as it was in an older commit. |
git commit --amend | Folds staged changes into the last commit, or fixes its message. Only before you push. |
git revert <commit> | Makes a new commit that undoes an old one. Safe on a shared branch. |
git reset --soft HEAD~1 | Undoes the last commit and keeps the changes staged. |
git stash | Parks your uncommitted work so you can switch branches. |
git stash pop | Brings it back. |
🔀 The Branch and PR Workflow
The same five steps every time, whether the change is one tag or a new subscription.
- Pull main first.
git switch main && git pull. Branching off a stale main is the most common cause of a conflict you did not need to have. - Branch, and name it after the change.
git switch -c add-staging-vnet. Notfix, notparveen-test. The branch name is the first thing a reviewer reads. - Change one thing, then run the preview.
terraform planoraz deployment group what-if. Paste that output into the PR description. A reviewer who can see the plan can approve in two minutes instead of twenty. - Commit and push the branch.
git push -u origin add-staging-vnet. The-usets the upstream, so later pushes are a baregit push. - Open the pull request, get it reviewed, merge, delete the branch. Then pull main again locally.
git switch main
git pull
git switch -c add-staging-vnet
# edit main.tf
terraform plan # paste this into the PR
git add main.tf
git commit -m "Add staging VNet, 10.20.0.0/16, peered to hub"
git push -u origin add-staging-vnetA PR description that reviewers can act on:
## What changes
Adds a staging VNet, 10.20.0.0/16, peered to the hub.
## Plan output
<paste terraform plan or what-if output here>
## Risk and rollback
Adds resources only, nothing existing changes. Roll back by reverting this PR.Once this is routine, let a pipeline run the plan on every PR and post it as a comment. The reviewer then never depends on you remembering to paste it.

Automate Bicep Deployments with GitHub Actions CI/CD Pipeline | CloudLearn
Build a GitHub Actions CI/CD pipeline that lints, validates, previews, and deploys Bicep templates to Azure with approval gates.
🛡️ Protecting Main
A branch strategy nobody enforces is a suggestion. Protection is what stops one person overwriting another, and stops a Friday afternoon push straight to production.
| Rule | What it stops | GitHub | Azure DevOps |
|---|---|---|---|
| Pull request required | Anyone pushing straight to main | Require a pull request before merging | Branch policy on main |
| Approvals | A change nobody else has read | Require approvals | Minimum number of reviewers |
| Checks must pass | Merging a change whose plan failed | Require status checks to pass | Build validation |
| Owners review their area | Someone editing the prod folder unreviewed | CODEOWNERS plus required Code Owner review | Automatically included reviewers |
| No force pushes | Rewriting history everyone shares | Block force pushes | Force push set to Deny |
Where do the required checks come from? A workflow that runs on every pull request.

Writing Your First GitHub Actions Workflow | CloudLearn
Learn GitHub Actions fundamentals by creating workflows with multiple triggers, custom inputs, and multi-job CI/CD pipelines in this hands-on lab
🌍 Environment Separation
Staging and production are separate state and separate variable files, usually in the same folder. They are not separate branches.
infra/
main.tf
variables.tf
envs/
staging.tfvars
prod.tfvars# same code, different environment
terraform init -reconfigure -backend-config="key=staging.terraform.tfstate"
terraform plan -var-file=envs/staging.tfvars
# Bicep: the .bicepparam file names its template with a using line
az deployment group what-if --resource-group rg-staging --parameters envs/staging.bicepparamPromote by pull request: merge the change, plan and apply it in staging, check the result, then plan and apply the same commit in production.
🙈 What Goes in the Repo, and What Never Does
| Thing | In the repo? | Why |
|---|---|---|
.tf, .bicep, .bicepparam files | Yes | This is the point. |
.gitignore | Yes | Commit it first, before anything else. |
.terraform.lock.hcl | Yes | Pins provider versions so everyone plans against the same providers. |
| Module source, pinned to a version | Yes | An unpinned module means your plan changes when someone else's does. |
README.md with how to run a plan | Yes | Future you will not remember the variable names. |
terraform.tfstate | Never | It holds resource IDs and often secrets in plain text. State belongs in a remote backend: an Azure Storage Account, S3, or HCP Terraform. |
.terraform/ | Never | Downloaded providers. Hundreds of megabytes, and machine specific. |
Saved plan files (*.tfplan) | Never | A plan can contain secret values in plain text. |
*.tfvars with real values | Never | This is where connection strings and passwords end up. |
.env, key files, certificates | Never | Same reason. |
| Anything you would not read aloud on a call | Never | A good enough test. |
A .gitignore that covers the common cases:
# Terraform
.terraform/
*.tfstate
*.tfstate.*
*.tfplan
tfplan
*.tfvars
*.tfvars.json
crash.log
override.tf
# Secrets and local config
.env
.env.*
*.pem
*.key
# Editors and OS
.vscode/
.DS_Store🔐 If a Secret Reaches a Commit
Deleting the file in the next commit does not remove the secret. It is still in the history, and on a public repo you should assume it was scraped within minutes. In this order:
- Rotate the credential. Assume it is compromised the moment it was pushed. Rotate first, every time.
- Remove it from the current code and add the file to
.gitignore. - Then clean the history. Tools such as
git filter-repoor BFG Repo-Cleaner rewrite it, and everyone with a clone has to re-clone afterwards, so tell the team first. - Check the logs for use of that credential while it was exposed.
⚠️ Five Traps
| Trap | What Actually Happens |
|---|---|
| Branching off a stale main | You inherit a conflict you did not need. Run git switch main && git pull first, every time. |
Running git add . on an infrastructure repo | It stages state files, variable files and keys along with your change. Name the files, and read git diff --staged. |
| Deleting a leaked secret in the next commit | The secret is still in history. Rotate the credential first. |
| One long-lived branch per environment | The branches drift, and a fix in one never reaches the other. |
git push --force on a shared branch | It overwrites other people's commits. If you must, use --force-with-lease, and never on main. |
⚡ Ten to Actually Remember
git status
git diff --staged
git switch -c <descriptive-name>
git add -p
git commit -m "What changed, and why"
git push -u origin <branch>
git pull
git restore --staged <file>
git revert <commit>
git log -p -- <file>🎯 The Three Habits Interviewers Notice
- You branch for everything. Even alone, even for a one-line change.
- Your commit messages say what changed and why. "Add staging VNet, 10.20.0.0/16, peered to hub" beats "update". Six months later the message is the only explanation that survives.
- Your PR carries the plan output. It shows you ran the preview before asking anyone to approve, which is the single habit that separates people who have broken production from people who have not yet.
📦 Past This Note
Rebase, cherry-pick, submodules and the reflog are real, and you will meet them. None of them are on the path to your first role, and learning them now costs time you should spend in the Azure portal. Come back to each when a team's workflow needs it.
What to read next depends on the tool you are versioning:
- Terraform: Terraform CLI Field Notes for the commands, then the Terraform Learning Roadmap for the path.
- Bicep: Azure Bicep Syntax Quick Reference for the syntax you will be committing.