DevToolBoxฟรี
บล็อก

Git Workflow Guide: Internals, Branching Strategies, Interactive Rebase, Hooks & CI/CD Integration

22 min readโดย DevToolBox Team

Git is far more than add, commit, and push. Mastering Git internals, branching strategies, interactive rebase, hooks, and CI/CD integration transforms your development workflow. This guide covers 13 essential Git topics with practical examples for professional developers.

TL;DR: Git stores data as content-addressable objects (blobs, trees, commits, tags). Use Git Flow for scheduled releases, GitHub Flow for continuous delivery, or trunk-based development for rapid iteration. Interactive rebase lets you squash, reword, and reorder commits. Cherry-pick selects specific commits, bisect finds bugs via binary search. Hooks automate quality checks, and semantic release with GitHub Actions automates versioning.

Key Takeaways

  • Git stores everything as objects (blobs, trees, commits) identified by SHA-1 hashes, not as file diffs.
  • Choose Git Flow for complex releases, GitHub Flow for simplicity, or trunk-based for high-velocity teams.
  • Interactive rebase rewrites history cleanly — use squash, fixup, reword, and edit to craft meaningful commits.
  • Git bisect performs binary search to find the exact commit that introduced a bug.
  • Git hooks (pre-commit, commit-msg, pre-push) automate linting, testing, and commit message validation.
  • Sign commits with GPG or SSH keys to verify author identity and establish trust in your codebase.

Git Internals

Git is a content-addressable filesystem. Every file, directory, and commit is stored as an object identified by a SHA-1 hash. Understanding this model explains why Git is so fast and how operations like branch, merge, and rebase actually work under the hood.

Tip: A branch in Git is just a 41-byte file containing a commit SHA. Creating a branch is essentially free, which is why Git encourages branching workflows. HEAD is a symbolic reference that points to the current branch, and tags are permanent pointers to specific commits.
# Explore Git objects
git cat-file -t HEAD          # commit
git cat-file -p HEAD          # show commit content
git cat-file -p HEAD^{tree}   # show tree (directory listing)

# Every object is stored in .git/objects/
# Object types: blob (file), tree (dir), commit, tag
echo "hello" | git hash-object --stdin    # compute SHA-1
git rev-parse HEAD             # full SHA of HEAD
git rev-parse --short HEAD     # short SHA

