[{"data":1,"prerenderedAt":2951},["ShallowReactive",2],{"navigation":3,"search-sections":42,"blog-featured-8":441},[4],{"title":5,"path":6,"stem":7,"children":8,"page":41},"Blogs","\u002Fblogs","blogs",[9,13,17,21,25,29,33,37],{"title":10,"path":11,"stem":12},"Getting Started with ESP32 - A Comprehensive Guide to Installing ESP-IDF on Ubuntu","\u002Fblogs\u002Fesp-idf-ubuntu-setup","blogs\u002Fesp-idf-ubuntu-setup",{"title":14,"path":15,"stem":16},"Automate Your Release Notes - Building a Conventional Commit Changelog Hook","\u002Fblogs\u002Fgit-changelog-hook","blogs\u002Fgit-changelog-hook",{"title":18,"path":19,"stem":20},"Master Git Housekeeping - Auto-Pruning Dead Tracking Branches and Fixing Detached HEADs","\u002Fblogs\u002Fgit-housekeeping","blogs\u002Fgit-housekeeping",{"title":22,"path":23,"stem":24},"Supercharge Your Git Workflow - Automate Quality Control with Pre-Commit Hooks","\u002Fblogs\u002Fgit-pre-commit","blogs\u002Fgit-pre-commit",{"title":26,"path":27,"stem":28},"Safely Update All Local Git Branches At Once Without Breaking Your Working Tree","\u002Fblogs\u002Fgit-pull-all","blogs\u002Fgit-pull-all",{"title":30,"path":31,"stem":32},"Debug Pipelines Locally - The Complete Guide to Running GitHub Actions with Act","\u002Fblogs\u002Flocal-github-actions","blogs\u002Flocal-github-actions",{"title":34,"path":35,"stem":36},"Setting Up a PlatformIO Project with ESP-IDF - step-by-step Guide","\u002Fblogs\u002Fplatformio-esp-idf-setup","blogs\u002Fplatformio-esp-idf-setup",{"title":38,"path":39,"stem":40},"Bash-ify Your PowerShell - The Ultimate Guide to Autosuggestions, Completions, and Subcommands","\u002Fblogs\u002Fpowershell-bash","blogs\u002Fpowershell-bash",false,[43,47,53,59,64,69,74,79,84,89,94,99,104,110,115,120,125,130,133,138,143,148,153,158,163,168,173,178,183,186,191,196,201,206,210,215,220,225,229,232,237,242,247,252,257,261,264,269,274,279,284,289,294,298,301,306,311,316,321,326,331,336,341,346,351,355,358,363,368,373,378,383,388,393,398,403,408,411,416,421,426,431,436],{"id":11,"title":10,"titles":44,"content":45,"level":46},[],"Master the complete installation workflow for Espressif SoCs on Ubuntu. Learn to configure dependencies, purge line-ending bugs, compile firmware, and manage ports. Setting up an embedded development ecosystem on Linux shouldn't feel like guesswork. While Espressif's IoT Development Framework (ESP-IDF) provides massive flexibility for targeting microcontrollers like the standard ESP32, ESP32-S3, or ESP32-C3, configuring the native tools requires a precise sequence of system dependency curation and shell workspace preparation. This comprehensive guide details the absolute path to setting up a production-ready ESP-IDF development environment natively on an Ubuntu system, including fixes for line endings (CRLF), peripheral port configurations, and shell environment persistence.",1,{"id":48,"title":49,"titles":50,"content":51,"level":52},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#preparing-host-tools-and-dependencies","Preparing Host Tools and Dependencies",[10],"The ESP-IDF toolchain requires specific host utility packages—ranging from build engines like CMake and Ninja to cross-compilation system modules. Update your internal package paths first using the Advanced Package Tool (APT):",2,{"id":54,"title":55,"titles":56,"content":57,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#refresh-system-software-index-repositories","Refresh system software index repositories",[10,49],"sudo apt update",3,{"id":60,"title":61,"titles":62,"content":63,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#install-required-build-tools-python-environments-and-underlying-usb-port-managers","Install required build tools, Python environments, and underlying USB port managers",[10,49],"sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv \\\ncmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 dos2unix Ensure your Python installation is functional before proceeding: python3 --version",{"id":65,"title":66,"titles":67,"content":68,"level":52},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#cloning-the-target-code-repository","Cloning the Target Code Repository",[10],"Create a structured development folder inside your user home directory to house the framework workspace. To keep things highly compatible across active projects, clone the repository while explicitly retaining structural submodules:",{"id":70,"title":71,"titles":72,"content":73,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#form-the-core-directory-path","Form the core directory path",[10,66],"mkdir -p ~\u002Fesp\ncd ~\u002Fesp",{"id":75,"title":76,"titles":77,"content":78,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#clone-the-main-repository-framework-into-a-local-folder-named-espidf","Clone the main repository framework into a local folder named espidf",[10,66],"git clone --recursive https:\u002F\u002Fgithub.com\u002Fespressif\u002Fesp-idf.git espidf",{"id":80,"title":81,"titles":82,"content":83,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#the-broken-submodule-catch-all","The Broken Submodule Catch-All",[10,66],"If you previously pulled down the project files but skipped the submodule dependencies during initialization, your local repository tree will sit in an incomplete state. Repair it instantly by running: cd ~\u002Fesp\u002Fespidf\ngit submodule update --init --recursive",{"id":85,"title":86,"titles":87,"content":88,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#purging-cross-platform-shebang-line-issues","Purging Cross-Platform Shebang Line Issues",[10,66],"If your repository configurations pass through host file servers or a Windows subsystem before arriving on your Ubuntu box, line endings can easily convert from Unix LF format to Windows CRLF formats. This hidden alteration triggers terminal script rejections like: usr\u002Fbin\u002Fenv: ‘bash\\r’: No such file or directory Fix this instantly across your whole localized repository tree before calling any internal installer scripts: cd ~\u002Fesp\u002Fespidf\n\n### Force any corrupted shell scripts back into proper native Unix layout parameters\nfind . -name \"*.sh\" -exec dos2unix {} +",{"id":90,"title":91,"titles":92,"content":93,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#triggering-the-toolchain-installation","Triggering the Toolchain Installation",[10,66],"With clean formatting secured, execute the structural installation script. While you can opt to install tool sets for every single target variant via .\u002Finstall.sh all, targeting only your explicit board framework saves hours of disk read times and download space. For standard boards such as the ESP32-DevKitC (esp32dev), pass the esp32 parameter directly: cd ~\u002Fesp\u002Fespidf\n.\u002Finstall.sh esp32 This script builds an isolated Python environment and populates custom cross-compilation binaries (such as xtensa-esp32-elf) natively within a hidden directory layout (~\u002F.espressif).",{"id":95,"title":96,"titles":97,"content":98,"level":52},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#mapping-the-active-shell-workspace","Mapping the Active Shell Workspace",[10],"The environment tools are completely isolated by design to prevent conflicting with regular Linux operations. Consequently, you must load the active tool configuration paths into your shell workspace session before compilation.",{"id":100,"title":101,"titles":102,"content":103,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#source-the-configuration-environment-map-directly","Source the configuration environment map directly",[10,96],"cd ~\u002Fesp\u002Fespidf\n. .\u002Fexport.sh",{"id":105,"title":106,"titles":107,"content":108,"level":109},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#establishing-a-permanent-environment-shortcut","Establishing a Permanent Environment Shortcut",[10,96,101],"Running that explicit script string manually every time you launch a fresh Ubuntu terminal window is tedious. Simplify your pathing by introducing a terminal profile alias: Open your native terminal profile configuration: nano ~\u002F.bashrc Paste this macro line at the absolute bottom of the document space: alias get_idf='. ~\u002Fesp\u002Fespidf\u002Fexport.sh' Save the changes and exit ( +    + ). Now, entering the lightweight command get_idf inside any new bash terminal session instantly prepares your environment workspace.",4,{"id":111,"title":112,"titles":113,"content":114,"level":52},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#project-compilation-flashing-and-port-access","Project Compilation, Flashing, and Port Access",[10],"With your environment loaded cleanly, test the complete pipeline by spinning up a fresh workspace program outside of your framework code repository path:",{"id":116,"title":117,"titles":118,"content":119,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#copy-a-foundational-template-application-to-your-workspace","Copy a foundational template application to your workspace",[10,112],"cp -r ~\u002Fesp\u002Fespidf\u002Fexamples\u002Fget-started\u002Fhello_world ~\u002Fesp\u002F\ncd ~\u002Fesp\u002Fhello_world\n## Clean up any lingering or corrupted configuration file configurations\nrm -rf build\u002F\n\n## Target your hardware profile layout parameters\nidf.py set-target esp32",{"id":121,"title":122,"titles":123,"content":124,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#managing-system-port-permissions","Managing System Port Permissions",[10,112],"When you plug your ESP32 board into a USB port on Ubuntu, the kernel creates devices like \u002Fdev\u002FttyUSB0 or \u002Fdev\u002FttyACM0. However, standard Linux users lack read\u002Fwrite permissions for these devices by default, causing flashing attempts to fail with a Permission Denied error. Grant your active system user profile permanent access privileges: sudo usermod -aG dialout $USER You must log out of your Ubuntu user session completely and log back in for this access mapping to apply to your terminal terminal.",{"id":126,"title":127,"titles":128,"content":129,"level":58},"\u002Fblogs\u002Fesp-idf-ubuntu-setup#compiling-flashing-and-monitoring","Compiling, Flashing, and Monitoring",[10,112],"Chain your final terminal steps together to execute compilation, flash binaries directly to your hardware, and capture serial terminal output in real time: idf.py build flash monitor To exit the real-time serial monitor window safely at any time, press  + . html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"id":15,"title":14,"titles":131,"content":132,"level":46},[],"Stop writing release notes by hand. Learn how to pair Conventional Commits with a prepare-commit-msg hook to auto-generate crisp, readable project changelogs. Writing release notes at the end of a sprint is a tedious chore that usually results in vague updates like \"Fixed bugs and updated files.\" Your clients, project managers, and fellow developers deserve to know exactly what changed without scrolling through a messy git log history. The solution isn't to work harder; it is to standardize your commit entries. By pairing the Conventional Commits specification with automated Git hooks, your workspace can dynamically update a beautiful, hyper-accurate CHANGELOG.md file every time you tag a new software version.",{"id":134,"title":135,"titles":136,"content":137,"level":52},"\u002Fblogs\u002Fgit-changelog-hook#step-1-core-architecture-conventional-commits","Step 1: Core Architecture — Conventional Commits",[14],"Automated changelogs only work if your computer can read and categorize your commit messages. Conventional Commits provide a strict structure that looks like this: \u003Ctype>(\u003Coptional scope>): \u003Cdescription>\n\n[optional body]\n[optional footer(s)]",{"id":139,"title":140,"titles":141,"content":142,"level":58},"\u002Fblogs\u002Fgit-changelog-hook#common-types-feat-a-brand-new-application-feature-for-the-user","Common Types:- feat: A brand new application feature for the user.",[14,135],"fix: A bug resolution or patch.docs: Documentation changes only.style: Formatting, missing semicolons, or design updates (no code logic changes).refactor: Code changes that neither fix a bug nor add a feature.",{"id":144,"title":145,"titles":146,"content":147,"level":52},"\u002Fblogs\u002Fgit-changelog-hook#step-2-enforcing-the-standard-with-commitlint","Step 2: Enforcing the Standard with commitlint",[14],"Before we generate a changelog, we must block non-conforming commit messages. We can tie this verification step right into our existing pre-commit framework using commitlint. Open your project's .pre-commit-config.yaml file.Append the following block to install the validation engine: - repo: https:\u002F\u002Fgithub.com\n\n  rev: v9.16.0\n  hooks:\n    - id: commitlint\n      stages: [commit-msg]\n      additional_dependencies: [\"@commitlint\u002Fconfig-conventional\"] Create a configuration file named commitlint.config.js in your root folder to load the standard definitions: module.exports = { extends: [\"@commitlint\u002Fconfig-conventional\"] }; Register the message hook with your local Git subsystem: pre-commit install --hook-type commit-msg Now, if you try to type a lazy message like git commit -m \"fixed stuff\", your terminal will promptly reject it, forcing your message structure to stay uniform.",{"id":149,"title":150,"titles":151,"content":152,"level":52},"\u002Fblogs\u002Fgit-changelog-hook#step-3-setting-up-the-automated-changelog-pipeline","Step 3: Setting Up the Automated Changelog Pipeline",[14],"To extract these standardized logs into a markdown file, we will use Commitizen and Standard-Version (or its modern equivalent, cliff-or-cz). For maximum flexibility across any development environment, we will use a lightweight Python tool named cz-cli or Node-based standard-version. Let's configure it via NPM for general engineering environments: npm install -g standard-version Add an execution shortcut script to your project's package.json file: {\n  \"scripts\": {\n    \"release\": \"standard-version\"\n  }\n} When you execute your new command, the runner automates a multi-step workflow: It reviews all commit logs since your last tag.It bumps your project version number following semantic versioning rules (v1.0.0 -> v1.1.0).It generates or updates your CHANGELOG.md file dynamically.It creates a local git tag for the new release.",{"id":154,"title":155,"titles":156,"content":157,"level":52},"\u002Fblogs\u002Fgit-changelog-hook#step-4-the-post-commit-automated-hook","Step 4: The Post-Commit Automated Hook",[14],"If you want the changelog update process to trigger entirely behind the scenes whenever a release or merge happens, you can link it directly into your git workflow using a post-commit hook. Create a file named .git\u002Fhooks\u002Fpost-merge (or configure it in your pipeline tools): #!\u002Fbin\u002Fbash\n# Check if the last commit was a formal release version switch\nif git log -1 --pretty=%B | grep -q \"chore(release):\"; then\n    echo \"Release commit detected. Pushing updated documentation...\"\n    git push --follow-tags origin main\nfi",{"id":159,"title":160,"titles":161,"content":162,"level":58},"\u002Fblogs\u002Fgit-changelog-hook#the-end-result-your-new-changelogmd","The End Result: Your New CHANGELOG.md",[14,155],"The pipeline aggregates your individual commits and transforms them instantly into clean markdown:",{"id":164,"title":165,"titles":166,"content":167,"level":52},"\u002Fblogs\u002Fgit-changelog-hook#_120-2026-06-29","1.2.0 (2026-06-29)",[14],"",{"id":169,"title":170,"titles":171,"content":172,"level":58},"\u002Fblogs\u002Fgit-changelog-hook#features","Features",[14,165],"auth: added interactive two-factor authentication flow (a1b2c3d)terminal: injected carapace subcommand engine (e5f6g7h)",{"id":174,"title":175,"titles":176,"content":177,"level":58},"\u002Fblogs\u002Fgit-changelog-hook#bug-fixes","Bug Fixes",[14,165],"profile: resolved broken path lookup inside windows systems (z9y8x7w)",{"id":179,"title":180,"titles":181,"content":182,"level":52},"\u002Fblogs\u002Fgit-changelog-hook#wrapping-up","Wrapping Up",[14],"By delegating your documentation to a structured commit linting framework, you completely delete release coordination overhead. Your code history stays searchable, your changes remain organized, and your project stakeholders get crisp release descriptions updated completely on autopilot. html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"id":19,"title":18,"titles":184,"content":185,"level":46},[],"Clean up the debris after a massive local sync. Learn how to automatically drop deleted remote tracking branches and rescue your code from a detached HEAD state. Once you automate your local branch syncs, you will quickly notice a secondary annoying problem: ghost branches. Your teammates delete their feature branches on GitHub after pulling a pull request, but those references still clutter your local git branch -a view forever. Worse yet, if an automated script or manual checkout accidentally lands you on a raw commit identifier instead of a formal pointer, you will drop straight into the twilight zone known as a detached HEAD state. Here is how to automate your repository cleanup and rescue your code when Git loses its coordinates.",{"id":187,"title":188,"titles":189,"content":190,"level":52},"\u002Fblogs\u002Fgit-housekeeping#step-1-automate-stale-branch-pruning","Step 1: Automate Stale Branch Pruning",[18],"By default, when you run git fetch or git pull, Git keeps your local tracking copies of remote branches even if someone deleted them from the main cloud server. Your local machine is left holding a graveyard of stale references. You can manually clean them up using: git fetch --prune But you shouldn't have to remember to type that flag every single time.",{"id":192,"title":193,"titles":194,"content":195,"level":58},"\u002Fblogs\u002Fgit-housekeeping#the-permanent-fix-run-this-global-configuration-command-to-instruct-git-to-automatically-sweep-away-dead-remote-branch-pointers-during-every-single-sync-operation","The Permanent Fix Run this global configuration command to instruct Git to automatically sweep away dead remote branch pointers during every single sync operation:",[18,188],"git config --global fetch.prune true Now, your project history list actively auto-cleans itself without manual intervention.",{"id":197,"title":198,"titles":199,"content":200,"level":52},"\u002Fblogs\u002Fgit-housekeeping#step-2-demystifying-and-fixing-the-detached-head","Step 2: Demystifying and Fixing the \"Detached HEAD\"",[18],"A detached HEAD state occurs when your terminal pointer (HEAD) is looking directly at a specific commit hash rather than a named local branch (like main or feature-login).",{"id":202,"title":203,"titles":204,"content":205,"level":58},"\u002Fblogs\u002Fgit-housekeeping#how-you-usually-get-there-you-checked-out-a-raw-commit-to-inspect-old-code-git-checkout-7a1b3c2","How you usually get there:- You checked out a raw commit to inspect old code: git checkout 7a1b3c2",[18,198],"You checked out a remote branch directly without creating a local copy: git checkout origin\u002Ffeature-x- An automation script errored out mid-transition.",{"id":207,"title":208,"titles":209,"content":167,"level":58},"\u002Fblogs\u002Fgit-housekeeping#the-danger-zoneyou-can-still-write-code-modify-files-and-make-commits-while-in-a-detached-head-state-however-these-new-commits-are-not-attached-to-any-branch-if-you-switch-back-to-main-your-new-changes-will-vanish-into-the-background-leaving-them-open-to-being-permanently-deleted-by-gits-garbage-collector","The Danger ZoneYou can still write code, modify files, and make commits while in a detached HEAD state. However, these new commits are not attached to any branch. If you switch back to main, your new changes will vanish into the background, leaving them open to being permanently deleted by Git's garbage collector.",[18,198],{"id":211,"title":212,"titles":213,"content":214,"level":52},"\u002Fblogs\u002Fgit-housekeeping#step-3-the-detached-head-rescue-mission","Step 3: The Detached HEAD Rescue Mission",[18],"If you realize you made commits while detached, do not panic. Your work is completely safe if you follow these precise steps.",{"id":216,"title":217,"titles":218,"content":219,"level":58},"\u002Fblogs\u002Fgit-housekeeping#scenario-a-you-havent-left-the-detached-state-yetif-your-terminal-currently-says-head-detached-at-simply-wrap-your-floating-commits-into-a-brand-new-branch-immediately","Scenario A: You haven't left the detached state yetIf your terminal currently says HEAD detached at..., simply wrap your floating commits into a brand new branch immediately:",[18,212],"# Create a new branch and switch to it right now\ngit checkout -b feature-rescued-work Git automatically anchors all your floating commits directly to this new branch name. You can now safely merge it back into your primary workflow.",{"id":221,"title":222,"titles":223,"content":224,"level":58},"\u002Fblogs\u002Fgit-housekeeping#scenario-b-you-already-switched-branches-and-your-work-vanishedif-you-accidentally-switched-back-to-main-and-your-recent-work-disappeared-gits-commit-history-tool-git-log-wont-show-it-you-must-query-the-deep-internal-log-system","Scenario B: You already switched branches and your work \"vanished\"If you accidentally switched back to main and your recent work disappeared, Git's commit history tool (git log) won't show it. You must query the deep internal log system:",[18,212],"git reflog This outputs a master transaction history of everywhere your terminal pointer has moved: 7a1b3c2 HEAD@{0}: checkout: moving from 9f3e4d5 to main\n9f3e4d5 HEAD@{1}: commit: Added critical hotfix code in detached state\n7a1b3c2 HEAD@{2}: checkout: moving to 7a1b3c2 Find the commit hash where you wrote your work (in this case, 9f3e4d5).2. Target that hash to build a formal rescue branch: git branch feature-recovered-commits 9f3e4d5 Your changes are successfully pulled from the void into a clean, permanent tracking pointer.",{"id":226,"title":180,"titles":227,"content":228,"level":52},"\u002Fblogs\u002Fgit-housekeeping#wrapping-up",[18],"Maintaining a pristine repository requires a blend of automated configurations and conceptual awareness. By enforcing automatic reference pruning and mastering the mechanics of the reflog, you ensure your developer workspace remains highly performant, predictable, and resilient against unexpected operational mistakes. html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"id":23,"title":22,"titles":230,"content":231,"level":46},[],"Stop pushing broken code or accidental API keys. Learn how to configure a multi-language pre-commit pipeline that scans your staged files completely offline. We have all done it. You type a fast git commit -m \"fix typo\", push it straight to production, and immediately break the automated CI\u002FCD pipeline because you left a missing trailing semicolon, a broken bracket, or worse—a raw, unencrypted API key. Instead of relying on remote servers to find your silly mistakes, you can force your local machine to check your work first. By leveraging Pre-Commit Hooks, Git will automatically run your code through a gauntlet of formatters, linters, and security scanners. If anything is broken, it blocks the commit right on your desktop before it can ever infect your shared repository history.",{"id":233,"title":234,"titles":235,"content":236,"level":52},"\u002Fblogs\u002Fgit-pre-commit#step-1-why-built-in-git-hooks-are-clunky","Step 1: Why Built-In Git Hooks Are Clunky",[22],"If you look inside any project workspace directory under .git\u002Fhooks\u002F, you will see a collection of sample shell scripts. You could write raw Bash scripts inside .git\u002Fhooks\u002Fpre-commit directly, but this approach has two massive problems: Non-Transferable: The .git\u002F folder is strictly ignored by your project history. Your team cannot download or share your custom hook rules.2. Maintenance Nightmare: Writing custom logic to isolate only changed lines, handle multiple languages, and format files safely takes hundreds of lines of brittle bash syntax. To fix this, we use the industry-standard pre-commit framework. It abstracts away the complex logic into a single, clean configuration file.",{"id":238,"title":239,"titles":240,"content":241,"level":52},"\u002Fblogs\u002Fgit-pre-commit#step-2-installing-the-pre-commit-framework","Step 2: Installing the Pre-Commit Framework",[22],"First, install the pipeline manager tool using your favorite system package manager: # macOS (Homebrew)\nbrew install pre-commit\n\n# Windows (Winget or Pip)\nwinget install pre-commit\n# OR: pip install pre-commit Verify that the installation was successful by checking the version string: pre-commit --version",{"id":243,"title":244,"titles":245,"content":246,"level":52},"\u002Fblogs\u002Fgit-pre-commit#step-3-architecting-your-multi-language-blueprint","Step 3: Architecting Your Multi-Language Blueprint",[22],"Navigate to the root directory of your project repository and create a brand new configuration file named .pre-commit-config.yaml: touch .pre-commit-config.yaml Open this new file and paste the following high-utility core structure. This layout handles standard code hygiene, layout formatting, and automated security scans all at once: # See https:\u002F\u002Fpre-commit.com for more information\n# See https:\u002F\u002Fpre-commit.com for more community hooks\n\nrepos:\n  # 1. Standard Code Hygiene & Cleanup\n  - repo: https:\u002F\u002Fgithub.com\n\n    rev: v4.6.0 # Use the latest stable version\n    hooks:\n      - id: trailing-whitespace # Trims unnecessary spaces at the end of lines\n      - id: end-of-file-fixer # Ensures files end with a standard newline character\n      - id: check-yaml # Validates structural syntax of all YAML files\n      - id: check-added-large-files # Blocks giant files from accidentally bloating the repo\n\n  # 2. Security: Stop Secret & Credential Leaking\n  - repo: https:\u002F\u002Fgithub.com\n\n    rev: v8.18.2\n    hooks:\n      - id: gitleaks-system # Scans staged lines for AWS, Stripe, or GitHub API tokens\n\n  # 3. Code Formatting (Example: Python\u002FWeb Assets)\n  - repo: https:\u002F\u002Fgithub.com\n\n    rev: 24.4.2\n    hooks:\n      - id: black # Instantly formats Python files to strict style guides",{"id":248,"title":249,"titles":250,"content":251,"level":52},"\u002Fblogs\u002Fgit-pre-commit#step-4-activating-your-local-shield","Step 4: Activating Your Local Shield",[22],"Creating the configuration configuration file isn't enough; you must explicitly instruct Git to bind itself to the pipeline manager engine. Run this command inside your project root: pre-commit install```\n\nYou will see a success output: `pre-commit installed at .git\u002Fhooks\u002Fpre-commit`.\n\nFrom now on, whenever you execute a `git commit`, the pre-commit manager intercepts the action, extracts only your staged code changes, and runs them through your configured tools.\n\n### What Happens When a Hook Fails?\nIf the pipeline catches an error (e.g., you left extra spaces or `gitleaks` flags a secret string), the process will abort entirely:\n\n```text\nTrailing Whitespace..................................Failed\nEnd of File Fixer....................................Passed\nGitleaks System......................................Passed\n[x] Commit blocked! Fix the formatting errors and stage files again. The tool will often automatically fix the formatting files directly in place for you. All you have to do is re-stage the corrected modifications (git add .) and re-run your commit command!",{"id":253,"title":254,"titles":255,"content":256,"level":52},"\u002Fblogs\u002Fgit-pre-commit#step-5-forcing-a-complete-manual-review","Step 5: Forcing a Complete Manual Review",[22],"Hooks are configured by default to only scan files that are actively changing in your current commit. If you want to force the engine to audit every single file across your entire legacy workspace tree right now, execute: pre-commit run --all-files This is highly recommended when introducing pre-commit pipelines into an older, existing project for the first time to clean out historical style issues.",{"id":258,"title":180,"titles":259,"content":260,"level":52},"\u002Fblogs\u002Fgit-pre-commit#wrapping-up",[22],"By introducing automated pre-commit triggers, you effectively build a lightweight continuous integration layer directly on your workspace terminal. You save yourself from pipeline failure notifications, protect your infrastructure from credential leaks, and guarantee that every commit pushed to your remote repository is structurally clean. html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"id":27,"title":26,"titles":262,"content":263,"level":46},[],"Stop manual checkouts. Learn why your naive git pull loops fail and discover the correct, automation-friendly way to fast-forward all local tracking branches at once. Picture this scenario. You return to a massive project repository after a long weekend. Dozens of team branches have updated on GitHub, and your local workspace feels incredibly left behind. Naturally, you decide to write a quick, clever shell script line to pull everything down at once: for branch in \\((git branch -r \\vert{} grep -v '\\->'); do git pull\\)branch; done You hit Enter, expecting a beautifully synced repository. Instead, your console explodes into a mess of syntax errors, detached HEAD states, and unexpected merge conflicts. Here is why your native git pull loops are broken, how to fix them, and the ultimate safe alternative.",{"id":265,"title":266,"titles":267,"content":268,"level":52},"\u002Fblogs\u002Fgit-pull-all#why-the-naive-script-breaks-your-repo","Why The Naive Script Breaks Your Repo",[26],"To understand why the loop above fails, you have to look closely at how git pull operates under the hood. The command relies on two distinct expectations: Active Checkouts Only: git pull is explicitly designed to download remote changes and immediately merge them into your currently checked-out local branch. It is physically incapable of updating separate background branches.Argument Syntax: git branch -r outputs remote tracking references prefixed with the remote identifier (e.g., origin\u002Ffeature-auth). Passing origin\u002Ffeature-auth directly to a git pull command breaks structural syntax. If you run this inside your main branch, the loop will continuously try to force-merge every single remote branch into your clean main history.",{"id":270,"title":271,"titles":272,"content":273,"level":52},"\u002Fblogs\u002Fgit-pull-all#the-instant-fix-trust-git-fetch-all","The Instant Fix: Trust git fetch --all",[26],"Before writing custom automation scripts, remember that you rarely need to explicitly run a git pull on branches you aren't currently coding on. If you simply want to download the latest state of the entire project to inspect histories or check things out later, run this native command: git fetch --all",{"id":275,"title":276,"titles":277,"content":278,"level":58},"\u002Fblogs\u002Fgit-pull-all#why-this-is-your-best-default","Why this is your best default:",[26,271],"Zero Risk: It downloads the raw remote objects and updates remote tracking pointers (like origin\u002Fmain) without modifying your current workspace files.No Merge Conflicts: It will never accidentally force a broken merge or pollute your active staging index.Server Friendly: It makes a single optimized network request instead of hitting your server individually for every branch reference.",{"id":280,"title":281,"titles":282,"content":283,"level":52},"\u002Fblogs\u002Fgit-pull-all#building-the-automated-local-multi-pull-script","Building the Automated Local Multi-Pull Script",[26],"If you truly need every single local branch to immediately step forward and match its remote counterpart, you must explicitly force Git to safely navigate between branches. Open a new shell script or your .bashrc\u002F.zshrc file and add this robust layout: #!\u002Fbin\u002Fbash\n\n# 1. Stash any uncommitted workspace changes so they aren't lost\nhas_changes=\\$(git status --porcelain)\nif [ -n \"\\$has_changes\" ]; then\n    echo \"Saving uncommitted work to stash...\"\n    git stash -u\nfi\n\n# 2. Save your current branch name to return safely later\ncurrent_branch=\\$(git rev-parse --abbrev-ref HEAD)\n\n# 3. Safely loop through clean local branch lists\nfor branch in \\$(git for-each-ref --format='%(refname:short)' refs\u002Fheads\u002F); do\n    echo \"Checking out \\$branch...\"\n    git checkout \"\\$branch\" 2>\u002Fdev\u002Fnull\n\n    # Use fast-forward only to avoid generating messy, unnecessary merge commits\n    echo \"Applying remote fast-forward updates...\"\n    git pull --ff-only\ndone\n\n# 4. Return to your starting point and restore work\ngit checkout \"\\$current_branch\" 2>\u002Fdev\u002Fnull\nif [ -n \"\\$has_changes\" ]; then\n    echo \"Restoring your original uncommitted changes...\"\n    git stash pop\nfi\n\necho \"✨ All local branches synced successfully!\"",{"id":285,"title":286,"titles":287,"content":288,"level":58},"\u002Fblogs\u002Fgit-pull-all#key-upgrades-in-this-script","Key upgrades in this script:",[26,281],"Stash Safety Net: It actively checks for uncommitted edits and temporarily shelves them so your checkout transitions don't error out.Fast-Forward Restrictions: Using --ff-only ensures that if a local branch has split or drifted too far from the remote history, the script will gracefully skip it rather than creating an automated merge mess.",{"id":290,"title":291,"titles":292,"content":293,"level":52},"\u002Fblogs\u002Fgit-pull-all#convert-this-into-a-permanent-git-alias","Convert This Into a Permanent Git Alias",[26],"Typing out long Bash scripts every time you open a project gets exhausting. Let's register this tool directly into your core Git configuration so it is accessible globally. Open your global git configuration file: git config --global --edit Find the [alias] block and add a new custom command named pull-all: [alias]\n    pull-all = \"!f() { \\\n        curr=\\$(git rev-parse --abbrev-ref HEAD); \\\n        for b in \\$(git for-each-ref --format='%(refname:short)' refs\u002Fheads\u002F); do \\\n            git checkout \\$b && git pull --ff-only; \\\n        done; \\\n        git checkout \\$curr; \\\n    }; f\" Save and exit. Now, clean updates across your entire workspace are compressed into a single elegant command: git pull-all",{"id":295,"title":180,"titles":296,"content":297,"level":52},"\u002Fblogs\u002Fgit-pull-all#wrapping-up",[26],"Automating your terminal flow should never come at the expense of your repository's stability. By switching from a raw git pull loop to an intentional, state-aware layout or leveraging git fetch --all, you keep your workflows smooth, fast, and entirely conflict-free. Here is some additional information for your reader. Here is a helpful suggestion. Be careful with this action as it might have unexpected results. This action cannot be undone. Lorem velit voluptate ex reprehenderit ullamco et culpa.\n:::\n\n:::tabs-item{label=\"Preview\" icon=\"i-lucide-eye\"}\n\n::callout\nLorem velit voluptate ex reprehenderit ullamco et culpa.\n::\n\n:::\n\n:: html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"id":31,"title":30,"titles":299,"content":300,"level":46},[],"Learn how to use Act to run, test, and step-debug your GitHub Actions workflows locally, saving time and keeping your commit history clean. We have all been trapped in the infamous CI\u002FCD commit loop. You make a change to a .github\u002Fworkflows\u002Fci.yml file, commit it, push it, wait five minutes for a cloud runner to spin up, and realize you missed a minor indentation or a basic syntax flag. Ten commits later, your Git history is littered with messages like \"fix ci\", \"fix ci again\", and \"please work\". It doesn’t have to be this way. By utilizing Act, an open-source tool that reads your GitHub Actions files and spins them up inside local Docker containers, you can run, test, and debug your entire automation pipeline locally in seconds.",{"id":302,"title":303,"titles":304,"content":305,"level":52},"\u002Fblogs\u002Flocal-github-actions#step-1-core-prerequisites-and-architecture","Step 1: Core Prerequisites and Architecture",[30],"Under the hood, act uses your local container engine to mimic the hosted virtual environments provided by GitHub (like ubuntu-latest). Before starting, ensure you have the following installed and running: Docker Desktop (or Podman \u002F Docker Engine via WSL2).Your Terminal Shell (Bash, Zsh, or PowerShell).",{"id":307,"title":308,"titles":309,"content":310,"level":58},"\u002Fblogs\u002Flocal-github-actions#installing-act","Installing Act",[30,303],"Install the binary framework via your system package manager: # macOS (Homebrew)\nbrew install nektos\u002Ftap\u002Fact\n\n# Windows (Winget or Scoop)\nwinget install nektos.act\n# OR: scoop install act\n\n# Linux (Bash script installation)\ncurl --proto '=https' --tlsv1.2 -sSf https:\u002F\u002Fgithubusercontent.com | sudo sh Verify your installation works by checking the core version output: act --version",{"id":312,"title":313,"titles":314,"content":315,"level":52},"\u002Fblogs\u002Flocal-github-actions#step-2-the-initial-sandbox-setup","Step 2: The Initial Sandbox Setup",[30],"The first time you execute act inside a repository, it will ask you to select a default Docker image size to represent the ubuntu-latest runner. Run a basic list command to trigger this configuration menu: act -l",{"id":317,"title":318,"titles":319,"content":320,"level":58},"\u002Fblogs\u002Flocal-github-actions#choosing-the-right-runner-size","Choosing the Right Runner Size:",[30,313],"Micro (Default): ~200MB image. Fast to download but contains almost no tools. You will manually have to install basics like curl, git, or languages inside your steps.Medium: ~500MB+ image. Contains common build tools, Node.js, Python, and Docker dependencies. (Highly Recommended for most devs).Large: ~18GB+ image. A near-exact match of the actual GitHub cloud environment. Massive download, but highly accurate. Note: If you want to change your mind later, you can modify these choices inside your global config file at ~\u002F.actrc.",{"id":322,"title":323,"titles":324,"content":325,"level":52},"\u002Fblogs\u002Flocal-github-actions#step-3-executing-your-local-pipeline","Step 3: Executing Your Local Pipeline",[30],"Imagine you have a standard test workflow saved inside .github\u002Fworkflows\u002Ftest.yml that triggers on a code push event: name: Core Test Suite\non: [push]\n\njobs:\n  build-and-test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions\u002Fcheckout@v4\n\n      - name: Setup Node Environment\n        uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: 20\n\n      - name: Install and Run Tests\n        run: |\n          npm ci\n          npm test To run this workflow completely offline from the root of your project directory, simply run: act push act will intercept the push event string, match it to the workflow file, compile your code directories directly into a Docker container workspace volumes matrix, and stream the console outputs in real-time.",{"id":327,"title":328,"titles":329,"content":330,"level":52},"\u002Fblogs\u002Flocal-github-actions#step-4-advanced-scenarios-events-secrets-and-artifacts","Step 4: Advanced Scenarios — Events, Secrets, and Artifacts",[30],"Real pipelines are rarely as simple as a basic push. They rely on webhooks, secure deployment keys, and matrix configurations. Here is how to manage complex environments locally.",{"id":332,"title":333,"titles":334,"content":335,"level":58},"\u002Fblogs\u002Flocal-github-actions#simulating-specific-webhook-events","Simulating Specific Webhook Events",[30,328],"If your workflow triggers on a complex event like a pull_request or an issue_comment, you can pass mock JSON payloads to test targeted behaviors. Create a file named mock-event.json: {\n  \"pull_request\": {\n    \"head\": { \"ref\": \"feature-branch\" },\n    \"base\": { \"ref\": \"main\" }\n  }\n} Trigger your workflow by passing the event type and payload path flags: act pull_request -e mock-event.json",{"id":337,"title":338,"titles":339,"content":340,"level":58},"\u002Fblogs\u002Flocal-github-actions#safely-injecting-secrets-and-variables","Safely Injecting Secrets and Variables",[30,328],"Never hardcode production API tokens or environment configs into your files. act allows you to load mock credentials locally using .env syntax files. Create a file named .secrets (and add it to your .gitignore immediately!): AWS_ACCESS_KEY_ID=MOCK_LOCAL_KEY_12345\nDEPLOY_TOKEN=ghp_MockSecretTokenStringHere Inject these variables directly into your execution context using the secure secret loader flag: act --secret-file .secrets",{"id":342,"title":343,"titles":344,"content":345,"level":58},"\u002Fblogs\u002Flocal-github-actions#isolating-individual-jobs","Isolating Individual Jobs",[30,328],"If your workflow file contains multiple long-running jobs (e.g., lint, test, deploy) and you only want to focus on fixing a specific piece, use the targeted job parameter flag: act -j build-and-test",{"id":347,"title":348,"titles":349,"content":350,"level":52},"\u002Fblogs\u002Flocal-github-actions#step-5-common-gotchas-and-limitations","Step 5: Common Gotchas and Limitations",[30],"While act is incredibly powerful, it is a simulation wrapper, not an identical duplicate of the GitHub cloud architecture. Keep these structural limitations in mind: Windows\u002FmacOS Runners: act runs natively inside Linux Docker environments. If your workflow declares runs-on: windows-latest or runs-on: macos-latest, act will attempt to run them inside Linux wrappers, which will fail if you rely on native binaries like MSBuild or Xcode.The Checkout Action Caveat: The native actions\u002Fcheckout@v4 action usually fetches historical branches. When executed via act, it copies your live local tracking directory as-is. Make sure your local folder doesn't contain giant compiled file structures that will slow down your container mounting states! Use a .actignore file to omit massive binary data.",{"id":352,"title":180,"titles":353,"content":354,"level":52},"\u002Fblogs\u002Flocal-github-actions#wrapping-up",[30],"Adding act to your localized DevOps toolchain fundamentally changes how you develop automation infrastructure. It shortens your loop testing times from minutes to fractions of a second, protects your repository's commit history from pollution, and ensures that when your pipeline finally makes it to the cloud, it works flawlessly on the very first try. html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"id":35,"title":34,"titles":356,"content":357,"level":46},[],"Learn how to correctly scaffold, configure, and initialize an Espressif ESP-IDF project inside PlatformIO using both CLI tools and VS Code. Microcontroller development moves fast. While the Arduino framework is great for rapid prototyping, production-grade hardware engineering often requires the raw optimization, power management features, and real-time operating system (FreeRTOS) integration native to Espressif’s official ESP-IDF (Espressif IoT Development Framework). Managing toolchains directly inside ESP-IDF can be complex. This guide details how to build an isolated, reproducible development environment using PlatformIO to scaffold a project named learn-gsm-esp32-dev.",{"id":359,"title":360,"titles":361,"content":362,"level":52},"\u002Fblogs\u002Fplatformio-esp-idf-setup#choosing-your-scaffolding-workflow","Choosing Your Scaffolding Workflow",[34],"PlatformIO offers two separate pathways to initialize a new runtime: an automated command-line tool or an integrated graphical user interface (GUI) inside Visual Studio Code. Both paths yield identical configuration structures.",{"id":364,"title":365,"titles":366,"content":367,"level":58},"\u002Fblogs\u002Fplatformio-esp-idf-setup#option-a-the-rapid-cli-initialization","Option A: The Rapid CLI Initialization",[34,360],"For developers working directly inside standard shells or automated scripting workflows, the PlatformIO Core CLI is the fastest tool available. Execute this single string to build the folder structure, enter the directory, and invoke the scaffolding engine: mkdir learn-gsm-esp32-dev && cd learn-gsm-esp32-dev && pio project init --board esp32dev --project-option \"framework=espidf\"",{"id":369,"title":370,"titles":371,"content":372,"level":58},"\u002Fblogs\u002Fplatformio-esp-idf-setup#option-b-the-vs-code-visual-wizard","Option B: The VS Code Visual Wizard",[34,360],"If you prefer visual management tools within your IDE, follow these manual configuration steps: Open VS Code.Click the PlatformIO Alien Head icon on your primary sidebar activity deck.Locate the Quick Access panel and click PIO Home -> Open.Click the New Project button on the central control page.Provide your project metrics within the wizard form:\nName: learn-gsm-esp32-devBoard: Select Espressif ESP32 Dev ModuleFramework: Select Espressif IoT Development FrameworkClick Finish to pull down necessary core compiler tools and create the space.",{"id":374,"title":375,"titles":376,"content":377,"level":52},"\u002Fblogs\u002Fplatformio-esp-idf-setup#navigating-the-component-file-structure","Navigating the Component File Structure",[34],"ESP-IDF relies heavily on a rigid configuration structure orchestrated by CMake compilation rules. Unlike traditional flat Arduino sketch structures, your initialized directory needs to mirror this system layout layout: learn-gsm-esp32-dev\u002F\n├── include\u002F\n│   └── README\n├── src\u002F\n│   ├── CMakeLists.txt\n│   └── main.c\n├── platformio.ini\n└── CMakeLists.txt",{"id":379,"title":380,"titles":381,"content":382,"level":52},"\u002Fblogs\u002Fplatformio-esp-idf-setup#configuring-the-system-manifest-files","Configuring the System Manifest Files",[34],"To make sure your project compiles perfectly on your hardware target, overwrite your file structures using the standard boilerplate snippets below.",{"id":384,"title":385,"titles":386,"content":387,"level":58},"\u002Fblogs\u002Fplatformio-esp-idf-setup#_1-the-global-environment-manifest-platformioini","1. The Global Environment Manifest (platformio.ini)",[34,380],"This root-level configuration defines how PlatformIO sets up its internal compilation pipelines, monitors outputs, and manages hardware flash targets. [env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = espidf\nmonitor_speed = 115200",{"id":389,"title":390,"titles":391,"content":392,"level":58},"\u002Fblogs\u002Fplatformio-esp-idf-setup#_2-root-build-instructions-cmakeliststxt","2. Root Build Instructions (CMakeLists.txt)",[34,380],"This tells the base system build wrapper to locate your current ESP-IDF installation directory and load the required platform tools. cmake_minimum_required(VERSION 3.16.0)\ninclude(\\$ENV{IDF_PATH}\u002Ftools\u002Fcmake\u002Fproject.cmake)\nproject(learn-gsm-esp32-dev)",{"id":394,"title":395,"titles":396,"content":397,"level":58},"\u002Fblogs\u002Fplatformio-esp-idf-setup#_3-component-build-targets-srccmakeliststxt","3. Component Build Targets (src\u002FCMakeLists.txt)",[34,380],"ESP-IDF views project folders as a series of modular items. This file registers your local code blocks as active targets for inclusion during compiler execution passes. idf_component_register(SRCS \"main.c\"\n                    INCLUDE_DIRS \".\")",{"id":399,"title":400,"titles":401,"content":402,"level":58},"\u002Fblogs\u002Fplatformio-esp-idf-setup#_4-hardware-boilerplate-logic-srcmainc","4. Hardware Boilerplate Logic (src\u002Fmain.c)",[34,380],"Unlike ordinary code loops, ESP-IDF relies directly on a non-returning execution target called app_main. This code implements simple periodic console logs using the native multitasking utility engine FreeRTOS. #include \u003Cstdio.h>\n#include \"freertos\u002FFreeRTOS.h\"\n#include \"freertos\u002Ftask.h\"\n#include \"esp_log.h\"\n\nstatic const char *TAG = \"MAIN\";\n\nvoid app_main(void)\n{\n    ESP_LOGI(TAG, \"GSM ESP32 Project Initialized\");\n\n    while (1) {\n        ESP_LOGI(TAG, \"Hello World from GSM Dev Board!\");\n        vTaskDelay(pd_TO_TICKS(2000));\n    }\n}",{"id":404,"title":405,"titles":406,"content":407,"level":52},"\u002Fblogs\u002Fplatformio-esp-idf-setup#compiling-and-running-code-on-your-device","Compiling and Running Code on Your Device",[34],"With the project successfully configured, you can use these shortcuts to build and upload your code: Compile the Binaries: Hit Ctrl + Alt + B (Windows\u002FLinux) or Cmd + Option + B (macOS).Flash & Open Logging Monitor: Press Ctrl + Alt + T to open your terminal menu shell, then select the Upload and Monitor task option. Your terminal tool will begin tracking lines of standard serial log messages coming straight from your physical ESP32 device every two seconds. html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"id":39,"title":38,"titles":409,"content":410,"level":46},[],"Learn how to make PowerShell look, feel, and behave exactly like a premium Bash\u002FZsh environment with autosuggestions, interactive subcommand completions, and fuzzy history search. Let’s be honest. If you are coming from a Linux or macOS background, opening up a raw PowerShell (pwsh) terminal can feel a bit like stepping into a parallel universe where everything is almost familiar, but just clunky enough to drive you crazy. You miss the instant, predictive text of fish, the robust history search of zsh, and the effortless subcommand completions of a well-tuned bash setup. Out of the box, PowerShell’s tab-completion feels slow, and its visual feedback is... lacking. But here is the secret: PowerShell is secretly an absolute powerhouse of customizability. With a few modern modules and a slick profile configuration, you can make pwsh look, feel, and behave exactly like a premium Bash\u002FZsh environment—all while retaining PowerShell's insane object-oriented pipeline capabilities. Here is how to build the ultimate Bash-ified PowerShell experience.",{"id":412,"title":413,"titles":414,"content":415,"level":52},"\u002Fblogs\u002Fpowershell-bash#step-1-fix-the-keybindings-and-enable-fish-style-autosuggestions","Step 1: Fix the Keybindings and Enable Fish-Style Autosuggestions",[38],"The foundation of a good Bash experience is how the line editor behaves. PowerShell handles this via a built-in module called PSReadLine. We just need to wake it up and give it the right instructions. First, open your PowerShell profile in your favorite editor (e.g., VS Code): code $PROFILE (If the file doesn't exist yet, run New-Item -Path $PROFILE -Type File -Force first). Now, paste these essential configurations into your profile: # Set Bash-like Emacs keybindings (Ctrl+A to start of line, Ctrl+E to end, etc.)\nSet-PSReadLineOption -EditMode Emacs\n\n# Enable Fish-like inline predictive text history\nSet-PSReadLineOption -PredictionSource History\n\n# Change the prediction view to \"ListView\" or \"InlineView\" (Arrow keys to navigate)\nSet-PSReadLineOption -PredictionViewStyle InlineView\n\n# Set the color of the predictive text to be a subtle gray\nSet-PSReadLineOption -Colors @{ InlinePrediction = '#666666' }\n\n# Bind the Right Arrow key to accept the current inline suggestion\nSet-PSReadLineKeyHandler -Chord 'RightArrow' -Function AcceptSuggestion\n\n# Bind Ctrl+Space to trigger standard menu completion (Zsh style)\nSet-PSReadLineKeyHandler -Chord 'Ctrl+Space' -Function MenuComplete",{"id":417,"title":418,"titles":419,"content":420,"level":58},"\u002Fblogs\u002Fpowershell-bash#what-this-gives-you","What this gives you:",[38,413],"Inline History Predictions: As you type, pwsh will look through your command history and visually suggest the rest of the command in gray text. Press the Right Arrow to accept it.Zsh-style Menus: Hit Ctrl + Space to open an interactive grid menu of all available completions right in your terminal buffer.",{"id":422,"title":423,"titles":424,"content":425,"level":52},"\u002Fblogs\u002Fpowershell-bash#step-2-supercharge-subcommand-completions-with-carapace","Step 2: Supercharge Subcommand Completions with Carapace",[38],"Standard PowerShell only knows how to tab-complete standard cmdlet arguments (like -Path or -Credential). If you type git che[TAB], it stares at you blankly. To get full subcommand completion for hundreds of CLI tools (git, docker, kubectl, npm, gh, gcloud), we are going to use Carapace-bin, the absolute gold standard for multi-shell command completion. Install Carapace using a package manager like Scoop or Winget: winget install rsteube.carapace Add the initialization logic to your $PROFILE: # Initialize Carapace completions for PowerShell\n# This hooks into the native engine to provide rich subcommand completions\nif (Get-Command carapace -ErrorAction SilentlyContinue) {\n    $old_executioncontext = $ExecutionContext\n    carapace _powershell | Out-String | Invoke-Expression\n} Now, try typing git followed by Ctrl + Space. You will see an interactive menu showing options like checkout, commit, clone, complete with help descriptions for every single subcommand!",{"id":427,"title":428,"titles":429,"content":430,"level":52},"\u002Fblogs\u002Fpowershell-bash#step-3-add-fuzzy-history-searching-fzf","Step 3: Add Fuzzy History Searching (FZF)",[38],"If you've ever used Ctrl + R in Bash to reverse-search your history using a fuzzy finder, you know you can't live without it. We can bring this exact feature to PowerShell using the PSFzf module. Install the fzf binary and the PowerShell wrapper module: winget install junegunn.fzf\nInstall-Module PSFzf -Scope CurrentUser -Force Add this to your $PROFILE: Import-Module PSFzf\n# Overrides Ctrl+R to use the fuzzy finder for your PowerShell history\nSet-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock { [PSFzf]::PostContextHistoryFzf() }",{"id":432,"title":433,"titles":434,"content":435,"level":52},"\u002Fblogs\u002Fpowershell-bash#step-4-inject-essential-bash-aliases-functions","Step 4: Inject Essential Bash Aliases & Functions",[38],"PowerShell has a few built-in aliases like ls and rm, but they map directly to PowerShell cmdlets (Get-ChildItem, Remove-Item), which don't accept standard Linux flags like -la or -rf. Let's clean that up by introducing native functions that mirror standard Unix behavior: # Quick directory listings that accept traditional arguments\nfunction ll { Get-ChildItem -Path . -Force | Out-Host }\nfunction la { Get-ChildItem -Path . -Force -Recurse | Out-Host }\n\n# A quick wrapper to make 'grep' behave beautifully\nfunction grep ($pattern) { Select-String -Pattern $pattern }\n\n# Ensure sudo behavior exists via 'gsudo' (install via winget install gerardog.gsudo)\nif (Get-Command gsudo -ErrorAction SilentlyContinue) {\n    Set-Alias -Name sudo -Value gsudo\n}\n\n# Quick navigation shortcuts\nfunction .. { Set-Location .. }\nfunction ... { Set-Location ..\\.. }",{"id":437,"title":438,"titles":439,"content":440,"level":52},"\u002Fblogs\u002Fpowershell-bash#step-5-put-it-all-together-your-master-profile","Step 5: Put It All Together (Your Master Profile)",[38],"Here is your complete, optimized $PROFILE. Copy this layout, save the file, and restart your terminal to activate your brand new, incredibly fast Bash-ified environment: # ==========================================\n# 1. PSREADLINE CONFIG (Autosuggestions & Keybindings)\n# ==========================================\nImport-Module PSReadLine\nSet-PSReadLineOption -EditMode Emacs\nSet-PSReadLineOption -PredictionSource History\nSet-PSReadLineOption -PredictionViewStyle InlineView\nSet-PSReadLineOption -Colors @{ InlinePrediction = '#666666' }\n\n# Intuitive Navigation\nSet-PSReadLineKeyHandler -Chord 'RightArrow' -Function AcceptSuggestion\nSet-PSReadLineKeyHandler -Chord 'Ctrl+Space' -Function MenuComplete\n\n# Up\u002FDown Arrows search history matching what you've already typed\nSet-PSReadLineKeyHandler -Chord 'UpArrow' -Function HistorySearchBackward\nSet-PSReadLineKeyHandler -Chord 'DownArrow' -Function HistorySearchForward\n\n# ==========================================\n# 2. SUBCOMMAND COMPLETIONS (Carapace Engine)\n# ==========================================\nif (Get-Command carapace -ErrorAction SilentlyContinue) {\n    carapace _powershell | Out-String | Invoke-Expression\n}\n\n# ==========================================\n# 3. FUZZY HISTORY MATCHING (FZF)\n# ==========================================\nif (Get-Module -ListAvailable -Name PSFzf) {\n    Import-Module PSFzf\n    Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock { [PSFzf]::PostContextHistoryFzf() }\n}\n\n# ==========================================\n# 4. BASH ALIASES & UTILITIES\n# ==========================================\nfunction ll { Get-ChildItem -Force }\nfunction grep ($pattern) { $Input | Select-String -Pattern $pattern }\nif (Get-Command gsudo -ErrorAction SilentlyContinue) { Set-Alias -Name sudo -Value gsudo }\nfunction .. { Set-Location .. }\n\nWrite-Host \"🚀 PowerShell environment loaded with Bash-UX engine.\" -ForegroundColor Cyan html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",[442,1338,2191],{"id":443,"title":30,"anchors":444,"author":445,"body":483,"categories":1293,"coverImage":1294,"date":1298,"description":1299,"draft":41,"excerpt":1300,"extension":1301,"featured":448,"gallery":1302,"meta":1311,"navigation":448,"path":31,"published":448,"publishedAt":1298,"seo":1317,"slug":1326,"stem":32,"tags":1327,"updatedAt":1298,"__hash__":1337},"blogs\u002Fblogs\u002Flocal-github-actions.md",[],{"id":446,"title":447,"active":448,"avatar":449,"color":452,"company":453,"description":458,"email":459,"extension":460,"featured":41,"meta":461,"name":462,"slug":463,"socialLinks":464,"stem":480,"website":481,"__hash__":482},"authors\u002Fauthors\u002Fgideon-yebei.yml","Software Engineer",true,{"src":450,"alt":451},"\u002Fblogs\u002Fauthors\u002Fgideon-yebei\u002Favatar.png","Gideon Yebei's profile picture","#facc15",{"name":454,"website":455,"icon":456,"role":457},"Nodewave","https:\u002F\u002Fnodewave.net","https:\u002F\u002Fnodewave.net\u002Ffavicon.png","Full-Stack Developer","Gideon is a software engineer with a passion for building scalable web applications. With over 5 years of experience in the industry, he has worked on various projects ranging from startups to large enterprises. Gideon specializes in full-stack development and is proficient in technologies such as JavaScript, React, Node.js, and Python. In his free time, he enjoys contributing to open-source projects and exploring new technologies.","yebei@nodewave.net","yml",{},"Gideon Yebei","gideon-yebei",[465,470,475],{"platform":466,"url":467,"icon":468,"color":469},"GitHub","https:\u002F\u002Fgithub.com\u002FYebei-Gideon","i-line-md-github-loop","#14b8a6",{"platform":471,"url":472,"icon":473,"color":474},"Twitter","https:\u002F\u002Fx.com\u002F0x00_GK","i-line-md-twitter-x","#1DA1F2",{"platform":476,"url":477,"icon":478,"color":479},"LinkedIn","https:\u002F\u002Flinkedin.com\u002Fin\u002Fgideon-yebei","i-line-md-linkedin","#0077B5","authors\u002Fgideon-yebei","https:\u002F\u002Fyebei-gideon.github.io","wRPvJKp0JNkwNwV6cQE3zkcqxIj6-Py5QUyQIv6s-sA",{"type":484,"value":485,"toc":1277},"minimark",[486,500,515,522,525,529,540,543,559,563,566,670,673,685,687,690,699,702,714,717,747,756,758,761,768,951,954,966,974,976,979,981,984,995,1001,1105,1108,1126,1129,1139,1149,1166,1169,1184,1187,1200,1215,1217,1220,1226,1264,1267,1273],[487,488,489,490,494,495,499],"p",{},"We have all been trapped in the infamous ",[491,492,493],"strong",{},"CI\u002FCD commit loop",". You make a change to a ",[496,497,498],"code",{},".github\u002Fworkflows\u002Fci.yml"," file, commit it, push it, wait five minutes for a cloud runner to spin up, and realize you missed a minor indentation or a basic syntax flag.",[487,501,502,503,506,507,510,511,514],{},"Ten commits later, your Git history is littered with messages like ",[496,504,505],{},"\"fix ci\"",", ",[496,508,509],{},"\"fix ci again\"",", and ",[496,512,513],{},"\"please work\"",".",[487,516,517,518,521],{},"It doesn’t have to be this way. By utilizing ",[491,519,520],{},"Act",", an open-source tool that reads your GitHub Actions files and spins them up inside local Docker containers, you can run, test, and debug your entire automation pipeline locally in seconds.",[523,524],"hr",{},[526,527,303],"h2",{"id":528},"step-1-core-prerequisites-and-architecture",[487,530,531,532,535,536,539],{},"Under the hood, ",[496,533,534],{},"act"," uses your local container engine to mimic the hosted virtual environments provided by GitHub (like ",[496,537,538],{},"ubuntu-latest",").",[487,541,542],{},"Before starting, ensure you have the following installed and running:",[544,545,546,553],"ol",{},[547,548,549,552],"li",{},[491,550,551],{},"Docker Desktop"," (or Podman \u002F Docker Engine via WSL2).",[547,554,555,558],{},[491,556,557],{},"Your Terminal Shell"," (Bash, Zsh, or PowerShell).",[560,561,308],"h3",{"id":562},"installing-act",[487,564,565],{},"Install the binary framework via your system package manager:",[567,568,572],"pre",{"className":569,"code":570,"language":571,"meta":167,"style":167},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# macOS (Homebrew)\nbrew install nektos\u002Ftap\u002Fact\n\n# Windows (Winget or Scoop)\nwinget install nektos.act\n# OR: scoop install act\n\n# Linux (Bash script installation)\ncurl --proto '=https' --tlsv1.2 -sSf https:\u002F\u002Fgithubusercontent.com | sudo sh\n","bash",[496,573,574,582,595,600,605,616,622,627,633],{"__ignoreMap":167},[575,576,578],"span",{"class":577,"line":46},"line",[575,579,581],{"class":580},"sHwdD","# macOS (Homebrew)\n",[575,583,584,588,592],{"class":577,"line":52},[575,585,587],{"class":586},"sBMFI","brew",[575,589,591],{"class":590},"sfazB"," install",[575,593,594],{"class":590}," nektos\u002Ftap\u002Fact\n",[575,596,597],{"class":577,"line":58},[575,598,599],{"emptyLinePlaceholder":448},"\n",[575,601,602],{"class":577,"line":109},[575,603,604],{"class":580},"# Windows (Winget or Scoop)\n",[575,606,608,611,613],{"class":577,"line":607},5,[575,609,610],{"class":586},"winget",[575,612,591],{"class":590},[575,614,615],{"class":590}," nektos.act\n",[575,617,619],{"class":577,"line":618},6,[575,620,621],{"class":580},"# OR: scoop install act\n",[575,623,625],{"class":577,"line":624},7,[575,626,599],{"emptyLinePlaceholder":448},[575,628,630],{"class":577,"line":629},8,[575,631,632],{"class":580},"# Linux (Bash script installation)\n",[575,634,636,639,642,646,649,652,655,658,661,664,667],{"class":577,"line":635},9,[575,637,638],{"class":586},"curl",[575,640,641],{"class":590}," --proto",[575,643,645],{"class":644},"sMK4o"," '",[575,647,648],{"class":590},"=https",[575,650,651],{"class":644},"'",[575,653,654],{"class":590}," --tlsv1.2",[575,656,657],{"class":590}," -sSf",[575,659,660],{"class":590}," https:\u002F\u002Fgithubusercontent.com",[575,662,663],{"class":644}," |",[575,665,666],{"class":586}," sudo",[575,668,669],{"class":590}," sh\n",[487,671,672],{},"Verify your installation works by checking the core version output:",[567,674,676],{"className":569,"code":675,"language":571,"meta":167,"style":167},"act --version\n",[496,677,678],{"__ignoreMap":167},[575,679,680,682],{"class":577,"line":46},[575,681,534],{"class":586},[575,683,684],{"class":590}," --version\n",[523,686],{},[526,688,313],{"id":689},"step-2-the-initial-sandbox-setup",[487,691,692,693,695,696,698],{},"The first time you execute ",[496,694,534],{}," inside a repository, it will ask you to select a default Docker image size to represent the ",[496,697,538],{}," runner.",[487,700,701],{},"Run a basic list command to trigger this configuration menu:",[567,703,705],{"className":569,"code":704,"language":571,"meta":167,"style":167},"act -l\n",[496,706,707],{"__ignoreMap":167},[575,708,709,711],{"class":577,"line":46},[575,710,534],{"class":586},[575,712,713],{"class":590}," -l\n",[560,715,318],{"id":716},"choosing-the-right-runner-size",[718,719,720,732,741],"ul",{},[547,721,722,725,726,506,728,731],{},[491,723,724],{},"Micro (Default):"," ~200MB image. Fast to download but contains almost no tools. You will manually have to install basics like ",[496,727,638],{},[496,729,730],{},"git",", or languages inside your steps.",[547,733,734,737,738,514],{},[491,735,736],{},"Medium:"," ~500MB+ image. Contains common build tools, Node.js, Python, and Docker dependencies. ",[491,739,740],{},"(Highly Recommended for most devs)",[547,742,743,746],{},[491,744,745],{},"Large:"," ~18GB+ image. A near-exact match of the actual GitHub cloud environment. Massive download, but highly accurate.",[487,748,749],{},[750,751,752,753,514],"em",{},"Note: If you want to change your mind later, you can modify these choices inside your global config file at ",[496,754,755],{},"~\u002F.actrc",[523,757],{},[526,759,323],{"id":760},"step-3-executing-your-local-pipeline",[487,762,763,764,767],{},"Imagine you have a standard test workflow saved inside ",[496,765,766],{},".github\u002Fworkflows\u002Ftest.yml"," that triggers on a code push event:",[567,769,773],{"className":770,"code":771,"language":772,"meta":167,"style":167},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","name: Core Test Suite\non: [push]\n\njobs:\n  build-and-test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions\u002Fcheckout@v4\n\n      - name: Setup Node Environment\n        uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: 20\n\n      - name: Install and Run Tests\n        run: |\n          npm ci\n          npm test\n","yaml",[496,774,775,787,804,808,816,823,833,840,853,863,868,880,890,898,910,915,927,939,945],{"__ignoreMap":167},[575,776,777,781,784],{"class":577,"line":46},[575,778,780],{"class":779},"swJcz","name",[575,782,783],{"class":644},":",[575,785,786],{"class":590}," Core Test Suite\n",[575,788,789,793,795,798,801],{"class":577,"line":52},[575,790,792],{"class":791},"sfNiH","on",[575,794,783],{"class":644},[575,796,797],{"class":644}," [",[575,799,800],{"class":590},"push",[575,802,803],{"class":644},"]\n",[575,805,806],{"class":577,"line":58},[575,807,599],{"emptyLinePlaceholder":448},[575,809,810,813],{"class":577,"line":109},[575,811,812],{"class":779},"jobs",[575,814,815],{"class":644},":\n",[575,817,818,821],{"class":577,"line":607},[575,819,820],{"class":779},"  build-and-test",[575,822,815],{"class":644},[575,824,825,828,830],{"class":577,"line":618},[575,826,827],{"class":779},"    runs-on",[575,829,783],{"class":644},[575,831,832],{"class":590}," ubuntu-latest\n",[575,834,835,838],{"class":577,"line":624},[575,836,837],{"class":779},"    steps",[575,839,815],{"class":644},[575,841,842,845,848,850],{"class":577,"line":629},[575,843,844],{"class":644},"      -",[575,846,847],{"class":779}," name",[575,849,783],{"class":644},[575,851,852],{"class":590}," Checkout Code\n",[575,854,855,858,860],{"class":577,"line":635},[575,856,857],{"class":779},"        uses",[575,859,783],{"class":644},[575,861,862],{"class":590}," actions\u002Fcheckout@v4\n",[575,864,866],{"class":577,"line":865},10,[575,867,599],{"emptyLinePlaceholder":448},[575,869,871,873,875,877],{"class":577,"line":870},11,[575,872,844],{"class":644},[575,874,847],{"class":779},[575,876,783],{"class":644},[575,878,879],{"class":590}," Setup Node Environment\n",[575,881,883,885,887],{"class":577,"line":882},12,[575,884,857],{"class":779},[575,886,783],{"class":644},[575,888,889],{"class":590}," actions\u002Fsetup-node@v4\n",[575,891,893,896],{"class":577,"line":892},13,[575,894,895],{"class":779},"        with",[575,897,815],{"class":644},[575,899,901,904,906],{"class":577,"line":900},14,[575,902,903],{"class":779},"          node-version",[575,905,783],{"class":644},[575,907,909],{"class":908},"sbssI"," 20\n",[575,911,913],{"class":577,"line":912},15,[575,914,599],{"emptyLinePlaceholder":448},[575,916,918,920,922,924],{"class":577,"line":917},16,[575,919,844],{"class":644},[575,921,847],{"class":779},[575,923,783],{"class":644},[575,925,926],{"class":590}," Install and Run Tests\n",[575,928,930,933,935],{"class":577,"line":929},17,[575,931,932],{"class":779},"        run",[575,934,783],{"class":644},[575,936,938],{"class":937},"s7zQu"," |\n",[575,940,942],{"class":577,"line":941},18,[575,943,944],{"class":590},"          npm ci\n",[575,946,948],{"class":577,"line":947},19,[575,949,950],{"class":590},"          npm test\n",[487,952,953],{},"To run this workflow completely offline from the root of your project directory, simply run:",[567,955,957],{"className":569,"code":956,"language":571,"meta":167,"style":167},"act push\n",[496,958,959],{"__ignoreMap":167},[575,960,961,963],{"class":577,"line":46},[575,962,534],{"class":586},[575,964,965],{"class":590}," push\n",[487,967,968,970,971,973],{},[496,969,534],{}," will intercept the ",[496,972,800],{}," event string, match it to the workflow file, compile your code directories directly into a Docker container workspace volumes matrix, and stream the console outputs in real-time.",[523,975],{},[526,977,328],{"id":978},"step-4-advanced-scenarios-events-secrets-and-artifacts",[487,980,330],{},[560,982,333],{"id":983},"simulating-specific-webhook-events",[487,985,986,987,990,991,994],{},"If your workflow triggers on a complex event like a ",[496,988,989],{},"pull_request"," or an ",[496,992,993],{},"issue_comment",", you can pass mock JSON payloads to test targeted behaviors.",[487,996,997,998,783],{},"Create a file named ",[496,999,1000],{},"mock-event.json",[567,1002,1006],{"className":1003,"code":1004,"language":1005,"meta":167,"style":167},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"pull_request\": {\n    \"head\": { \"ref\": \"feature-branch\" },\n    \"base\": { \"ref\": \"main\" }\n  }\n}\n","json",[496,1007,1008,1013,1029,1064,1095,1100],{"__ignoreMap":167},[575,1009,1010],{"class":577,"line":46},[575,1011,1012],{"class":644},"{\n",[575,1014,1015,1018,1021,1024,1026],{"class":577,"line":52},[575,1016,1017],{"class":644},"  \"",[575,1019,989],{"class":1020},"spNyl",[575,1022,1023],{"class":644},"\"",[575,1025,783],{"class":644},[575,1027,1028],{"class":644}," {\n",[575,1030,1031,1034,1037,1039,1041,1044,1047,1050,1052,1054,1056,1059,1061],{"class":577,"line":58},[575,1032,1033],{"class":644},"    \"",[575,1035,1036],{"class":586},"head",[575,1038,1023],{"class":644},[575,1040,783],{"class":644},[575,1042,1043],{"class":644}," {",[575,1045,1046],{"class":644}," \"",[575,1048,1049],{"class":908},"ref",[575,1051,1023],{"class":644},[575,1053,783],{"class":644},[575,1055,1046],{"class":644},[575,1057,1058],{"class":590},"feature-branch",[575,1060,1023],{"class":644},[575,1062,1063],{"class":644}," },\n",[575,1065,1066,1068,1071,1073,1075,1077,1079,1081,1083,1085,1087,1090,1092],{"class":577,"line":109},[575,1067,1033],{"class":644},[575,1069,1070],{"class":586},"base",[575,1072,1023],{"class":644},[575,1074,783],{"class":644},[575,1076,1043],{"class":644},[575,1078,1046],{"class":644},[575,1080,1049],{"class":908},[575,1082,1023],{"class":644},[575,1084,783],{"class":644},[575,1086,1046],{"class":644},[575,1088,1089],{"class":590},"main",[575,1091,1023],{"class":644},[575,1093,1094],{"class":644}," }\n",[575,1096,1097],{"class":577,"line":607},[575,1098,1099],{"class":644},"  }\n",[575,1101,1102],{"class":577,"line":618},[575,1103,1104],{"class":644},"}\n",[487,1106,1107],{},"Trigger your workflow by passing the event type and payload path flags:",[567,1109,1111],{"className":569,"code":1110,"language":571,"meta":167,"style":167},"act pull_request -e mock-event.json\n",[496,1112,1113],{"__ignoreMap":167},[575,1114,1115,1117,1120,1123],{"class":577,"line":46},[575,1116,534],{"class":586},[575,1118,1119],{"class":590}," pull_request",[575,1121,1122],{"class":590}," -e",[575,1124,1125],{"class":590}," mock-event.json\n",[560,1127,338],{"id":1128},"safely-injecting-secrets-and-variables",[487,1130,1131,1132,1134,1135,1138],{},"Never hardcode production API tokens or environment configs into your files. ",[496,1133,534],{}," allows you to load mock credentials locally using ",[496,1136,1137],{},".env"," syntax files.",[487,1140,997,1141,1144,1145,1148],{},[496,1142,1143],{},".secrets"," (and add it to your ",[496,1146,1147],{},".gitignore"," immediately!):",[567,1150,1154],{"className":1151,"code":1152,"language":1153,"meta":167,"style":167},"language-env shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","AWS_ACCESS_KEY_ID=MOCK_LOCAL_KEY_12345\nDEPLOY_TOKEN=ghp_MockSecretTokenStringHere\n","env",[496,1155,1156,1161],{"__ignoreMap":167},[575,1157,1158],{"class":577,"line":46},[575,1159,1160],{},"AWS_ACCESS_KEY_ID=MOCK_LOCAL_KEY_12345\n",[575,1162,1163],{"class":577,"line":52},[575,1164,1165],{},"DEPLOY_TOKEN=ghp_MockSecretTokenStringHere\n",[487,1167,1168],{},"Inject these variables directly into your execution context using the secure secret loader flag:",[567,1170,1172],{"className":569,"code":1171,"language":571,"meta":167,"style":167},"act --secret-file .secrets\n",[496,1173,1174],{"__ignoreMap":167},[575,1175,1176,1178,1181],{"class":577,"line":46},[575,1177,534],{"class":586},[575,1179,1180],{"class":590}," --secret-file",[575,1182,1183],{"class":590}," .secrets\n",[560,1185,343],{"id":1186},"isolating-individual-jobs",[487,1188,1189,1190,506,1193,506,1196,1199],{},"If your workflow file contains multiple long-running jobs (e.g., ",[496,1191,1192],{},"lint",[496,1194,1195],{},"test",[496,1197,1198],{},"deploy",") and you only want to focus on fixing a specific piece, use the targeted job parameter flag:",[567,1201,1203],{"className":569,"code":1202,"language":571,"meta":167,"style":167},"act -j build-and-test\n",[496,1204,1205],{"__ignoreMap":167},[575,1206,1207,1209,1212],{"class":577,"line":46},[575,1208,534],{"class":586},[575,1210,1211],{"class":590}," -j",[575,1213,1214],{"class":590}," build-and-test\n",[523,1216],{},[526,1218,348],{"id":1219},"step-5-common-gotchas-and-limitations",[487,1221,1222,1223,1225],{},"While ",[496,1224,534],{}," is incredibly powerful, it is a simulation wrapper, not an identical duplicate of the GitHub cloud architecture. Keep these structural limitations in mind:",[718,1227,1228,1247],{},[547,1229,1230,1233,1234,1236,1237,1240,1241,506,1244,1246],{},[491,1231,1232],{},"Windows\u002FmacOS Runners:"," ",[496,1235,534],{}," runs natively inside Linux Docker environments. If your workflow declares ",[496,1238,1239],{},"runs-on: windows-latest"," or ",[496,1242,1243],{},"runs-on: macos-latest",[496,1245,534],{}," will attempt to run them inside Linux wrappers, which will fail if you rely on native binaries like MSBuild or Xcode.",[547,1248,1249,1252,1253,1256,1257,1259,1260,1263],{},[491,1250,1251],{},"The Checkout Action Caveat:"," The native ",[496,1254,1255],{},"actions\u002Fcheckout@v4"," action usually fetches historical branches. When executed via ",[496,1258,534],{},", it copies your live local tracking directory as-is. Make sure your local folder doesn't contain giant compiled file structures that will slow down your container mounting states! Use a ",[496,1261,1262],{},".actignore"," file to omit massive binary data.",[526,1265,180],{"id":1266},"wrapping-up",[487,1268,1269,1270,1272],{},"Adding ",[496,1271,534],{}," to your localized DevOps toolchain fundamentally changes how you develop automation infrastructure. It shortens your loop testing times from minutes to fractions of a second, protects your repository's commit history from pollution, and ensures that when your pipeline finally makes it to the cloud, it works flawlessly on the very first try.",[1274,1275,1276],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":167,"searchDepth":607,"depth":607,"links":1278},[1279,1282,1285,1286,1291,1292],{"id":528,"depth":52,"text":303,"children":1280},[1281],{"id":562,"depth":58,"text":308},{"id":689,"depth":52,"text":313,"children":1283},[1284],{"id":716,"depth":58,"text":318},{"id":760,"depth":52,"text":323},{"id":978,"depth":52,"text":328,"children":1287},[1288,1289,1290],{"id":983,"depth":58,"text":333},{"id":1128,"depth":58,"text":338},{"id":1186,"depth":58,"text":343},{"id":1219,"depth":52,"text":348},{"id":1266,"depth":52,"text":180},[],{"src":1295,"alt":1296,"caption":1297},"\u002Fblogs\u002Fposts\u002Flocal-github-actions\u002Fcover.png","Visual showing a terminal executing a GitHub Actions workflow pipeline entirely on a local machine using Act","Stop making dummy commits. Test and debug your cloud pipelines completely offline.","2026-06-26","Learn how to use Act to run, test, and step-debug your GitHub Actions workflows locally, saving time and keeping your commit history clean.","Blog post excerpt text","md",[1303,1307],{"src":1304,"alt":1305,"caption":1306},"\u002Fblogs\u002Fposts\u002Flocal-github-actions\u002Fact-running.png","Terminal interface splitting workflow jobs into localized Docker execution steps","Act visualizes and executes your YAML workflow steps as local containers.",{"src":1308,"alt":1309,"caption":1310},"\u002Fblogs\u002Fposts\u002Flocal-github-actions\u002Fsecret-injection.png","Console view demonstrating safe injection of mock API variables and environment variables","Mock secrets and environment variables safely without exposing production keys.",{"readingTime":1312},{"text":1313,"minutes":1314,"time":1315,"words":1316},"4 min read",3.765,225900,753,{"title":1318,"description":1319,"keywords":1320,"canonicalUrl":31},"How to Test GitHub Actions Locally using Act (2026 Guide)","Deep-dive tutorial into configuring Act for offline GitHub Actions testing. Master Docker runners, event simulation, custom variables, and secret mocking.",[1321,520,1322,1323,1324,1325],"GitHub Actions","CI\u002FCD","DevOps","Docker","Local Testing","local-github-actions",[1328],{"id":1329,"color":1330,"description":1331,"extension":460,"icon":1332,"meta":1333,"name":1323,"slug":1334,"stem":1335,"__hash__":1336},"tags\u002Ftags\u002Fdevops.yml","#FF5733","DevOps practices, tools, and methodologies for software development and operations.","i-codicon-tools",{},"devops","tags\u002Fdevops","UWhQS6qqVVvm-xcuqdsEuLabxhDDOBINt6NrioO-nOQ","l1N_pX2M8It-6MIwAVVBF_8bZVebBTmJADvdaf5sjaY",{"id":1339,"title":26,"anchors":1340,"author":1341,"body":1349,"categories":2131,"coverImage":2141,"date":1298,"description":2145,"draft":41,"excerpt":1300,"extension":1301,"featured":448,"gallery":2146,"meta":2155,"navigation":448,"path":27,"published":448,"publishedAt":1298,"seo":2160,"slug":2169,"stem":28,"tags":2170,"updatedAt":1298,"__hash__":2190},"blogs\u002Fblogs\u002Fgit-pull-all.md",[],{"id":446,"title":447,"active":448,"avatar":1342,"color":452,"company":1343,"description":458,"email":459,"extension":460,"featured":41,"meta":1344,"name":462,"slug":463,"socialLinks":1345,"stem":480,"website":481,"__hash__":482},{"src":450,"alt":451},{"name":454,"website":455,"icon":456,"role":457},{},[1346,1347,1348],{"platform":466,"url":467,"icon":468,"color":469},{"platform":471,"url":472,"icon":473,"color":474},{"platform":476,"url":477,"icon":478,"color":479},{"type":484,"value":1350,"toc":2120},[1351,1354,1357,1431,1434,1441,1444,1450,1483,1496,1503,1509,1512,1527,1530,1554,1556,1559,1566,1577,1921,1924,1942,1944,1947,1950,1953,1971,1981,2028,2031,2043,2045,2054,2058,2064,2070,2076,2082,2117],[487,1352,1353],{},"Picture this scenario. You return to a massive project repository after a long weekend. Dozens of team branches have updated on GitHub, and your local workspace feels incredibly left behind.",[487,1355,1356],{},"Naturally, you decide to write a quick, clever shell script line to pull everything down at once:",[567,1358,1360],{"className":569,"code":1359,"language":571,"meta":167,"style":167},"for branch in \\((git branch -r \\vert{} grep -v '\\->'); do git pull\\)branch; done\n",[496,1361,1362],{"__ignoreMap":167},[575,1363,1364,1367,1371,1374,1377,1380,1382,1385,1388,1391,1394,1397,1400,1402,1405,1407,1410,1413,1416,1419,1422,1425,1428],{"class":577,"line":46},[575,1365,1366],{"class":937},"for",[575,1368,1370],{"class":1369},"sTEyZ"," branch ",[575,1372,1373],{"class":937},"in",[575,1375,1376],{"class":1369}," \\(",[575,1378,1379],{"class":644},"(",[575,1381,730],{"class":586},[575,1383,1384],{"class":590}," branch",[575,1386,1387],{"class":590}," -r",[575,1389,1390],{"class":1369}," \\v",[575,1392,1393],{"class":590},"ert{}",[575,1395,1396],{"class":590}," grep",[575,1398,1399],{"class":590}," -v",[575,1401,645],{"class":644},[575,1403,1404],{"class":590},"\\->",[575,1406,651],{"class":644},[575,1408,1409],{"class":644},");",[575,1411,1412],{"class":937}," do",[575,1414,1415],{"class":586}," git",[575,1417,1418],{"class":590}," pull",[575,1420,1421],{"class":1369},"\\)",[575,1423,1424],{"class":590},"branch",[575,1426,1427],{"class":644},";",[575,1429,1430],{"class":937}," done\n",[487,1432,1433],{},"You hit Enter, expecting a beautifully synced repository. Instead, your console explodes into a mess of syntax errors, detached HEAD states, and unexpected merge conflicts.",[487,1435,1436,1437,1440],{},"Here is why your native ",[496,1438,1439],{},"git pull"," loops are broken, how to fix them, and the ultimate safe alternative.",[526,1442,266],{"id":1443},"why-the-naive-script-breaks-your-repo",[487,1445,1446,1447,1449],{},"To understand why the loop above fails, you have to look closely at how ",[496,1448,1439],{}," operates under the hood. The command relies on two distinct expectations:",[544,1451,1452,1464],{},[547,1453,1454,1233,1457,1459,1460,1463],{},[491,1455,1456],{},"Active Checkouts Only:",[496,1458,1439],{}," is explicitly designed to download remote changes and immediately merge them into your ",[750,1461,1462],{},"currently checked-out"," local branch. It is physically incapable of updating separate background branches.",[547,1465,1466,1233,1469,1472,1473,1476,1477,1479,1480,1482],{},[491,1467,1468],{},"Argument Syntax:",[496,1470,1471],{},"git branch -r"," outputs remote tracking references prefixed with the remote identifier (e.g., ",[496,1474,1475],{},"origin\u002Ffeature-auth","). Passing ",[496,1478,1475],{}," directly to a ",[496,1481,1439],{}," command breaks structural syntax.",[487,1484,1485,1486,1488,1489,1492,1493,1495],{},"If you run this inside your ",[496,1487,1089],{}," branch, the loop will continuously try to force-merge ",[750,1490,1491],{},"every single remote branch"," into your clean ",[496,1494,1089],{}," history.",[526,1497,1499,1500],{"id":1498},"the-instant-fix-trust-git-fetch-all","The Instant Fix: Trust ",[496,1501,1502],{},"git fetch --all",[487,1504,1505,1506,1508],{},"Before writing custom automation scripts, remember that you rarely need to explicitly run a ",[496,1507,1439],{}," on branches you aren't currently coding on.",[487,1510,1511],{},"If you simply want to download the latest state of the entire project to inspect histories or check things out later, run this native command:",[567,1513,1515],{"className":569,"code":1514,"language":571,"meta":167,"style":167},"git fetch --all\n",[496,1516,1517],{"__ignoreMap":167},[575,1518,1519,1521,1524],{"class":577,"line":46},[575,1520,730],{"class":586},[575,1522,1523],{"class":590}," fetch",[575,1525,1526],{"class":590}," --all\n",[560,1528,276],{"id":1529},"why-this-is-your-best-default",[718,1531,1532,1542,1548],{},[547,1533,1534,1537,1538,1541],{},[491,1535,1536],{},"Zero Risk:"," It downloads the raw remote objects and updates remote tracking pointers (like ",[496,1539,1540],{},"origin\u002Fmain",") without modifying your current workspace files.",[547,1543,1544,1547],{},[491,1545,1546],{},"No Merge Conflicts:"," It will never accidentally force a broken merge or pollute your active staging index.",[547,1549,1550,1553],{},[491,1551,1552],{},"Server Friendly:"," It makes a single optimized network request instead of hitting your server individually for every branch reference.",[523,1555],{},[526,1557,281],{"id":1558},"building-the-automated-local-multi-pull-script",[487,1560,1561,1562,1565],{},"If you truly need every single ",[491,1563,1564],{},"local"," branch to immediately step forward and match its remote counterpart, you must explicitly force Git to safely navigate between branches.",[487,1567,1568,1569,1572,1573,1576],{},"Open a new shell script or your ",[496,1570,1571],{},".bashrc","\u002F",[496,1574,1575],{},".zshrc"," file and add this robust layout:",[567,1578,1580],{"className":569,"code":1579,"language":571,"meta":167,"style":167},"#!\u002Fbin\u002Fbash\n\n# 1. Stash any uncommitted workspace changes so they aren't lost\nhas_changes=\\$(git status --porcelain)\nif [ -n \"\\$has_changes\" ]; then\n    echo \"Saving uncommitted work to stash...\"\n    git stash -u\nfi\n\n# 2. Save your current branch name to return safely later\ncurrent_branch=\\$(git rev-parse --abbrev-ref HEAD)\n\n# 3. Safely loop through clean local branch lists\nfor branch in \\$(git for-each-ref --format='%(refname:short)' refs\u002Fheads\u002F); do\n    echo \"Checking out \\$branch...\"\n    git checkout \"\\$branch\" 2>\u002Fdev\u002Fnull\n\n    # Use fast-forward only to avoid generating messy, unnecessary merge commits\n    echo \"Applying remote fast-forward updates...\"\n    git pull --ff-only\ndone\n\n# 4. Return to your starting point and restore work\ngit checkout \"\\$current_branch\" 2>\u002Fdev\u002Fnull\nif [ -n \"\\$has_changes\" ]; then\n    echo \"Restoring your original uncommitted changes...\"\n    git stash pop\nfi\n\necho \"✨ All local branches synced successfully!\"\n",[496,1581,1582,1587,1591,1596,1620,1644,1658,1669,1674,1678,1683,1707,1711,1716,1752,1768,1789,1793,1798,1809,1819,1825,1830,1836,1855,1876,1888,1898,1903,1908],{"__ignoreMap":167},[575,1583,1584],{"class":577,"line":46},[575,1585,1586],{"class":580},"#!\u002Fbin\u002Fbash\n",[575,1588,1589],{"class":577,"line":52},[575,1590,599],{"emptyLinePlaceholder":448},[575,1592,1593],{"class":577,"line":58},[575,1594,1595],{"class":580},"# 1. Stash any uncommitted workspace changes so they aren't lost\n",[575,1597,1598,1601,1604,1607,1609,1611,1614,1617],{"class":577,"line":109},[575,1599,1600],{"class":1369},"has_changes",[575,1602,1603],{"class":644},"=",[575,1605,1606],{"class":1369},"\\$",[575,1608,1379],{"class":644},[575,1610,730],{"class":586},[575,1612,1613],{"class":590}," status",[575,1615,1616],{"class":590}," --porcelain",[575,1618,1619],{"class":644},")\n",[575,1621,1622,1625,1627,1630,1632,1634,1636,1638,1641],{"class":577,"line":607},[575,1623,1624],{"class":937},"if",[575,1626,797],{"class":644},[575,1628,1629],{"class":644}," -n",[575,1631,1046],{"class":644},[575,1633,1606],{"class":1369},[575,1635,1600],{"class":590},[575,1637,1023],{"class":644},[575,1639,1640],{"class":644}," ];",[575,1642,1643],{"class":937}," then\n",[575,1645,1646,1650,1652,1655],{"class":577,"line":618},[575,1647,1649],{"class":1648},"s2Zo4","    echo",[575,1651,1046],{"class":644},[575,1653,1654],{"class":590},"Saving uncommitted work to stash...",[575,1656,1657],{"class":644},"\"\n",[575,1659,1660,1663,1666],{"class":577,"line":624},[575,1661,1662],{"class":586},"    git",[575,1664,1665],{"class":590}," stash",[575,1667,1668],{"class":590}," -u\n",[575,1670,1671],{"class":577,"line":629},[575,1672,1673],{"class":937},"fi\n",[575,1675,1676],{"class":577,"line":635},[575,1677,599],{"emptyLinePlaceholder":448},[575,1679,1680],{"class":577,"line":865},[575,1681,1682],{"class":580},"# 2. Save your current branch name to return safely later\n",[575,1684,1685,1688,1690,1692,1694,1696,1699,1702,1705],{"class":577,"line":870},[575,1686,1687],{"class":1369},"current_branch",[575,1689,1603],{"class":644},[575,1691,1606],{"class":1369},[575,1693,1379],{"class":644},[575,1695,730],{"class":586},[575,1697,1698],{"class":590}," rev-parse",[575,1700,1701],{"class":590}," --abbrev-ref",[575,1703,1704],{"class":590}," HEAD",[575,1706,1619],{"class":644},[575,1708,1709],{"class":577,"line":882},[575,1710,599],{"emptyLinePlaceholder":448},[575,1712,1713],{"class":577,"line":892},[575,1714,1715],{"class":580},"# 3. Safely loop through clean local branch lists\n",[575,1717,1718,1720,1722,1724,1727,1729,1731,1734,1737,1739,1742,1744,1747,1749],{"class":577,"line":900},[575,1719,1366],{"class":937},[575,1721,1370],{"class":1369},[575,1723,1373],{"class":937},[575,1725,1726],{"class":1369}," \\$",[575,1728,1379],{"class":644},[575,1730,730],{"class":586},[575,1732,1733],{"class":590}," for-each-ref",[575,1735,1736],{"class":590}," --format=",[575,1738,651],{"class":644},[575,1740,1741],{"class":590},"%(refname:short)",[575,1743,651],{"class":644},[575,1745,1746],{"class":590}," refs\u002Fheads\u002F",[575,1748,1409],{"class":644},[575,1750,1751],{"class":937}," do\n",[575,1753,1754,1756,1758,1761,1763,1766],{"class":577,"line":912},[575,1755,1649],{"class":1648},[575,1757,1046],{"class":644},[575,1759,1760],{"class":590},"Checking out ",[575,1762,1606],{"class":1369},[575,1764,1765],{"class":590},"branch...",[575,1767,1657],{"class":644},[575,1769,1770,1772,1775,1777,1779,1781,1783,1786],{"class":577,"line":917},[575,1771,1662],{"class":586},[575,1773,1774],{"class":590}," checkout",[575,1776,1046],{"class":644},[575,1778,1606],{"class":1369},[575,1780,1424],{"class":590},[575,1782,1023],{"class":644},[575,1784,1785],{"class":644}," 2>",[575,1787,1788],{"class":590},"\u002Fdev\u002Fnull\n",[575,1790,1791],{"class":577,"line":929},[575,1792,599],{"emptyLinePlaceholder":448},[575,1794,1795],{"class":577,"line":941},[575,1796,1797],{"class":580},"    # Use fast-forward only to avoid generating messy, unnecessary merge commits\n",[575,1799,1800,1802,1804,1807],{"class":577,"line":947},[575,1801,1649],{"class":1648},[575,1803,1046],{"class":644},[575,1805,1806],{"class":590},"Applying remote fast-forward updates...",[575,1808,1657],{"class":644},[575,1810,1812,1814,1816],{"class":577,"line":1811},20,[575,1813,1662],{"class":586},[575,1815,1418],{"class":590},[575,1817,1818],{"class":590}," --ff-only\n",[575,1820,1822],{"class":577,"line":1821},21,[575,1823,1824],{"class":937},"done\n",[575,1826,1828],{"class":577,"line":1827},22,[575,1829,599],{"emptyLinePlaceholder":448},[575,1831,1833],{"class":577,"line":1832},23,[575,1834,1835],{"class":580},"# 4. Return to your starting point and restore work\n",[575,1837,1839,1841,1843,1845,1847,1849,1851,1853],{"class":577,"line":1838},24,[575,1840,730],{"class":586},[575,1842,1774],{"class":590},[575,1844,1046],{"class":644},[575,1846,1606],{"class":1369},[575,1848,1687],{"class":590},[575,1850,1023],{"class":644},[575,1852,1785],{"class":644},[575,1854,1788],{"class":590},[575,1856,1858,1860,1862,1864,1866,1868,1870,1872,1874],{"class":577,"line":1857},25,[575,1859,1624],{"class":937},[575,1861,797],{"class":644},[575,1863,1629],{"class":644},[575,1865,1046],{"class":644},[575,1867,1606],{"class":1369},[575,1869,1600],{"class":590},[575,1871,1023],{"class":644},[575,1873,1640],{"class":644},[575,1875,1643],{"class":937},[575,1877,1879,1881,1883,1886],{"class":577,"line":1878},26,[575,1880,1649],{"class":1648},[575,1882,1046],{"class":644},[575,1884,1885],{"class":590},"Restoring your original uncommitted changes...",[575,1887,1657],{"class":644},[575,1889,1891,1893,1895],{"class":577,"line":1890},27,[575,1892,1662],{"class":586},[575,1894,1665],{"class":590},[575,1896,1897],{"class":590}," pop\n",[575,1899,1901],{"class":577,"line":1900},28,[575,1902,1673],{"class":937},[575,1904,1906],{"class":577,"line":1905},29,[575,1907,599],{"emptyLinePlaceholder":448},[575,1909,1911,1914,1916,1919],{"class":577,"line":1910},30,[575,1912,1913],{"class":1648},"echo",[575,1915,1046],{"class":644},[575,1917,1918],{"class":590},"✨ All local branches synced successfully!",[575,1920,1657],{"class":644},[560,1922,286],{"id":1923},"key-upgrades-in-this-script",[718,1925,1926,1932],{},[547,1927,1928,1931],{},[491,1929,1930],{},"Stash Safety Net:"," It actively checks for uncommitted edits and temporarily shelves them so your checkout transitions don't error out.",[547,1933,1934,1937,1938,1941],{},[491,1935,1936],{},"Fast-Forward Restrictions:"," Using ",[496,1939,1940],{},"--ff-only"," ensures that if a local branch has split or drifted too far from the remote history, the script will gracefully skip it rather than creating an automated merge mess.",[523,1943],{},[526,1945,291],{"id":1946},"convert-this-into-a-permanent-git-alias",[487,1948,1949],{},"Typing out long Bash scripts every time you open a project gets exhausting. Let's register this tool directly into your core Git configuration so it is accessible globally.",[487,1951,1952],{},"Open your global git configuration file:",[567,1954,1956],{"className":569,"code":1955,"language":571,"meta":167,"style":167},"git config --global --edit\n",[496,1957,1958],{"__ignoreMap":167},[575,1959,1960,1962,1965,1968],{"class":577,"line":46},[575,1961,730],{"class":586},[575,1963,1964],{"class":590}," config",[575,1966,1967],{"class":590}," --global",[575,1969,1970],{"class":590}," --edit\n",[487,1972,1973,1974,1977,1978,783],{},"Find the ",[496,1975,1976],{},"[alias]"," block and add a new custom command named ",[496,1979,1980],{},"pull-all",[567,1982,1986],{"className":1983,"code":1984,"language":1985,"meta":167,"style":167},"language-ini shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[alias]\n    pull-all = \"!f() { \\\n        curr=\\$(git rev-parse --abbrev-ref HEAD); \\\n        for b in \\$(git for-each-ref --format='%(refname:short)' refs\u002Fheads\u002F); do \\\n            git checkout \\$b && git pull --ff-only; \\\n        done; \\\n        git checkout \\$curr; \\\n    }; f\"\n","ini",[496,1987,1988,1993,1998,2003,2008,2013,2018,2023],{"__ignoreMap":167},[575,1989,1990],{"class":577,"line":46},[575,1991,1992],{},"[alias]\n",[575,1994,1995],{"class":577,"line":52},[575,1996,1997],{},"    pull-all = \"!f() { \\\n",[575,1999,2000],{"class":577,"line":58},[575,2001,2002],{},"        curr=\\$(git rev-parse --abbrev-ref HEAD); \\\n",[575,2004,2005],{"class":577,"line":109},[575,2006,2007],{},"        for b in \\$(git for-each-ref --format='%(refname:short)' refs\u002Fheads\u002F); do \\\n",[575,2009,2010],{"class":577,"line":607},[575,2011,2012],{},"            git checkout \\$b && git pull --ff-only; \\\n",[575,2014,2015],{"class":577,"line":618},[575,2016,2017],{},"        done; \\\n",[575,2019,2020],{"class":577,"line":624},[575,2021,2022],{},"        git checkout \\$curr; \\\n",[575,2024,2025],{"class":577,"line":629},[575,2026,2027],{},"    }; f\"\n",[487,2029,2030],{},"Save and exit. Now, clean updates across your entire workspace are compressed into a single elegant command:",[567,2032,2034],{"className":569,"code":2033,"language":571,"meta":167,"style":167},"git pull-all\n",[496,2035,2036],{"__ignoreMap":167},[575,2037,2038,2040],{"class":577,"line":46},[575,2039,730],{"class":586},[575,2041,2042],{"class":590}," pull-all\n",[526,2044,180],{"id":1266},[487,2046,2047,2048,2050,2051,2053],{},"Automating your terminal flow should never come at the expense of your repository's stability. By switching from a raw ",[496,2049,1439],{}," loop to an intentional, state-aware layout or leveraging ",[496,2052,1502],{},", you keep your workflows smooth, fast, and entirely conflict-free.",[2055,2056],"icon",{"name":2057},"i-simple-icons-nuxtdotjs",[2059,2060,2061],"note",{},[487,2062,2063],{},"Here is some additional information for your reader.",[2065,2066,2067],"tip",{},[487,2068,2069],{},"Here is a helpful suggestion.",[2071,2072,2073],"warning",{},[487,2074,2075],{},"Be careful with this action as it might have unexpected results.",[2077,2078,2079],"caution",{},[487,2080,2081],{},"This action cannot be undone.",[2083,2084,2085],"tabs",{},[2086,2087,2090,2096,2104,2113],"tabs-item",{"icon":2088,"label":2089},"i-lucide-code","Code",[2091,2092,2093],"callout",{},[487,2094,2095],{},"Lorem velit voluptate ex reprehenderit ullamco et culpa.",[567,2097,2102],{"className":2098,"code":2100,"language":2101},[2099],"language-text","\n:::\n\n:::tabs-item{label=\"Preview\" icon=\"i-lucide-eye\"}\n\n::callout\nLorem velit voluptate ex reprehenderit ullamco et culpa.\n::\n\n:::\n\n::\n","text",[496,2103,2100],{"__ignoreMap":167},[2105,2106],"iframe",{"src":2107,"title":2108,"frameBorder":2109,"allow":2110,"referrerPolicy":2111,"allowFullScreen":448,"style":2112},"https:\u002F\u002Fwww.youtube-nocookie.com\u002Fembed\u002F_eQxomah-nA?si=pDSzchUBDKb2NQu7","YouTube video player","0","accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share","strict-origin-when-cross-origin","aspect-ratio: 16\u002F9; width: 100%;",[2105,2114],{"style":2115,"src":2116,"allowFullScreen":448},"border: 1px solid rgba(0, 0, 0, 0.1); width: 100%; height: 450px;","https:\u002F\u002Fembed.figma.com\u002Ffile\u002F1544369209862884086\u002Fhf_embed?community_viewer=true&embed_host=fastma&fuid=960610330589944894&kind=file&page-selector=0&viewer=1",[1274,2118,2119],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":167,"searchDepth":607,"depth":607,"links":2121},[2122,2123,2126,2129,2130],{"id":1443,"depth":52,"text":266},{"id":1498,"depth":52,"text":271,"children":2124},[2125],{"id":1529,"depth":58,"text":276},{"id":1558,"depth":52,"text":281,"children":2127},[2128],{"id":1923,"depth":58,"text":286},{"id":1946,"depth":52,"text":291},{"id":1266,"depth":52,"text":180},[2132],{"id":2133,"color":1330,"description":2134,"extension":460,"featured":41,"icon":2135,"meta":2136,"name":2137,"slug":2138,"stem":2139,"__hash__":2140},"categories\u002Fcategories\u002Fterminal-and-shells.yml","Deep dives into shell configurations, command-line utilities, and productivity workflows.","i-codicon-terminal",{},"Terminal and Shells","terminal-and-shells","categories\u002Fterminal-and-shells","tpuWcAHcJUiqq_5LlkJQHndrI7vVveg-kedVRBtlxwc",{"src":2142,"alt":2143,"caption":2144},"\u002Fblogs\u002Fposts\u002Fgit-pull-all\u002Fcover.png","Visual depiction of a terminal running a Git automation loop across multiple local branch trees","Keep your local workspace seamlessly aligned with remote changes.","Stop manual checkouts. Learn why your naive git pull loops fail and discover the correct, automation-friendly way to fast-forward all local tracking branches at once.",[2147,2151],{"src":2148,"alt":2149,"caption":2150},"\u002Fblogs\u002Fposts\u002Fgit-pull-all\u002Fgit-fetch-diagram.png","Diagram showing the difference between git fetch all and sequential git pulls","Git fetch downloads references instantly without risking uncommitted changes.",{"src":2152,"alt":2153,"caption":2154},"\u002Fblogs\u002Fposts\u002Fgit-pull-all\u002Fscript-output.png","Clean terminal output showing automated branch transitions and fast-forward actions","Elegant script-driven updates across feature, staging, and main branches.",{"readingTime":2156},{"text":1313,"minutes":2157,"time":2158,"words":2159},3.595,215700,719,{"title":2161,"description":2162,"keywords":2163,"canonicalUrl":27},"How to Pull and Update All Local Git Branches Safely (2026 Guide)","Step-by-step tutorial exposing the dangers of looping git pull and configuring custom bash automation scripts and aliases to keep repos healthy.",[2164,1323,2165,2166,2167,2168],"Git","Bash","Git Fetch","Shell Scripting","Software Engineering","git-pull-all",[2171,2179,2188],{"id":2172,"color":2173,"description":2174,"extension":460,"icon":2175,"meta":2176,"name":2164,"slug":730,"stem":2177,"__hash__":2178},"tags\u002Ftags\u002Fgit.yml","#F05032","Git is a distributed version control system that allows developers to track changes in source code during software development. It enables collaboration, branching, and merging of code, making it an essential tool for modern software development workflows.","i-codicon-git-branch",{},"tags\u002Fgit","O8TA1_cFfkfLFG9uWLf6T5g5Ox_L8-lwYmempicMd2Y",{"id":2180,"color":2181,"description":2182,"extension":460,"icon":2135,"meta":2183,"name":2184,"slug":2185,"stem":2186,"__hash__":2187},"tags\u002Ftags\u002Fcommand-line.yml","#4CAF50","Command line tools and utilities for developers.",{},"Command Line","command-line","tags\u002Fcommand-line","0gaowGPie_cZRZvPlFLoQbYVwEdhMXUjsbtMEHoch9M",{"id":1329,"color":1330,"description":1331,"extension":460,"icon":1332,"meta":2189,"name":1323,"slug":1334,"stem":1335,"__hash__":1336},{},"iCn12PzErAj0KrVxqipSQMrwch_jhytyK5DMwPvyOUU",{"id":2192,"title":38,"anchors":2193,"author":2194,"body":2202,"categories":2904,"coverImage":2907,"date":2911,"description":2206,"draft":41,"excerpt":2912,"extension":1301,"featured":448,"gallery":2913,"meta":2922,"navigation":448,"path":39,"published":448,"publishedAt":2911,"seo":2928,"slug":2936,"stem":40,"tags":2937,"updatedAt":2911,"__hash__":2950},"blogs\u002Fblogs\u002Fpowershell-bash.md",[],{"id":446,"title":447,"active":448,"avatar":2195,"color":452,"company":2196,"description":458,"email":459,"extension":460,"featured":41,"meta":2197,"name":462,"slug":463,"socialLinks":2198,"stem":480,"website":481,"__hash__":482},{"src":450,"alt":451},{"name":454,"website":455,"icon":456,"role":457},{},[2199,2200,2201],{"platform":466,"url":467,"icon":468,"color":469},{"platform":471,"url":472,"icon":473,"color":474},{"platform":476,"url":477,"icon":478,"color":479},{"type":484,"value":2203,"toc":2895},[2204,2207,2218,2232,2242,2245,2248,2255,2258,2270,2281,2284,2369,2372,2397,2400,2414,2439,2444,2454,2462,2496,2515,2518,2529,2538,2553,2560,2580,2583,2607,2610,2686,2689,2695,2892],[487,2205,2206],{},"Learn how to make PowerShell look, feel, and behave exactly like a premium Bash\u002FZsh environment with autosuggestions, interactive subcommand completions, and fuzzy history search.",[487,2208,2209,2210,2213,2214,2217],{},"Let’s be honest. If you are coming from a Linux or macOS background, opening up a raw PowerShell (",[496,2211,2212],{},"pwsh",") terminal can feel a bit like stepping into a parallel universe where everything is ",[750,2215,2216],{},"almost"," familiar, but just clunky enough to drive you crazy.",[487,2219,2220,2221,2224,2225,2228,2229,2231],{},"You miss the instant, predictive text of ",[496,2222,2223],{},"fish",", the robust history search of ",[496,2226,2227],{},"zsh",", and the effortless subcommand completions of a well-tuned ",[496,2230,571],{}," setup. Out of the box, PowerShell’s tab-completion feels slow, and its visual feedback is... lacking.",[487,2233,2234,2235,2238,2239,2241],{},"But here is the secret: ",[491,2236,2237],{},"PowerShell is secretly an absolute powerhouse of customizability."," With a few modern modules and a slick profile configuration, you can make ",[496,2240,2212],{}," look, feel, and behave exactly like a premium Bash\u002FZsh environment—all while retaining PowerShell's insane object-oriented pipeline capabilities.",[487,2243,2244],{},"Here is how to build the ultimate Bash-ified PowerShell experience.",[526,2246,413],{"id":2247},"step-1-fix-the-keybindings-and-enable-fish-style-autosuggestions",[487,2249,2250,2251,2254],{},"The foundation of a good Bash experience is how the line editor behaves. PowerShell handles this via a built-in module called ",[491,2252,2253],{},"PSReadLine",". We just need to wake it up and give it the right instructions.",[487,2256,2257],{},"First, open your PowerShell profile in your favorite editor (e.g., VS Code):",[567,2259,2263],{"className":2260,"code":2261,"language":2262,"meta":167,"style":167},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","code $PROFILE\n\n","powershell",[496,2264,2265],{"__ignoreMap":167},[575,2266,2267],{"class":577,"line":46},[575,2268,2269],{},"code $PROFILE\n",[487,2271,2272,1233,2278],{},[750,2273,2274,2275],{},"(If the file doesn't exist yet, run ",[496,2276,2277],{},"New-Item -Path $PROFILE -Type File -Force",[750,2279,2280],{},"first).",[487,2282,2283],{},"Now, paste these essential configurations into your profile:",[567,2285,2287],{"className":2260,"code":2286,"language":2262,"meta":167,"style":167},"# Set Bash-like Emacs keybindings (Ctrl+A to start of line, Ctrl+E to end, etc.)\nSet-PSReadLineOption -EditMode Emacs\n\n# Enable Fish-like inline predictive text history\nSet-PSReadLineOption -PredictionSource History\n\n# Change the prediction view to \"ListView\" or \"InlineView\" (Arrow keys to navigate)\nSet-PSReadLineOption -PredictionViewStyle InlineView\n\n# Set the color of the predictive text to be a subtle gray\nSet-PSReadLineOption -Colors @{ InlinePrediction = '#666666' }\n\n# Bind the Right Arrow key to accept the current inline suggestion\nSet-PSReadLineKeyHandler -Chord 'RightArrow' -Function AcceptSuggestion\n\n# Bind Ctrl+Space to trigger standard menu completion (Zsh style)\nSet-PSReadLineKeyHandler -Chord 'Ctrl+Space' -Function MenuComplete\n\n",[496,2288,2289,2294,2299,2303,2308,2313,2317,2322,2327,2331,2336,2341,2345,2350,2355,2359,2364],{"__ignoreMap":167},[575,2290,2291],{"class":577,"line":46},[575,2292,2293],{},"# Set Bash-like Emacs keybindings (Ctrl+A to start of line, Ctrl+E to end, etc.)\n",[575,2295,2296],{"class":577,"line":52},[575,2297,2298],{},"Set-PSReadLineOption -EditMode Emacs\n",[575,2300,2301],{"class":577,"line":58},[575,2302,599],{"emptyLinePlaceholder":448},[575,2304,2305],{"class":577,"line":109},[575,2306,2307],{},"# Enable Fish-like inline predictive text history\n",[575,2309,2310],{"class":577,"line":607},[575,2311,2312],{},"Set-PSReadLineOption -PredictionSource History\n",[575,2314,2315],{"class":577,"line":618},[575,2316,599],{"emptyLinePlaceholder":448},[575,2318,2319],{"class":577,"line":624},[575,2320,2321],{},"# Change the prediction view to \"ListView\" or \"InlineView\" (Arrow keys to navigate)\n",[575,2323,2324],{"class":577,"line":629},[575,2325,2326],{},"Set-PSReadLineOption -PredictionViewStyle InlineView\n",[575,2328,2329],{"class":577,"line":635},[575,2330,599],{"emptyLinePlaceholder":448},[575,2332,2333],{"class":577,"line":865},[575,2334,2335],{},"# Set the color of the predictive text to be a subtle gray\n",[575,2337,2338],{"class":577,"line":870},[575,2339,2340],{},"Set-PSReadLineOption -Colors @{ InlinePrediction = '#666666' }\n",[575,2342,2343],{"class":577,"line":882},[575,2344,599],{"emptyLinePlaceholder":448},[575,2346,2347],{"class":577,"line":892},[575,2348,2349],{},"# Bind the Right Arrow key to accept the current inline suggestion\n",[575,2351,2352],{"class":577,"line":900},[575,2353,2354],{},"Set-PSReadLineKeyHandler -Chord 'RightArrow' -Function AcceptSuggestion\n",[575,2356,2357],{"class":577,"line":912},[575,2358,599],{"emptyLinePlaceholder":448},[575,2360,2361],{"class":577,"line":917},[575,2362,2363],{},"# Bind Ctrl+Space to trigger standard menu completion (Zsh style)\n",[575,2365,2366],{"class":577,"line":929},[575,2367,2368],{},"Set-PSReadLineKeyHandler -Chord 'Ctrl+Space' -Function MenuComplete\n",[560,2370,418],{"id":2371},"what-this-gives-you",[718,2373,2374,2387],{},[547,2375,2376,2379,2380,2382,2383,2386],{},[491,2377,2378],{},"Inline History Predictions:"," As you type, ",[496,2381,2212],{}," will look through your command history and visually suggest the rest of the command in gray text. Press the ",[491,2384,2385],{},"Right Arrow"," to accept it.",[547,2388,2389,2392,2393,2396],{},[491,2390,2391],{},"Zsh-style Menus:"," Hit ",[496,2394,2395],{},"Ctrl + Space"," to open an interactive grid menu of all available completions right in your terminal buffer.",[526,2398,423],{"id":2399},"step-2-supercharge-subcommand-completions-with-carapace",[487,2401,2402,2403,1240,2406,2409,2410,2413],{},"Standard PowerShell only knows how to tab-complete standard cmdlet arguments (like ",[496,2404,2405],{},"-Path",[496,2407,2408],{},"-Credential","). If you type ",[496,2411,2412],{},"git che[TAB]",", it stares at you blankly.",[487,2415,2416,2417,506,2419,506,2422,506,2425,506,2428,506,2431,2434,2435,2438],{},"To get full subcommand completion for hundreds of CLI tools (",[496,2418,730],{},[496,2420,2421],{},"docker",[496,2423,2424],{},"kubectl",[496,2426,2427],{},"npm",[496,2429,2430],{},"gh",[496,2432,2433],{},"gcloud","), we are going to use ",[491,2436,2437],{},"Carapace-bin",", the absolute gold standard for multi-shell command completion.",[544,2440,2441],{},[547,2442,2443],{},"Install Carapace using a package manager like Scoop or Winget:",[567,2445,2447],{"className":2260,"code":2446,"language":2262,"meta":167,"style":167},"winget install rsteube.carapace\n\n",[496,2448,2449],{"__ignoreMap":167},[575,2450,2451],{"class":577,"line":46},[575,2452,2453],{},"winget install rsteube.carapace\n",[544,2455,2456],{"start":52},[547,2457,2458,2459,783],{},"Add the initialization logic to your ",[496,2460,2461],{},"$PROFILE",[567,2463,2465],{"className":2260,"code":2464,"language":2262,"meta":167,"style":167},"# Initialize Carapace completions for PowerShell\n# This hooks into the native engine to provide rich subcommand completions\nif (Get-Command carapace -ErrorAction SilentlyContinue) {\n    $old_executioncontext = $ExecutionContext\n    carapace _powershell | Out-String | Invoke-Expression\n}\n\n",[496,2466,2467,2472,2477,2482,2487,2492],{"__ignoreMap":167},[575,2468,2469],{"class":577,"line":46},[575,2470,2471],{},"# Initialize Carapace completions for PowerShell\n",[575,2473,2474],{"class":577,"line":52},[575,2475,2476],{},"# This hooks into the native engine to provide rich subcommand completions\n",[575,2478,2479],{"class":577,"line":58},[575,2480,2481],{},"if (Get-Command carapace -ErrorAction SilentlyContinue) {\n",[575,2483,2484],{"class":577,"line":109},[575,2485,2486],{},"    $old_executioncontext = $ExecutionContext\n",[575,2488,2489],{"class":577,"line":607},[575,2490,2491],{},"    carapace _powershell | Out-String | Invoke-Expression\n",[575,2493,2494],{"class":577,"line":618},[575,2495,1104],{},[487,2497,2498,2499,2501,2502,2504,2505,506,2508,506,2511,2514],{},"Now, try typing ",[496,2500,730],{}," followed by ",[496,2503,2395],{},". You will see an interactive menu showing options like ",[496,2506,2507],{},"checkout",[496,2509,2510],{},"commit",[496,2512,2513],{},"clone",", complete with help descriptions for every single subcommand!",[526,2516,428],{"id":2517},"step-3-add-fuzzy-history-searching-fzf",[487,2519,2520,2521,2524,2525,2528],{},"If you've ever used ",[496,2522,2523],{},"Ctrl + R"," in Bash to reverse-search your history using a fuzzy finder, you know you can't live without it. We can bring this exact feature to PowerShell using the ",[496,2526,2527],{},"PSFzf"," module.",[544,2530,2531],{},[547,2532,2533,2534,2537],{},"Install the ",[496,2535,2536],{},"fzf"," binary and the PowerShell wrapper module:",[567,2539,2541],{"className":2260,"code":2540,"language":2262,"meta":167,"style":167},"winget install junegunn.fzf\nInstall-Module PSFzf -Scope CurrentUser -Force\n\n",[496,2542,2543,2548],{"__ignoreMap":167},[575,2544,2545],{"class":577,"line":46},[575,2546,2547],{},"winget install junegunn.fzf\n",[575,2549,2550],{"class":577,"line":52},[575,2551,2552],{},"Install-Module PSFzf -Scope CurrentUser -Force\n",[544,2554,2555],{"start":52},[547,2556,2557,2558,783],{},"Add this to your ",[496,2559,2461],{},[567,2561,2563],{"className":2260,"code":2562,"language":2262,"meta":167,"style":167},"Import-Module PSFzf\n# Overrides Ctrl+R to use the fuzzy finder for your PowerShell history\nSet-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock { [PSFzf]::PostContextHistoryFzf() }\n\n",[496,2564,2565,2570,2575],{"__ignoreMap":167},[575,2566,2567],{"class":577,"line":46},[575,2568,2569],{},"Import-Module PSFzf\n",[575,2571,2572],{"class":577,"line":52},[575,2573,2574],{},"# Overrides Ctrl+R to use the fuzzy finder for your PowerShell history\n",[575,2576,2577],{"class":577,"line":58},[575,2578,2579],{},"Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock { [PSFzf]::PostContextHistoryFzf() }\n",[526,2581,433],{"id":2582},"step-4-inject-essential-bash-aliases-functions",[487,2584,2585,2586,2589,2590,2593,2594,506,2597,2600,2601,1240,2604,514],{},"PowerShell has a few built-in aliases like ",[496,2587,2588],{},"ls"," and ",[496,2591,2592],{},"rm",", but they map directly to PowerShell cmdlets (",[496,2595,2596],{},"Get-ChildItem",[496,2598,2599],{},"Remove-Item","), which don't accept standard Linux flags like ",[496,2602,2603],{},"-la",[496,2605,2606],{},"-rf",[487,2608,2609],{},"Let's clean that up by introducing native functions that mirror standard Unix behavior:",[567,2611,2613],{"className":2260,"code":2612,"language":2262,"meta":167,"style":167},"# Quick directory listings that accept traditional arguments\nfunction ll { Get-ChildItem -Path . -Force | Out-Host }\nfunction la { Get-ChildItem -Path . -Force -Recurse | Out-Host }\n\n# A quick wrapper to make 'grep' behave beautifully\nfunction grep ($pattern) { Select-String -Pattern $pattern }\n\n# Ensure sudo behavior exists via 'gsudo' (install via winget install gerardog.gsudo)\nif (Get-Command gsudo -ErrorAction SilentlyContinue) {\n    Set-Alias -Name sudo -Value gsudo\n}\n\n# Quick navigation shortcuts\nfunction .. { Set-Location .. }\nfunction ... { Set-Location ..\\.. }\n\n",[496,2614,2615,2620,2625,2630,2634,2639,2644,2648,2653,2658,2663,2667,2671,2676,2681],{"__ignoreMap":167},[575,2616,2617],{"class":577,"line":46},[575,2618,2619],{},"# Quick directory listings that accept traditional arguments\n",[575,2621,2622],{"class":577,"line":52},[575,2623,2624],{},"function ll { Get-ChildItem -Path . -Force | Out-Host }\n",[575,2626,2627],{"class":577,"line":58},[575,2628,2629],{},"function la { Get-ChildItem -Path . -Force -Recurse | Out-Host }\n",[575,2631,2632],{"class":577,"line":109},[575,2633,599],{"emptyLinePlaceholder":448},[575,2635,2636],{"class":577,"line":607},[575,2637,2638],{},"# A quick wrapper to make 'grep' behave beautifully\n",[575,2640,2641],{"class":577,"line":618},[575,2642,2643],{},"function grep ($pattern) { Select-String -Pattern $pattern }\n",[575,2645,2646],{"class":577,"line":624},[575,2647,599],{"emptyLinePlaceholder":448},[575,2649,2650],{"class":577,"line":629},[575,2651,2652],{},"# Ensure sudo behavior exists via 'gsudo' (install via winget install gerardog.gsudo)\n",[575,2654,2655],{"class":577,"line":635},[575,2656,2657],{},"if (Get-Command gsudo -ErrorAction SilentlyContinue) {\n",[575,2659,2660],{"class":577,"line":865},[575,2661,2662],{},"    Set-Alias -Name sudo -Value gsudo\n",[575,2664,2665],{"class":577,"line":870},[575,2666,1104],{},[575,2668,2669],{"class":577,"line":882},[575,2670,599],{"emptyLinePlaceholder":448},[575,2672,2673],{"class":577,"line":892},[575,2674,2675],{},"# Quick navigation shortcuts\n",[575,2677,2678],{"class":577,"line":900},[575,2679,2680],{},"function .. { Set-Location .. }\n",[575,2682,2683],{"class":577,"line":912},[575,2684,2685],{},"function ... { Set-Location ..\\.. }\n",[526,2687,438],{"id":2688},"step-5-put-it-all-together-your-master-profile",[487,2690,2691,2692,2694],{},"Here is your complete, optimized ",[496,2693,2461],{},". Copy this layout, save the file, and restart your terminal to activate your brand new, incredibly fast Bash-ified environment:",[567,2696,2698],{"className":2260,"code":2697,"language":2262,"meta":167,"style":167},"# ==========================================\n# 1. PSREADLINE CONFIG (Autosuggestions & Keybindings)\n# ==========================================\nImport-Module PSReadLine\nSet-PSReadLineOption -EditMode Emacs\nSet-PSReadLineOption -PredictionSource History\nSet-PSReadLineOption -PredictionViewStyle InlineView\nSet-PSReadLineOption -Colors @{ InlinePrediction = '#666666' }\n\n# Intuitive Navigation\nSet-PSReadLineKeyHandler -Chord 'RightArrow' -Function AcceptSuggestion\nSet-PSReadLineKeyHandler -Chord 'Ctrl+Space' -Function MenuComplete\n\n# Up\u002FDown Arrows search history matching what you've already typed\nSet-PSReadLineKeyHandler -Chord 'UpArrow' -Function HistorySearchBackward\nSet-PSReadLineKeyHandler -Chord 'DownArrow' -Function HistorySearchForward\n\n# ==========================================\n# 2. SUBCOMMAND COMPLETIONS (Carapace Engine)\n# ==========================================\nif (Get-Command carapace -ErrorAction SilentlyContinue) {\n    carapace _powershell | Out-String | Invoke-Expression\n}\n\n# ==========================================\n# 3. FUZZY HISTORY MATCHING (FZF)\n# ==========================================\nif (Get-Module -ListAvailable -Name PSFzf) {\n    Import-Module PSFzf\n    Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock { [PSFzf]::PostContextHistoryFzf() }\n}\n\n# ==========================================\n# 4. BASH ALIASES & UTILITIES\n# ==========================================\nfunction ll { Get-ChildItem -Force }\nfunction grep ($pattern) { $Input | Select-String -Pattern $pattern }\nif (Get-Command gsudo -ErrorAction SilentlyContinue) { Set-Alias -Name sudo -Value gsudo }\nfunction .. { Set-Location .. }\n\nWrite-Host \"🚀 PowerShell environment loaded with Bash-UX engine.\" -ForegroundColor Cyan\n\n",[496,2699,2700,2705,2710,2714,2719,2723,2727,2731,2735,2739,2744,2748,2752,2756,2761,2766,2771,2775,2779,2784,2788,2792,2796,2800,2804,2808,2813,2817,2822,2827,2832,2837,2842,2847,2853,2858,2864,2870,2876,2881,2886],{"__ignoreMap":167},[575,2701,2702],{"class":577,"line":46},[575,2703,2704],{},"# ==========================================\n",[575,2706,2707],{"class":577,"line":52},[575,2708,2709],{},"# 1. PSREADLINE CONFIG (Autosuggestions & Keybindings)\n",[575,2711,2712],{"class":577,"line":58},[575,2713,2704],{},[575,2715,2716],{"class":577,"line":109},[575,2717,2718],{},"Import-Module PSReadLine\n",[575,2720,2721],{"class":577,"line":607},[575,2722,2298],{},[575,2724,2725],{"class":577,"line":618},[575,2726,2312],{},[575,2728,2729],{"class":577,"line":624},[575,2730,2326],{},[575,2732,2733],{"class":577,"line":629},[575,2734,2340],{},[575,2736,2737],{"class":577,"line":635},[575,2738,599],{"emptyLinePlaceholder":448},[575,2740,2741],{"class":577,"line":865},[575,2742,2743],{},"# Intuitive Navigation\n",[575,2745,2746],{"class":577,"line":870},[575,2747,2354],{},[575,2749,2750],{"class":577,"line":882},[575,2751,2368],{},[575,2753,2754],{"class":577,"line":892},[575,2755,599],{"emptyLinePlaceholder":448},[575,2757,2758],{"class":577,"line":900},[575,2759,2760],{},"# Up\u002FDown Arrows search history matching what you've already typed\n",[575,2762,2763],{"class":577,"line":912},[575,2764,2765],{},"Set-PSReadLineKeyHandler -Chord 'UpArrow' -Function HistorySearchBackward\n",[575,2767,2768],{"class":577,"line":917},[575,2769,2770],{},"Set-PSReadLineKeyHandler -Chord 'DownArrow' -Function HistorySearchForward\n",[575,2772,2773],{"class":577,"line":929},[575,2774,599],{"emptyLinePlaceholder":448},[575,2776,2777],{"class":577,"line":941},[575,2778,2704],{},[575,2780,2781],{"class":577,"line":947},[575,2782,2783],{},"# 2. SUBCOMMAND COMPLETIONS (Carapace Engine)\n",[575,2785,2786],{"class":577,"line":1811},[575,2787,2704],{},[575,2789,2790],{"class":577,"line":1821},[575,2791,2481],{},[575,2793,2794],{"class":577,"line":1827},[575,2795,2491],{},[575,2797,2798],{"class":577,"line":1832},[575,2799,1104],{},[575,2801,2802],{"class":577,"line":1838},[575,2803,599],{"emptyLinePlaceholder":448},[575,2805,2806],{"class":577,"line":1857},[575,2807,2704],{},[575,2809,2810],{"class":577,"line":1878},[575,2811,2812],{},"# 3. FUZZY HISTORY MATCHING (FZF)\n",[575,2814,2815],{"class":577,"line":1890},[575,2816,2704],{},[575,2818,2819],{"class":577,"line":1900},[575,2820,2821],{},"if (Get-Module -ListAvailable -Name PSFzf) {\n",[575,2823,2824],{"class":577,"line":1905},[575,2825,2826],{},"    Import-Module PSFzf\n",[575,2828,2829],{"class":577,"line":1910},[575,2830,2831],{},"    Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock { [PSFzf]::PostContextHistoryFzf() }\n",[575,2833,2835],{"class":577,"line":2834},31,[575,2836,1104],{},[575,2838,2840],{"class":577,"line":2839},32,[575,2841,599],{"emptyLinePlaceholder":448},[575,2843,2845],{"class":577,"line":2844},33,[575,2846,2704],{},[575,2848,2850],{"class":577,"line":2849},34,[575,2851,2852],{},"# 4. BASH ALIASES & UTILITIES\n",[575,2854,2856],{"class":577,"line":2855},35,[575,2857,2704],{},[575,2859,2861],{"class":577,"line":2860},36,[575,2862,2863],{},"function ll { Get-ChildItem -Force }\n",[575,2865,2867],{"class":577,"line":2866},37,[575,2868,2869],{},"function grep ($pattern) { $Input | Select-String -Pattern $pattern }\n",[575,2871,2873],{"class":577,"line":2872},38,[575,2874,2875],{},"if (Get-Command gsudo -ErrorAction SilentlyContinue) { Set-Alias -Name sudo -Value gsudo }\n",[575,2877,2879],{"class":577,"line":2878},39,[575,2880,2680],{},[575,2882,2884],{"class":577,"line":2883},40,[575,2885,599],{"emptyLinePlaceholder":448},[575,2887,2889],{"class":577,"line":2888},41,[575,2890,2891],{},"Write-Host \"🚀 PowerShell environment loaded with Bash-UX engine.\" -ForegroundColor Cyan\n",[1274,2893,2894],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":167,"searchDepth":607,"depth":607,"links":2896},[2897,2900,2901,2902,2903],{"id":2247,"depth":52,"text":413,"children":2898},[2899],{"id":2371,"depth":58,"text":418},{"id":2399,"depth":52,"text":423},{"id":2517,"depth":52,"text":428},{"id":2582,"depth":52,"text":433},{"id":2688,"depth":52,"text":438},[2905],{"id":2133,"color":1330,"description":2134,"extension":460,"featured":41,"icon":2135,"meta":2906,"name":2137,"slug":2138,"stem":2139,"__hash__":2140},{},{"src":2908,"alt":2909,"caption":2910},"\u002Fblogs\u002Fposts\u002Fpowershell-bash\u002Fcover.png","Stylized terminal window showing predictive text and interactive completion menus","Transform your PowerShell experience with modern shell features.","2026-06-16","[object Object]",[2914,2918],{"src":2915,"alt":2916,"caption":2917},"\u002Fblogs\u002Fposts\u002Fpowershell-bash\u002Fpsreadline-demo.png","Inline prediction highlighting history matching in the shell buffer","Inline predictions mimic the popular Fish shell experience.",{"src":2919,"alt":2920,"caption":2921},"\u002Fblogs\u002Fposts\u002Fpowershell-bash\u002Fcarapace-menu.png","Interactive grid showing git subcommand auto-completions via Carapace","Rich multi-shell subcommand menus triggered natively with Ctrl+Space.",{"readingTime":2923},{"text":2924,"minutes":2925,"time":2926,"words":2927},"5 min read",4.515,270900,903,{"title":2929,"description":2930,"keywords":2931,"canonicalUrl":39},"How to Make PowerShell Behave Like Bash\u002FZsh (2026 Guide)","Step-by-step tutorial to configure pwsh with emacs keybindings, fish-style autocomplete, carapace subcommand popups, and fzf fuzzy history search.",[2932,2165,2933,2934,2253,2935],"PowerShell","Carapace","FZF","Terminal Productivity","powershell-bash",[2938,2946,2948],{"id":2939,"color":2940,"description":2941,"extension":460,"icon":2942,"meta":2943,"name":2932,"slug":2262,"stem":2944,"__hash__":2945},"tags\u002Ftags\u002Fpowershell.yml","#012456","PowerShell scripting, cmdlets, and automation for system administration and development.","i-codicon-terminal-powershell",{},"tags\u002Fpowershell","JFyyC4CEgZ_YjOnRbTcAgCjvrKEib6nR3-wLVwUCA0c",{"id":2180,"color":2181,"description":2182,"extension":460,"icon":2135,"meta":2947,"name":2184,"slug":2185,"stem":2186,"__hash__":2187},{},{"id":1329,"color":1330,"description":1331,"extension":460,"icon":1332,"meta":2949,"name":1323,"slug":1334,"stem":1335,"__hash__":1336},{},"pNDEePCTBiliywEN3KlyB3C0I2sekadPa4-sNxzX5-Q",1782753894839]