Tag: git

Learn Git with beginner-friendly guides, tips, and tutorials. From Git basics to version control workflows, our posts help you understand how to use Git with confidence.

  • Husky Hooks: The Easy Way to Improve Your Project Workflow

    Husky Hooks: The Easy Way to Improve Your Project Workflow

    We all miss stuff sometimes — skipping a test run, forgetting to lint, or pushing code that breaks something.
    Yes, guilty as charged! Husky hooks help you catch those issues early by running scripts right when you commit or push. 🐶
    It’s a simple way to keep your workflow clean, lower the pressure, save time, and avoid nasty surprises later.

    Introduction: Why use Husky hooks in your project?

    Husky is a great tool to help you out when working on a project and being proactive. It can catch problems before they are committed and make it into your codebase.

    How? By running scripts like tests or linters when committing or pushing your code. It’s a simple way to enforce code quality.

    But why not just use native Git hooks or a CI tool like CircleCI or GitHub Actions, you might wonder… and honestly, that’s a fair question — I asked the same thing when I first came across Husky.

    The answer really comes down to when you want to catch issues in your code, and whether you’re comfortable setting up native Git hooks or working with a team where shared, versioned hooks make more sense.

    Do you want to wait for your CI tool to run all steps just to tell you a test failed or a semicolon was missing?
    Or would you rather know right away, before even pushing your code? ⚡

    What are you waiting for if you’d like to catch issues immediately? 🚀
    Let’s go ahead and install Husky and learn more about this cool tool! 🛠️🐶

    Installing and initializing Husky in your project

    Installing Husky is straightforward; you just type in your terminal

    npm
    npm install --save-dev husky
    Bash

    Or (if you are using yarn)

    yarn
    yarn add --dev husky
    Bash

    Now that we’ve installed the package, let’s go ahead and initialize it by typing:

    Bash
    npx husky init
    Bash

    Initializing Husky does the following:

    • creates a .husky directory in your project, which includes:
      • a pre-commit hook file
      • a _ subfolder for additional settings.
    • Adds a prepare script to your package.json file to ensure Husky is set up when dependencies are installed.

    .husky/pre-commit

    The pre-commit file is a Git hook managed by Husky. It runs automatically before each commit, allowing you to run scripts like linters or tests to catch issues early.

    When Husky initializes its structure, it adds the following content to this hook file:

    pre-commit
    npm test
    Plaintext

    This basically means that whenever you are running your git commit command, Husky will first run npm test. If the tests pass, the commit will go through. If they fail, the commit will be blocked, and you’ll need to fix the errors before trying again.

    When I tried this in a brand-new project by making a simple change and committing it, here’s what I saw:

    git commit -m "A simple change to see pre-commit hook"
    
    > [email protected] test
    > jest
    
     PASS  src/pages/hello.test.ts
     PASS  src/components/heading.test.tsx
    
    Test Suites: 2 passed, 2 total
    Tests:       2 passed, 2 total
    Snapshots:   0 total
    Time:        0.491 s, estimated 1 s
    Ran all test suites.
    [playground c6e4aaf] A simple change to see pre-commit hook
     2 files changed, 5 insertions(+), 1 deletion(-)
     create mode 100644 .husky/pre-commit
    
    
    Bash

    See? It ran the two tests included in my project and then finalized the commit process.

    .husky/_ folder

    This folder is created by Husky and contains setup code that helps your Git hooks run smoothly across different systems.

    You usually don’t need to touch anything here — it just works in the background to support the other hook files.

    prepare script

    When you set up Husky, it adds a prepare script to your package.json file:

    package.json
    "scripts": {
      "prepare": "husky install"
    }
    JSON5

    This script makes sure git hooks are installed whenever someone installs your project’s dependencies (e.g., by running npm install or yarn install).

    This could come in handy if you are sharing your project with a team. The prepare script will ensure Husky works automatically for everyone without any extra steps needed.

    Expanding pre-commit: Catch more before it hits your repo

    Although running tests before committing is what Husky suggests by default when it initializes, I personally find that a bit too much. It feels like a blocker when all I want is to make a quick commit to save my progress. So instead of leaving npm run test in the pre-commit file, I prefer to remove the testing and go with simpler, quicker checks at that point.

    Before we change our pre-commit file, I just want to share a quick tip — did you know you can test Husky hooks without having to write a new commit message every single time?

    Good news: you can do exactly that by adding a simple line at the end of your pre-commit file.

    pre-commit
    npm test
    
    exit 1
    
    Plaintext

    exit-1 will stop the script from continuing, which makes it a safe way to test your pre-commit commands without actually committing your changes.

    Hook for linting checks

    Go to your .husky folder and open the pre-commit file replace its content with:

    pre-commit
    echo "🐶 Executing pre-commit hook..."
    echo ""
    
    # Run lint on staged files
    
    echo "🔍 Running ESLint on staged files..."
    
    npx eslint .
    
    echo "✅ ESLint passed."
    
    Plaintext

    By doing this, we’ve added ESLint checks right before committing — simple as that!

    To make sure it works, try committing some new changes, and you’ll see the results show up right in your terminal.

    🐶 Executing pre-commit hook...
    
    🔍 Running ESLint on staged files...
     ESLint passed.
    
    Bash

    Awesome, right? No linting errors! 🎉
    But what if there were some? What would that look like?

    I added a small linting issue (couple of spaces) to test it, and here’s what showed up when I ran it again:

    🐶 Executing pre-commit hook...
    
    🔍 Running ESLint on staged files...
    
    /my-project/src/components/Heading.test.tsx
      6:5  error  Delete `··`  
    
     1 problem (1 error, 0 warnings)
      1 error and 0 warnings potentially fixable with the `--fix` option.
    
    Bash

    All that’s left now is to fix the issue and commit the changes successfully. ✅

    Hooks to catch console.log statements

    Now that we’ve got linting checks in place, why not expand them a bit and catch things we definitely don’t want sneaking into our code — like console.logs maybe?

    Just add the following content to your pre-commit file:

    pre-commit
    echo "🐶 Executing pre-commit hook..."
    echo ""
    
    # Run lint on staged files
    
    echo "🔍 Running ESLint on staged files..."
    
    npx eslint .
    
    echo "✅ ESLint passed."
    echo ""
    
    # Match staged JS/TS files
    FILES_PATTERN='\.(js|ts)(x)?$'
    
    # Disallowed patterns: console methods
    FORBIDDEN='(console.log)'
    
    echo "🔎 Checking staged files for forbidden patterns (e.g. console.log)..."
    
    # Scan staged files for forbidden patterns
    if git diff --cached --name-only --diff-filter=ACM | \
        grep -E "$FILES_PATTERN" | \
        xargs grep --with-filename -n -E "$FORBIDDEN" | \
        grep -v '^\s*//'; then
    
        echo ""
        echo "🚫 COMMIT REJECTED! Found forbidden patterns"
        echo "😅 Please clean them up before committing."
        echo ""
        exit 1
    fi
    
    echo "✅ No forbidden patterns found!"
    echo "✅ Git pre-commit hook passed. You're good to go 🚀"
    
    exit 0
    
    
    Plaintext

    Let’s check what each part does

    echo is a command used to print informational messages in the terminal — basically just outputting text so we can see what’s happening.

    exit 0 means the script completed successfully, while exit 1 signals an error or that something failed.

    Next, we see:

    pre-commit
    # Match staged JS/TS files
    FILES_PATTERN='\.(js|ts)(x)?$'
    
    # Disallowed patterns: console methods
    FORBIDDEN='(console.log)'
    Plaintext

    In this part, by using FILES_PATTERN, we’re basically saying we only want to match files with the extensions .js, .jsx, .ts, or .tsx — and yep, you guessed it, I’m working in a project that’s transitioning from JS to TS!

    The next constant, FORBIDDEN, defines what I don’t want slipping into my commits — for now, that’s just console.logs.

    The next part is the trickiest one:

    pre-commit
    if git diff --cached --name-only --diff-filter=ACM | \
        grep -E "$FILES_PATTERN" | \
        xargs grep --with-filename -n -E "$FORBIDDEN" | \
        grep -v '^\s*//'; then
    
        echo ""
        echo "🚫 COMMIT REJECTED! Found forbidden patterns"
        echo "😅 Please clean them up before committing."
        echo ""
        exit 1
    fi
    Plaintext

    It’s a loop that goes through all the staged files and checks each one against every pattern we’ve defined, like console.log. If it finds a match, it prints an error message showing the file and the exact pattern it caught.

    Otherwise, it lets us know everything’s clean and we’re good to move forward with the commit:

    pre-commit
    echo "✅ No forbidden patterns found!"
    echo "✅ Git pre-commit hook passed. You're good to go 🚀"
    
    Plaintext

    To test this script, I added a console.log to one of my files, just to see what it would print when running this hook

    🐶 Executing pre-commit hook...
    
    🔍 Running ESLint on staged files...
     ESLint passed.
    
    🔎 Checking staged files for forbidden patterns (e.g. console.log)...
    src/components/Heading.test.tsx:6:    console.log('test');
    
    🚫 COMMIT REJECTED! Found forbidden patterns
    😅 Please clean them up before committing.
    
    Bash

    After fixing that and removing the console.log, I ran it again and saw everything passed — no errors, no blocks. Just a smooth, satisfying commit! 🙌

    🐶 Executing pre-commit hook...
    
    🔍 Running ESLint on staged files...
     ESLint passed.
    
    🔎 Checking staged files for forbidden patterns (e.g. console.log)...
     No forbidden patterns found!
     Git pre-commit hook passed. You're good to go 🚀
    
    
    Bash

    This script could easily be expanded to catch all console methods like .log, .info, and so on — or even .only in your test files. All you need to do is update the FORBIDDEN constant like this:

    pre-commit
    # Disallowed patterns: console methods
    FORBIDDEN='(console\.(log|info|warn|error|clear|dir)|it\.only)'
    Plaintext

    Other Git hook ideas to level up your workflow

    Although using the pre-commit hook may seem like it’s blocking your workflow or might appear straightforward in terms of what you can do with it, there are other use cases where you can run scripts at different stages, not just on commit.
    Here are a few common Husky hooks you can use:

    • commit-msg – Validate or format the commit message using your project’s guidelines or some conventional ones
    • pre-push – Run final checks before pushing to remote
    • post-merge – Automatically sync dependencies or regenerate files after a merge (e.g., run npm install or pnpm install) 🔄
    • post-checkout – Run scripts after switching branches (e.g., load env files, clean build cache)

    These hooks are just examples of what’s possible — you don’t need to use them all, but knowing they exist can help you pick the right tool for the right task.
    Start small, and build up as your project grows!

    Husky vs GitHub actions: When to use each tool

    You might be working on a project that already uses a CI/CD tool like GitHub Actions or CircleCI, and wondering — how is that different from Husky? 🤔
    Let’s look at some key differences to help you decide whether Husky is a good fit for your project.

    Feature
    Husky
    CI/CD Tools (e.g., GitHub Actions, GitLab CI)
    Runs when?
    Locally, before code is committed or pushed
    After code is pushed to a remote repository
    Best for
    Catching issues early, enforcing local standards
    Automating builds, tests, deployments
    Speed
    Instant feedback (runs on your machine)
    Slower (runs in external environments)
    Purpose
    Prevent bad code from leaving your laptop 💻
    Handle what happens after it leaves your laptop 🚀

    The way I see it, it’s great to save time and feel confident that everything I’m pushing follows the project’s rules and guidelines. That’s why I’d choose to use both: CI/CD tools for automation after pushing, and Husky for those extra checks before the code even leaves my machine.

    Local git hooks vs Husky: What’s the difference?

    If you’ve worked with Git hooks before, it’s only natural to question what Husky really adds on top of them.
    I had the exact same thought when I first came across it. And then it clicked — let’s take a closer look at how they differ. 🔍

    Feature
    Local Git Hooks
    Husky
    Setup
    Manual – you write and place hook scripts
    Managed by Husky with simple commands
    Version control
    Not tracked by default
    Fully version-controlled in your repo
    Sharing with team
    Hard to sync
    Easy to share and maintain across the team

    I’d say the most significant and most useful advantage of Husky is that it lets you share your hooks with your team and track them through Git.
    I used to try setting up Git hooks manually, even when working solo — but it always felt like this mysterious black box, and I kept putting it off.
    Husky makes the whole process way easier and more straightforward. Plus, being able to commit your hooks with the repo and even reuse the same setup across projects? Huge time-saver. Count me in! 🙌

    Frequently Asked Questions

    Is there a way to temporarily skip Git hooks?

    Yes, you can!
    If you’re under pressure or just need to skip Git hooks (including Husky hooks) for any reason, you can do it by adding the --no-verify flag to your Git command.

    For example

    git commit -m "My quick fix" --no-verify
    Bash

    Just keep in mind — skipping hooks should be the exception, not the habit. Hooks are there to help your workflow, not get in the way. 😉

    Another way to do this is by using HUSKY=0 in your script e.g

    HUSKY=0 git commit ...
    Bash

    I got used to using --no-verify when I want to skip hooks, but it’s nice to know that Husky offers an alternative.

    Can I use Husky locally even if the rest of the team isn’t?

    Absolutely! You can set up Husky on your own without forcing it on others. Since Husky hooks live in the .husky/ folder, you can simply add that folder to .gitignore if you don’t want to commit it.
    Alternatively, you can commit it and let others opt in if they want — it’s up to your team’s workflow.

    Have you used Husky in your projects, or do you prefer sticking with native Git hooks or CI tools?
    Drop a comment and share how you manage your Git workflow — We’d love to hear what’s worked for you! 💬👇

  • What does git add -a do?

    If you’re reading this post, chances are you’re looking for a Git command that stages all changes before committing. To set the record straight: the correct command is git add -A. A quick look at the git add documentation will show you that git add -a doesn’t exist. Instead, git add -A is the command that stages all recent changes — including new, modified, and deleted files.

    Let’s take a closer look to see if this is the command you’re really after.

    Common Mistake: git add -a

    When someone types git add -a, they’re usually trying to stage everything before a commit. It’s often a case of muscle memory or a mistaken assumption that -a stands for “add all.”

    In most situations, what the user actually meant was either:

    • git add -A to stage everything, or
    • git add . to stage changes in the current folder and below

    git add . vs git add -A

    These two commands are often used interchangeably, but they’re not exactly the same. While both will stage new, modified, and (in modern Git) deleted files, the main difference lies in their scope.

    git add -A: Stages Everything, Everywhere

    When you run git add -A, Git stages all changes across the entire working tree, no matter where you are in the project.
    For example, even if you’re working in a deep directory like src/assets/images, git add -A will still stage changes from higher directories like src/ or the root.

    git add .: Stages From the Current Directory Down

    On the other hand, git add . only stages changes in the current directory and its subdirectories. The dot (.) refers to “this folder,” so changes in sibling or parent directories won’t be included.

    So, When Does It Matter?

    If you’re working from the root of your repository, there’s practically no difference between git add . and git add -A in modern Git versions — both will stage everything.

    But if you’re working in a subdirectory and want to stage all changes in the project, you should use git add -A.

    If you only want to stage changes within the folder you’re in, then git add . is the right choice.

    Frequently Asked Questions (FAQ)

    Is git add -a a valid Git command?

    No — git add -a is not a valid command. If you try it, Git will return an error: error: unknown switch 'a'.
    The correct command to stage all changes is git add -A.

    Do I need to run git add -A from the root of my repository?

    No, you can run git add -A from any directory inside your project, and it will always stage changes across the entire directory

    Thanks for being here! 🙌 If you found this post helpful, giving it a like or share means a lot to us — it helps others find it too.

    Got another Git command that’s confusing or unclear? Drop a comment below, and we’ll be happy to explain it in a future post or reply directly. We’re here to make Git simpler, one command at a time. 😊

  • How to install Git on Mac – MacOS for beginners

    How to install Git on Mac – MacOS for beginners

    So, you’re new to macOS and ready to set up Git? Great choice! Git is one of the essential tools for developers, and installing it should be one of the first steps in your journey. Don’t worry—it’s easier than you think. Let’s get started!

    If you’ve never worked with Git before, think of it as a timeline for your files. It’s a tool used to keep track of every change you make, so you can jump backward in time if you break something or experiment freely without losing your original work.

    It’s not just for programmers — writers, researchers, and designers also use Git to track versions of their work. Installing Git on your Mac now will save you a lot of headaches later.

    Although there’s a small learning curve at first, you’ll quickly find that once you’ve used Git for a while, you can’t imagine working without it — you’ll wonder how you ever managed before.

    Check if Git is already installed

    If you’re just setting up your Mac, it’s unlikely that Git is already installed. macOS doesn’t come with a fully functional Git by default. Instead, it includes a placeholder located at /usr/bin/git. This placeholder acts as a link to the actual Git version, which gets installed with Xcode or the Command Line Tools.

    To check, open your terminal and type:

    git --version

    If you see something like:

    No developer tools were found, requesting install

    it means that macOS detected that you tried to use a command-line developer tool – git in this case – but the Xcode Command Line Tools are not installed on your system.

    From here, you have two main choices for installing Git on your Mac — Apple’s Xcode Command Line Tools or the Homebrew package manager. Both will get the job done, but they have different strengths.

    • Xcode Command Line Tools is quick and easy if you just want to start using Git right away, but the version it installs is maintained by Apple and might not always be the latest.
    • Homebrew, on the other hand, gives you more control and makes it simple to update Git whenever a new release comes out. If you plan to keep working with Git regularly, I suggest going with Homebrew for its flexibility and ease of maintenance.

    Install Git on Mac using Xcode

    Xcode is one of the quickest ways to install Git on your system. Since Xcode Command Line tools include Git in the package, to use Git all you need to do is type the following command in your terminal

    xcode-select --install

    When the pop-up appears, click Install. Make sure you’re connected to the internet.

    Once the installation finishes, confirm it by typing:

    git --version

    You should now see something like:

    git version 2.39.5 (Apple Git-154)

    Install Git on Mac using Homebrew

    Another popular way to install Git on macOS, apart from using Xcode Command Line Tools, is by using Homebrew.

    This method is often preferred by developers who want more control over the Git version or are already using Homebrew for managing other software.

    To install Git using Homebrew, run the following command

    brew install git

    Running this command will display some logs related to the Git installation, such as:

    ....
    ==> Installing git
    ==> Pouring git--2.47.1.arm64_sequoia.bottle.tar.gz
    ==> Caveats
    The Tcl/Tk GUIs (e.g. gitk, git-gui) are now in the `git-gui` formula.
    Subversion interoperability (git-svn) is now in the `git-svn` formula.
    
    zsh completions and functions have been installed to:
      /opt/homebrew/share/zsh/site-functions
    ==> Summary
    🍺  /opt/homebrew/Cellar/git/2.47.1: 1,685 files, 54.4MB
    ==> Running `brew cleanup git`...
    ....

    Once the installation process is complete, you can verify that Git was installed successfully by typing:

    git --version

    You should see

    git version 2.39.5 (Apple Git-154)

    With Git successfully installed, you’re now ready to dive into your development journey and take full control of your projects!

    🛠 Extra Tip: When installing via Homebrew, you can easily update Git later by running:

    brew update && brew upgrade git
    Bash

    This ensures you’re always on the latest stable release without waiting for Apple updates. It also makes switching between different Git versions simple, which is useful for testing or specific project needs.

    Verify Git configuration

    After installing Git, it’s a good idea to configure your identity so your commits are linked to the right name and email address. Run the following commands in your terminal:

    git config --global user.name "Your Name"
    git config --global user.email "[email protected]"
    Bash

    You can check your saved settings with:

    git config --list
    Bash

    This will show your username, email, and other configuration details. These can be changed at any time if you switch accounts or need to adjust your settings.

    Next Steps with Git

    Installing Git is just the beginning. The next step is learning a few key commands that will make you productive right away. Start with:

    • git init – Create a new repository in the current folder.
    • git add <filename> – Stage files you want to include in your next commit.
    • git commit -m "message" – Save your staged changes with a short description.
    • git status – Check what’s been modified, staged, or committed.
    • git log – View a history of all commits in the repository.

    Once you’re comfortable with these, try creating a branch with git branch <branchname> and switching to it using git checkout <branchname>. Branching is one of Git’s most powerful features, letting you work on new ideas without touching your main project until you’re ready.

    As you explore these commands, remember that consistent practice is the fastest way to build confidence and skill with Git. And if you want to take things a step further, tools like Husky pre-commit hooks can help automate checks and streamline your workflow as you grow.