# Pack files compress objects for efficiency
git count-objects -vH          # show object stats
git gc                         # garbage collect and pack
git verify-pack -v .git/objects/pack/*.idx | head
Deep dive: Git has four object types: blobs store file contents, trees represent directories mapping names to blobs or other trees, commits point to a tree and parent commits, and annotated tags point to commits with metadata. The SHA-1 hash is computed from the object type, size, and content, ensuring data integrity across the entire history.

The Object Model

When you run git add, Git creates a blob object for each file. When you commit, Git creates a tree object for each directory and a commit object pointing to the root tree. Branches and tags are simply files containing a commit SHA, making them lightweight references rather than copies of data.

Branching Strategies

A branching strategy defines how your team creates, merges, and releases code. The right choice depends on team size, release cadence, and deployment model. Three dominant strategies have emerged in the industry.

Tip: Git Flow works best for teams shipping versioned software with scheduled releases. GitHub Flow is ideal for web applications with continuous deployment. Trunk-based development suits teams with strong CI/CD pipelines, feature flags, and a culture of small, frequent commits.
# Git Flow: structured releases
git flow init                         # initialize git-flow
git flow feature start user-auth      # create feature branch
git flow feature finish user-auth     # merge to develop
git flow release start 2.0.0          # create release branch
git flow release finish 2.0.0         # merge to main + develop

# GitHub Flow: simple continuous delivery
git checkout -b feat/add-search       # branch from main
git push -u origin feat/add-search    # push and open PR
# PR review -> merge -> auto deploy

# Trunk-based: short-lived branches
git checkout -b fix/typo main
git commit -am "fix: correct typo in header"
git push origin fix/typo              # merge within hours
Deep dive: Git Flow uses two permanent branches (main and develop) plus temporary feature, release, and hotfix branches. GitHub Flow uses only main plus short-lived feature branches merged via pull requests. Trunk-based development commits directly to main or uses very short-lived branches lasting hours, not days.

Branch Naming Conventions

Consistent branch names improve readability and automation. Common patterns include type/description (feat/user-auth, fix/login-bug), type/ticket-id (feat/JIRA-123), and owner/description (alice/refactor-api). Many teams prefix with feat/, fix/, hotfix/, chore/, or docs/ to categorize branches automatically.

Interactive Rebase

Interactive rebase lets you rewrite commit history before sharing it. You can squash multiple commits into one, reword commit messages, reorder commits, or edit a commit to split it. This keeps your history clean and meaningful.

Tip: The golden rule of rebase: never rebase commits that have been pushed to a shared branch. Rebase rewrites commit SHAs, which causes conflicts for anyone who has based work on the original commits. Use rebase only on local or personal branches before merging.
# Interactive rebase last 4 commits
git rebase -i HEAD~4

# Editor opens with:
# pick a1b2c3d Add user model
# pick e4f5g6h Fix typo in model       -> fixup
# pick i7j8k9l Add user controller     -> squash
# pick m0n1o2p Update error messages   -> reword

# Commands:
# pick   = keep commit as-is
# squash = combine with previous, edit message
# fixup  = combine with previous, discard message
# reword = keep commit, edit message
# edit   = pause to amend the commit
# drop   = remove commit entirely

# Abort if something goes wrong
git rebase --abort
Deep dive: When you rebase, Git creates new commits with new SHAs that have the same changes as the originals. The old commits become orphaned and will eventually be garbage collected. If you rebase a branch that others have pulled, they will see divergent history and face merge conflicts.

Autosquash Workflow

Use git commit --fixup=<sha> to create fixup commits, then git rebase -i --autosquash automatically moves them next to the target commit with the fixup command. This workflow lets you make corrections as you work and clean up later without manual reordering.

Cherry-Pick and Bisect

Cherry-pick applies specific commits from one branch to another without merging the entire branch. Bisect uses binary search to find the commit that introduced a bug. Together, they are essential debugging and selective-merge tools.

Tip: Cherry-pick creates a new commit with a different SHA, so the same change exists twice in history. Use it sparingly for hotfixes or backports. For routine work, prefer merge or rebase to keep history connected.
# Cherry-pick a single commit to current branch
git cherry-pick abc1234

# Cherry-pick range without committing
git cherry-pick abc1234..def5678 --no-commit
git commit -m "feat: backport fixes from develop"

# Bisect: find the bug-introducing commit
git bisect start
git bisect bad                 # current commit is broken
git bisect good v1.0.0         # this tag was working
# Git checks out midpoint, test it, then:
git bisect good                # or git bisect bad
# Repeat until Git identifies the culprit
git bisect reset               # return to original HEAD

# Automated bisect with a test script
git bisect start HEAD v1.0.0
git bisect run npm test
Deep dive: Automated bisect is extremely powerful: provide a test script that returns exit code 0 for good and non-zero for bad, and Git will automatically narrow down to the exact commit. This works with any test, build script, or even a manual inspection command.

Automating Bisect

For maximum efficiency, write a small script that reproduces the bug and exits with non-zero on failure. Pass it to git bisect run and Git will perform the entire binary search unattended. With 1000 commits, bisect only needs about 10 tests to find the culprit.

Stash and Worktrees

Git stash temporarily shelves uncommitted changes so you can switch branches. Worktrees let you check out multiple branches simultaneously in separate directories, avoiding constant stashing and branch switching.

Tip: Worktrees are especially useful for code review: check out a PR branch in a separate worktree while keeping your feature branch untouched. Each worktree has its own working directory and index, but shares the same .git repository.
# Stash with a descriptive message
git stash push -m "WIP: auth refactor"
git stash list                     # list all stashes
git stash show -p stash@{0}        # show stash diff
git stash pop                      # apply and remove
git stash apply stash@{1}          # apply without removing
git stash drop stash@{2}           # delete specific stash

# Stash including untracked files
git stash push -u -m "include new files"

# Worktrees: multiple branches simultaneously
git worktree add ../hotfix-branch hotfix/v2
git worktree add ../feature-branch feat/search
git worktree list                  # list all worktrees
git worktree remove ../hotfix-branch
Deep dive: Stash entries are stored as commit objects in a special reflog. You can create multiple stashes, apply them selectively, and even create a branch from a stash entry. The --keep-index flag stashes only unstaged changes, useful when you want to test what is currently staged.

Worktree Use Cases

Common worktree scenarios include: reviewing a pull request while working on your own feature, running a long build on one branch while coding on another, comparing behavior between branches side-by-side, and maintaining a production hotfix branch that is always checked out and ready for emergency patches.

Creating a Branch from a Stash

If you stashed changes but then realize they deserve their own branch, use git stash branch new-branch-name stash@{0}. This creates a new branch from the commit where the stash was originally created, applies the stash, and drops it. It is the cleanest way to promote stashed work into a proper feature branch.

Git Hooks

Hooks are scripts that Git runs before or after certain events like commit, push, or merge. They enforce code quality standards, validate commit messages, run tests, and prevent bad code from entering the repository.

Tip: Client-side hooks (pre-commit, commit-msg, pre-push) run on the developer machine. Server-side hooks (pre-receive, post-receive) run on the remote. Use Husky or lefthook to version-control client hooks so every team member runs the same checks.
#!/bin/sh
# .husky/pre-commit
npx lint-staged

# .husky/commit-msg
npx --no -- commitlint --edit "\$1"

# package.json lint-staged config
# "lint-staged": {
#   "*.{js,ts}": ["eslint --fix", "prettier --write"],
#   "*.css": ["stylelint --fix"]
# }

# Setup husky in a project
npx husky init
echo "npx lint-staged" > .husky/pre-commit
echo "npx commitlint --edit \$1" > .husky/commit-msg
Deep dive: Common hook workflows include: pre-commit runs linters and formatters via lint-staged, commit-msg validates conventional commit format with commitlint, and pre-push runs the test suite. The prepare-commit-msg hook can auto-populate commit messages with branch names or ticket numbers.

Hook Manager Comparison

Husky is the most popular hook manager with 30k+ GitHub stars and simple configuration via .husky/ directory. Lefthook is faster, written in Go, and supports parallel hook execution. simple-git-hooks is a zero-dependency alternative for projects that need minimal setup. All three store hooks in the repository so every contributor runs the same checks.

lint-staged Configuration

lint-staged runs linters only on staged files, keeping pre-commit hooks fast even in large repos. Configure it in package.json or a separate .lintstagedrc file. Map glob patterns to commands: JavaScript files to ESLint and Prettier, CSS to Stylelint, and Markdown to markdownlint. Failed checks abort the commit, preventing poorly formatted code from entering the repo.

Submodules and Subtrees

Submodules and subtrees let you include external repositories inside your project. Submodules maintain a pointer to a specific commit in another repo. Subtrees merge the external repo history directly into your project tree.

Tip: Submodules are better when you need to pin an exact version of a dependency and update it explicitly. Subtrees are simpler for consumers because they do not require special clone commands. Many teams prefer subtrees for shared libraries and submodules for vendored dependencies.
# Submodules: pointer to external repo commit
git submodule add https://github.com/lib/utils.git libs/utils
git submodule update --init --recursive
git submodule update --remote         # pull latest

# Clone repo with submodules
git clone --recurse-submodules https://github.com/org/project

# Subtrees: merge external repo into your tree
git subtree add --prefix=libs/utils \
  https://github.com/lib/utils.git main --squash

# Pull updates from subtree remote
git subtree pull --prefix=libs/utils \
  https://github.com/lib/utils.git main --squash

# Push changes back to subtree remote
git subtree push --prefix=libs/utils \
  https://github.com/lib/utils.git main
Deep dive: A .gitmodules file tracks submodule URLs and paths. After cloning a repo with submodules, run git submodule update --init --recursive. Forgetting this step is the most common submodule issue. With subtrees, all code lives in your repo so consumers never need extra commands.

Monorepo vs Multi-repo

Monorepos store all projects in a single repository, simplifying dependency management and atomic cross-project changes. Multi-repos give teams autonomy and isolation. Submodules bridge both approaches: a parent repo references child repos at specific commits. Tools like Nx, Turborepo, and Lerna help manage monorepo builds and dependency graphs.

Merge vs Rebase

Merge creates a merge commit preserving branch history. Rebase replays commits on top of another branch creating a linear history. Each approach has tradeoffs in readability, conflict resolution, and collaboration safety.

Tip: A common team convention is to rebase locally before opening a pull request, then merge the PR with a merge commit on the main branch. This gives you clean individual commits plus a clear record of when features were integrated.
# Merge: preserves branch history
git checkout main
git merge feature/auth --no-ff    # always create merge commit

# Rebase: linear history
git checkout feature/auth
git rebase main                   # replay commits on main
git checkout main
git merge feature/auth            # fast-forward merge

# Resolve conflicts during rebase
git rebase main
# CONFLICT in file.js
# Edit file.js to resolve
git add file.js
git rebase --continue

# Merge strategies
git merge -s ours legacy-branch   # keep ours, discard theirs
git merge -X theirs feature       # prefer theirs on conflict
Deep dive: The --no-ff flag on merge always creates a merge commit even when a fast-forward is possible. This preserves the branch topology so you can see when a feature branch was merged. Some teams prefer squash merges to collapse an entire feature branch into a single commit on main.

Conflict Resolution Tips

Use git mergetool to open a visual diff tool. Configure merge.conflictstyle=diff3 to see the common ancestor alongside both sides of a conflict. After resolving, use git diff --check to verify no conflict markers remain. For rerere (reuse recorded resolution), enable it with git config rerere.enabled true to auto-resolve repeated conflicts.

Squash Merge Strategy

Squash merge combines all commits from a feature branch into a single commit on the target branch. This creates a clean main branch history where each commit represents a complete feature. The tradeoff is losing individual commit history from the feature branch. GitHub and GitLab offer squash merge as a PR merge option alongside regular merge and rebase merge.

Git Reflog

The reflog records every change to HEAD and branch tips, including commits, rebases, resets, and checkouts. It is your safety net for recovering lost commits, undoing bad rebases, and restoring deleted branches.

Tip: Reflog entries expire after 90 days for reachable commits and 30 days for unreachable ones. You can change this with gc.reflogExpire and gc.reflogExpireUnreachable. After a bad operation, check the reflog immediately before running git gc.
# View reflog (every HEAD movement)
git reflog
# abc1234 HEAD@{0}: commit: add feature
# def5678 HEAD@{1}: rebase: updating HEAD
# ghi9012 HEAD@{2}: checkout: moving to main

# Recover from bad rebase
git reset --hard HEAD@{2}         # go back to before rebase

# Restore a deleted branch
git reflog | grep "checkout: moving from feature"
git checkout -b feature/restored abc1234

# Recover a dropped stash
git fsck --unreachable | grep commit
git stash apply <sha>

# Reflog for a specific branch
git reflog show feature/auth
Deep dive: The reflog is local only and is not shared when you push or pull. Each developer has their own reflog. If you accidentally force-push over a remote branch, the remote reflog (if the server supports it) or another team member local reflog may be your only recovery option.

Common Recovery Patterns

The most frequent recovery scenarios are: undoing a bad rebase (reset to reflog entry before rebase), restoring a deleted branch (find last commit SHA in reflog), recovering an amended commit (the previous version exists in reflog), and retrieving a dropped stash (use git fsck to find unreachable commit objects).

Reflog vs git fsck

Reflog tracks HEAD and branch tip movements, so it finds commits that were recently referenced. Git fsck --unreachable finds all orphaned objects, including those never referenced by any branch. Use reflog first for recent recovery, and fsck as a last resort for objects that fell outside the reflog window.

Signing Commits

Signed commits prove that code was authored by a verified identity. GitHub and GitLab display a verified badge next to signed commits. You can sign with GPG keys or SSH keys (Git 2.34+).

Tip: SSH signing is simpler than GPG because most developers already have SSH keys. Configure an allowed_signers file to verify signatures from your team. Organizations can require signed commits via branch protection rules.
# GPG signing setup
gpg --full-generate-key           # generate GPG key
gpg --list-secret-keys --keyid-format=long
git config --global user.signingkey ABC123DEF456
git config --global commit.gpgsign true

# SSH signing (Git 2.34+)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

# Sign a single commit
git commit -S -m "feat: signed commit"

# Verify signatures
git log --show-signature -1
git verify-commit HEAD
git verify-tag v1.0.0
Deep dive: To verify SSH-signed commits locally, create an allowed_signers file listing trusted public keys in the format: email nametype base64key. Then set gpg.ssh.allowedSignersFile in your git config. This enables git verify-commit and git log --show-signature to validate signatures.

Vigilant Mode

GitHub offers vigilant mode which marks unsigned commits as unverified, making it clear when a commit lacks a valid signature. Enable it in your GitHub settings under SSH and GPG keys. Combined with branch protection rules requiring signed commits, this creates a strong chain of trust for your codebase.

Signing Tags for Releases

Use git tag -s v1.0.0 to create a signed annotated tag. Signed tags verify that a release was created by an authorized person. CI pipelines can verify tag signatures before building and deploying. This is especially important for open source projects where anyone can submit pull requests but only maintainers should create releases.

Large File Storage

Git LFS replaces large files (images, videos, binaries, datasets) with lightweight pointer files in your repository, storing the actual file content on a remote server. This keeps your repo small and clone times fast.

Tip: Track large files with LFS before committing them. If you accidentally commit a large file without LFS, use git lfs migrate to rewrite history. Most Git hosts (GitHub, GitLab, Bitbucket) include free LFS storage with limits.
# Install and initialize Git LFS
git lfs install

# Track file patterns
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "datasets/**"

# .gitattributes is updated automatically
# *.psd filter=lfs diff=lfs merge=lfs -text

git add .gitattributes
git add assets/design.psd
git commit -m "feat: add design files with LFS"

# Check LFS status
git lfs ls-files                  # list tracked files
git lfs status                    # show pending changes
git lfs env                       # show LFS config

# Migrate existing files to LFS
git lfs migrate import --include="*.psd"
Deep dive: LFS pointer files are small text files containing the SHA-256 hash and size of the actual content. During checkout, LFS hooks download the real file from the LFS server. During push, the smudge and clean filters upload new large files automatically. This is transparent to your normal Git workflow.

LFS Best Practices

Add .gitattributes to your repo before tracking files with LFS. Use git lfs migrate to convert existing large files. Set up LFS locking for binary files that cannot be merged (design files, compiled assets). Monitor your LFS storage usage, as most hosts charge for bandwidth and storage beyond free tiers.

Advanced Log and Diff

Git log and diff have powerful formatting and filtering options. Pretty formats create custom output for changelogs and reports. Diff algorithms like patience and histogram produce cleaner diffs for complex changes.

Tip: The pickaxe option (-S) searches for commits that add or remove a specific string. The -G option searches for commits where the diff matches a regex. These are invaluable for understanding when and why a function was introduced or removed.
# Pretty log formats
git log --oneline --graph --all --decorate
git log --pretty=format:"%h %an %ar %s" -10
git log --since="2 weeks ago" --author="Alice"
git log --grep="fix:" --oneline

# Diff algorithms for cleaner output
git diff --patience file.js       # better for moved blocks
git diff --histogram               # improved patience
git diff --word-diff               # inline word changes

# Find who changed a line
git blame -L 10,20 src/app.js
git log -p -S "functionName"      # pickaxe search

# Shortlog for changelogs
git shortlog -sn --no-merges      # commit count by author
git log --format="%s" v1.0..v2.0  # messages between tags
Deep dive: The patience diff algorithm handles moved code blocks better than the default Myers algorithm by finding unique matching lines first. The histogram algorithm is an optimized version of patience used by default in JGit. For word-level changes, use --word-diff=color to highlight inline modifications.

Useful Git Aliases

Create aliases for frequently used log and diff commands. Add them to your global .gitconfig under the [alias] section. Popular aliases include lg for a decorated graph log, last for showing the last commit, unstage for resetting staged files, and amend for amending the last commit without editing the message.

Repository Statistics

Use git shortlog -sn to rank contributors by commit count. Use git log --format="%ae" | sort | uniq -c | sort -rn to list contributors by email. The git diff --stat command shows a summary of changed files. For detailed contribution analytics, tools like git-fame and gitstats generate comprehensive reports with charts and timelines.

CI/CD Integration

Git integrates tightly with CI/CD pipelines. Conventional commits enable automated versioning with semantic release. GitHub Actions workflows trigger on push, pull request, or tag events to build, test, and deploy automatically.

Tip: Conventional commits follow a structured format: type(scope): description. Types include feat, fix, docs, style, refactor, test, and chore. Tools like commitlint enforce this format, and semantic-release uses it to determine version bumps and generate changelogs.
# .github/workflows/ci.yml
name: CI Pipeline
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm test

# Conventional commits + semantic release
# feat: -> minor, fix: -> patch, BREAKING CHANGE: -> major
npm install -D semantic-release
npx semantic-release              # auto version + changelog
Deep dive: Semantic-release analyzes commit messages since the last release to determine the next version number. A feat commit triggers a minor bump, a fix triggers a patch, and a BREAKING CHANGE footer triggers a major bump. It can also generate release notes, create GitHub releases, and publish to npm automatically.

Branch Protection Rules

Configure branch protection on main to require pull request reviews, passing CI checks, signed commits, and linear history. This prevents direct pushes to main, ensures code review, and maintains a clean commit history. GitHub, GitLab, and Bitbucket all support these rules with varying granularity.

Automated Changelog Generation

Tools like conventional-changelog and release-please parse conventional commit messages to generate formatted changelogs. Each release section groups changes by type: features, bug fixes, breaking changes, and documentation updates. This eliminates manual changelog maintenance and ensures every merged PR is documented.

Frequently Asked Questions

What is the difference between git merge and git rebase?

Merge creates a merge commit that combines two branches, preserving full history. Rebase replays your commits on top of the target branch, creating a linear history. Use merge for shared branches, rebase for local cleanup.

How do I undo a git rebase?

Use git reflog to find the commit before the rebase, then git reset --hard to that commit. The reflog records every HEAD change, so you can always recover from a bad rebase.

Should I use Git Flow or trunk-based development?

Use Git Flow for teams with scheduled releases and multiple environments. Use trunk-based development for teams practicing continuous deployment with feature flags and short-lived branches.

How do I sign commits with SSH keys?

Configure git with gpg.format=ssh and user.signingkey pointing to your SSH public key. Then use git commit -S to sign. Git 2.34+ supports SSH signing natively.

What is git bisect and when should I use it?

Git bisect performs a binary search through your commit history to find the exact commit that introduced a bug. Mark a known good commit and a bad commit, then bisect tests the midpoint until it isolates the offending commit.

How does Git LFS work?

Git LFS replaces large files with small pointer files in your repo. The actual file content is stored on a separate LFS server. Git LFS hooks intercept checkout and push operations to download and upload large files transparently.

What are the most useful git hooks?

Pre-commit runs linters and formatters before each commit. Commit-msg validates commit message format. Pre-push runs tests before pushing. Use Husky or lefthook to manage hooks across your team.

How do I recover a deleted branch?

Use git reflog to find the last commit on the deleted branch, then git checkout -b branch-name commit-sha to recreate it. Reflog entries persist for 90 days by default, giving you a generous recovery window.

𝕏 Twitterin LinkedIn
บทความนี้มีประโยชน์ไหม?

อัปเดตข่าวสาร

รับเคล็ดลับการพัฒนาและเครื่องมือใหม่ทุกสัปดาห์

ไม่มีสแปม ยกเลิกได้ตลอดเวลา

ลองเครื่องมือที่เกี่ยวข้อง

{ }JSON Formatter.*Regex TesterMDMarkdown to HTML

บทความที่เกี่ยวข้อง

DevOps Pipeline Guide: CI/CD, GitHub Actions, Docker, Infrastructure as Code & Deployment Strategies

Complete DevOps pipeline guide covering CI/CD fundamentals, GitHub Actions, GitLab CI, Docker multi-stage builds, Terraform, Pulumi, deployment strategies, secrets management, GitOps, and pipeline security.

Clean Code Guide: Naming Conventions, SOLID Principles, Code Smells, Refactoring & Best Practices

Comprehensive clean code guide covering naming conventions, function design, SOLID principles, DRY/KISS/YAGNI, code smells and refactoring, error handling patterns, testing, code review, design by contract, and clean architecture.

Linux Command Guide: File System, Text Processing, Networking, Shell Scripting & Security

Complete Linux command guide covering file system navigation, text processing with grep/sed/awk, process management, networking, disk management, package managers, shell scripting, I/O redirection, system monitoring, and security commands.