init, clone, add, commit, push, pull — every DevOps pipeline, IaC repo, and GitOps workflow starts with a git push. This is the most important tool in the course.
a3f7c2d).
git add file1 file2 to stage just those. The other 3 stay in your working directory. This gives you atomic, focused commits instead of "changed stuff" mega-commits.
HEAD points to your current position in the commit graph — usually the tip of the branch you're on. When you run git log, commits above HEAD don't exist yet. When you make a new commit, HEAD advances forward.
HEAD — current commitHEAD~1 — one commit backHEAD~3 — three commits backHEAD^ — same as HEAD~1git log --oneline — compact one-line per commitgit log --oneline --graph --all — ASCII branch graphgit log --author="name" — commits by persongit log --since="2 days ago" — recent commitsgit show a1b2c3d — see what a commit changedgit diff HEAD~1 HEAD — diff last two commits# === Setup (do once per machine) === git config --global user.name "Your Name" git config --global user.email "you@example.com" git config --global core.editor "code --wait" git config --global init.defaultBranch main git config --list # Verify config # === Start a project === git init # New repo in current dir git clone https://github.com/user/repo.git git clone repo.git my-dir # Clone into custom dir # === See what's happening === git status # Untracked / modified / staged git diff # Unstaged changes (vs last commit) git diff --staged # Staged changes (what will be committed) git diff HEAD~1 # Changes since last commit # === Stage + commit === git add file.txt # Stage specific file git add . # Stage ALL changes (use carefully) git add -p # Interactive: choose hunks to stage git commit -m "feat: add login" git commit --amend # Fix last commit message (before push) # === Undo === git restore file.txt # Discard working dir changes git restore --staged file.txt # Unstage (keep changes in working dir) git reset HEAD~1 # Undo last commit (keep changes staged) git revert abc123 # Safe undo — creates a new "undo commit"
# === Remote management === git remote -v # List remotes git remote add origin URL # Add GitHub remote git remote set-url origin URL # Change remote URL # === Sync with remote === git fetch origin # Download (don't merge) git pull # fetch + merge git pull --rebase # fetch + rebase (cleaner history) git push origin main # Push to remote git push -u origin main # Push + set upstream tracking git push --force-with-lease # Safe force push (after rebase) # === Stash (temporarily shelve work) === git stash # Save dirty state, clean WD git stash push -m "WIP: login" # Named stash git stash list # Show all stashes git stash pop # Apply last stash + drop it git stash apply stash@{1} # Apply specific stash (keep it) git stash drop stash@{0} # Delete a stash
git add -p (patch mode) lets you choose exactly which lines to stage within a file. Edited 3 unrelated things in one file? Stage them as 3 separate logical commits. Reviewers love this.
! after type or in footer.feat: / fix:. Changelogs are auto-generated. Commitlint enforces the format in git hooks (Day 9).
git log useless for debugging. When you're chasing a regression at 2 AM, a good commit history is your best friend.
# === SECRETS (NEVER commit these) === .env .env.local .env.*.local *.pem *.key *_rsa *_dsa secrets.yml credentials.json # === Node.js === node_modules/ dist/ build/ .npm npm-debug.log* yarn-error.log # === Python === __pycache__/ *.pyc *.pyo .venv/ venv/ *.egg-info/ # === OS / IDE === .DS_Store # macOS Thumbs.db # Windows .idea/ # IntelliJ .vscode/ # VS Code (optional) *.swp # Vim swap files # === Docker === *.dockerignore # Already handled by Docker # === Terraform === .terraform/ *.tfstate *.tfstate.backup *.tfvars # May contain secrets # === Logs + Temp === *.log *.tmp coverage/ .nyc_output/
*.log — ignore all .log files (glob)logs/ — ignore the logs directory!important.log — un-ignore a specific file (! = exception)**/temp — ignore "temp" anywhere in treedoc/**/*.txt — all .txt inside doc/.gitignore only prevents future commits. If .env is already in history:git filter-repo --path .env --invert-pathsgitignore.io and type "node, python, macos, windows, visualstudiocode" — it generates a comprehensive .gitignore in seconds.
git fetch — Downloads remote changes into origin/main but does NOT touch your local main. Safe — nothing breaks.
git pull = git fetch + git merge. Downloads AND merges into your current branch. Can cause merge conflicts.
git pull --rebase = git fetch + git rebase. Replays your commits on top of the remote — cleaner linear history. Recommended.
gh auth login. Handles auth automatically.# === Generate SSH key pair === ssh-keygen -t ed25519 -C "you@example.com" # Press Enter for default location (~/.ssh/id_ed25519) # Set a passphrase (optional but recommended) # === Start SSH agent + add key === eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519 # === Copy public key to clipboard === cat ~/.ssh/id_ed25519.pub # Copy the output # GitHub → Settings → SSH keys → New SSH key → Paste # === Test the connection === ssh -T git@github.com # Hi your-username! You've successfully authenticated. # === Use SSH remote URL === git remote set-url origin git@github.com:user/repo.git git push # No password prompts! # === PAT (simpler option) === # GitHub → Settings → Developer settings → Tokens (classic) # Scopes: repo, workflow # Use token as password when git push prompts # === GitHub CLI (easiest) === gh auth login # Interactive, handles everything
# === diff === git diff # Working dir vs last commit git diff --staged # Staged vs last commit git diff main feature-x # Between two branches git diff HEAD~3 HEAD -- app.js # One file, 3 commits back # === stash — save incomplete work === # Scenario: mid-feature, urgent hotfix needed git stash push -m "WIP: user dashboard" git checkout main # Switch to main for hotfix # ... fix the bug, commit, push ... git checkout feature/dashboard git stash pop # Restore your work # === Useful aliases — add to ~/.gitconfig === git config --global alias.st "status -sb" git config --global alias.lg "log --oneline --graph --all --decorate" git config --global alias.cm "commit -m" git config --global alias.aa "add -A" git config --global alias.undo "reset HEAD~1" # Now you can use: git st # Short status git lg # Pretty graph log git undo # Undo last commit # === Show file history === git log --follow -p src/auth.js # All commits that touched this file git blame src/auth.js # Who wrote each line git log --all --full-history -- "*.secret" # Find deleted file history
git stash saves your messy uncommitted work, cleans your working directory, lets you switch branches, fix and push the hotfix, then git stash pop to resume exactly where you left off.
git blame filename shows who last changed each line and in which commit. When you find a bug in the code, blame tells you:
In VS Code: GitLens extension shows blame inline automatically.
init → configure → commit → .gitignore → connect GitHub → push — the complete first-repo workflow
my-devops-app directory, run git init, and create a README.md.git log --oneline.git add -p to stage only part of one file. Commit them separately — experience atomic commits.git stash → run git lg alias → git stash pop to restore.# === 1. Configure Git === git config --global user.name "Your Full Name" git config --global user.email "you@example.com" git config --global core.editor "code --wait" git config --global init.defaultBranch main git config --global alias.lg "log --oneline --graph --all --decorate" git config --global alias.st "status -sb" # === 2. Create project === mkdir my-devops-app && cd my-devops-app git init echo "# My DevOps App" > README.md echo "A sample app built during the DevOps 35-day course." >> README.md # === 3. First commit === git status git add README.md git status # See it go from red to green git commit -m "feat: initial project setup with README" git log --oneline # === 4. Add .gitignore === cat > .gitignore << 'EOF' node_modules/ .env *.log dist/ .DS_Store .vscode/ EOF git add .gitignore git commit -m "chore: add gitignore for Node.js project" # === 5. Create package.json === cat > package.json << 'EOF' { "name": "my-devops-app", "version": "1.0.0", "description": "DevOps 35-day course app" } EOF git add package.json git commit -m "chore: add package.json" git log --oneline # Should show 3 commits
# === 6. Connect to GitHub === # Create repo at github.com first (no init, no README) git remote add origin https://github.com/YOUR_USERNAME/my-devops-app.git # OR use SSH: # git remote add origin git@github.com:YOUR_USERNAME/my-devops-app.git git remote -v # Verify remote added git push -u origin main # Open github.com/YOUR_USERNAME/my-devops-app — see your commits! # === 7. Practise stash === echo "incomplete feature" > feature.txt git status # See untracked file git stash push -m "WIP: incomplete feature" git status # Working dir is clean git stash list # See the stash git stash pop # Restore it ls # feature.txt is back rm feature.txt # Clean up # === 8. Explore log === git lg # Pretty graph (alias we set) git log --stat # Files changed per commit git log -p README.md # All changes to README git show HEAD # See last commit details git diff HEAD~1 HEAD # What changed in last commit
notes/day6-git.md to this repo with: 3 commands you found most useful, 1 thing that confused you, and your SSH or PAT setup method. Commit: docs(day6): git fundamentals notes
3 questions · 5 minutes · Git areas, stash, and commit messages
git stash do to your working directory?feat: — new featurechore: — maintenance taskfix: — bug fixrefactor: — code restructure~/.gitconfig (st, lg, undo)notes/day6-git.md with your takeaways| Category | Command | What it does |
|---|---|---|
| Setup | git config --global user.name "Name" | Set identity for all commits |
| Start | git init | Initialise new repo in current dir |
| Start | git clone URL | Clone remote repo locally |
| Status | git status | Show modified/staged/untracked files |
| Stage | git add file | Stage specific file |
| Stage | git add -p | Interactively stage hunks |
| Commit | git commit -m "msg" | Save staged snapshot with message |
| Commit | git commit --amend | Fix last commit message (before push) |
| History | git log --oneline --graph | Visual commit history |
| History | git blame file | Who wrote each line |
| Diff | git diff | Unstaged changes vs last commit |
| Diff | git diff --staged | Staged changes vs last commit |
| Undo | git restore file | Discard working dir changes |
| Undo | git reset HEAD~1 | Undo last commit (keep changes) |
| Undo | git revert SHA | Safe undo — new "undo" commit |
| Remote | git remote add origin URL | Connect to GitHub remote |
| Remote | git push -u origin main | Push + set tracking |
| Remote | git pull --rebase | Fetch + rebase (clean history) |
| Stash | git stash push -m "msg" | Save dirty state to stack |
| Stash | git stash pop | Restore last stash + remove it |
[user] name = Your Full Name email = you@example.com [core] editor = code --wait autocrlf = input # Linux/Mac: input | Windows: true whitespace = trailing-space,space-before-tab [init] defaultBranch = main [pull] rebase = true # Always rebase on pull [push] autoSetupRemote = true # Auto -u on first push [fetch] prune = true # Remove deleted remote branches [merge] conflictstyle = diff3 # Show base + both sides in conflicts [diff] colorMoved = zebra [alias] st = status -sb lg = log --oneline --graph --all --decorate cm = commit -m aa = add -A undo = reset HEAD~1 hide = stash push -m [color] ui = auto
autocrlf = true. This converts LF↔CRLF automatically. In WSL2, use input (same as Linux). This prevents "all lines changed" noise in diffs.
# Inside any git repo, run: ls -la .git/ # .git/ # ├── HEAD ← which branch/commit you're on # ├── config ← repo-level git config # ├── index ← the staging area (binary) # ├── objects/ ← all commits, trees, blobs (compressed) # └── refs/ # ├── heads/ ← local branches (just text files with SHA) # └── remotes/ ← remote tracking branches # See what HEAD points to: cat .git/HEAD # ref: refs/heads/main # See what main branch points to: cat .git/refs/heads/main # a3f7c2d1e4b5... (the SHA of the latest commit) # Read a commit object: git cat-file -p HEAD # tree abc123... ← snapshot of all files # parent def456... ← previous commit # author ... # committer ... # Git objects are content-addressed storage: # SHA = hash of content. Same content = same SHA. # This is why Git is reliable — nothing can silently change.
Understanding that branches are just text files containing a SHA explains everything:
| Mistake | Why it's bad | Fix |
|---|---|---|
| Committed .env or API keys | Secret exposed to anyone with repo access — even after deletion, it's in history | git filter-repo --path .env --invert-paths then rotate the secret immediately |
| Committing node_modules/ (500MB+) | Massively bloats repo, slows clone, makes diffs useless | Add to .gitignore, then: git rm -r --cached node_modules/ |
| Vague commit messages ("fix", "wip", "stuff") | Impossible to understand history, makes git bisect and blame useless | Use Conventional Commits. Enforce with commitlint (Day 9). |
| git add . on everything | Accidentally commits unrelated changes, debug files, temp files | Use git add -p or git add specific-file |
| git push --force on shared branch | Rewrites history that others have already pulled — breaks their repos | Use git push --force-with-lease (safe) or never force-push main |
| Never using git stash | Committing "WIP" or losing work when switching branches | git stash push -m "WIP: description" before switching |
| No .gitignore in new projects | OS files, IDE config, build artefacts accidentally committed | Create .gitignore as the first commit in every new project |
| Day | Topic | Key Skill | Lab Output |
|---|---|---|---|
| Day 6 ✅ | Git Fundamentals | init, add, commit, push, stash, log | my-devops-app on GitHub |
| Day 7 | Branching Strategies | GitFlow / GitHub Flow / Trunk-Based | Feature branch → merged PR |
| Day 8 | Pull Requests & Review | PR template, code review, merge strategies | PR with review comments |
| Day 9 | Git Hooks & Automation | Husky, lint-staged, commitlint | Pre-commit hook enforcing Conventional Commits |
| Day 10 | Git Advanced Lab | rebase -i, cherry-pick, bisect, reflog | Conflict resolution + power commands |