Category: Setup & Tools

Quick-start guides, tool introductions, and environment setup tutorials. Whether you’re installing Git, configuring Jest, or learning Homebrew — this is your launchpad.

  • Docker & Docker Compose Commands I Keep Forgetting (Cheat Sheet)

    I recently started building a side project and decided to use Docker Compose to manage my containers. While working on it, I noticed that there are quite a few commands I keep reaching for—and I wanted to have them written down somewhere.

    In my day-to-day (9–5) work, I don’t use Docker extensively beyond the basic up and down commands, so some of the more advanced or less frequent commands tend to get rusty over time.

    While refreshing my Docker and Docker Compose knowledge, I decided to collect all the commands I actually use and put them into one place. Think of this post as a personal cheat sheet—useful for quick debugging, reminders, or getting unstuck when something isn’t behaving as expected. Hopefully, it helps you too. 😊

    Docker Compose Commands

    Docker Compose allows you to define and run multi-container applications using a single configuration file, making local development and orchestration much easier.. These are the commands I use most.

    Starting Services

    These commands are used to start one or more services defined in your docker-compose.yml file, either in the foreground or background.

    Start all services defined in docker-compose.yml:

    docker compose up
    Bash

    Start in background (detached mode) – you get your terminal back:

    docker compose up -d
    Bash

    Start services and force a rebuild of images (useful after changing a Dockerfile or dependencies):

    docker compose up --build
    Bash

    Start specific service only:

    docker compose up -d service-a
    Bash

    or start multiple services at once:

    docker compose up -d service-a service-b
    
    Bash

    Stopping Services

    Use these commands to stop running containers, with options to either keep or completely remove them.

    Stop all services (containers are stopped but not removed):

    docker compose stop
    Bash

    Stop and remove containers (this is what you usually want):

    docker compose down
    Bash

    Stop, remove containers and volumes
    ⚠️ Warning: This deletes persisted data such as databases.

    docker compose down -v
    Bash

    Stop specific service:

    docker compose stop service-a
    Bash

    Restarting Services

    Restarting services is useful after configuration changes or when a container becomes unresponsive.

    Restart all services:

    docker compose restart
    Bash

    Restart specific service:

    docker compose restart service-a
    Bash

    Viewing statuses

    These commands help you quickly check which services are running and their current state.

    List running containers for this project:

    docker compose ps
    Bash

    List all containers (including stopped):

    docker compose ps -a
    Bash

    Docker commands

    In addition to Docker Compose, these core Docker commands are useful for inspecting and interacting with individual containers.

    Executing Commands in Containers

    These commands let you access a running container directly, which is especially helpful for debugging and inspecting the runtime environment.

    Using an interactive shell

    docker exec -it container_name bash
    Bash

    If bash is not available (for example, in Alpine images), use sh instead:

    docker exec -it container_name sh
    Bash

    These commands let you enter a running container with an interactive shell, so you can inspect files, run commands, and debug things directly from inside the container.

    Cleanup commands

    Docker can accumulate unused containers, images, and volumes over time—these commands help keep your system clean.

    Remove stopped containers, images or volumes:

    docker container prune
    
    docker image prune
    
    docker volume prune
    Bash

    or in case you need something more generic

    docker system prune --volumes
    Bash

    which removes all unused resources, including volumes.

    Removing Containers by Name Prefix

    While setting up my project, I found some containers from old projects that i had probably forgotten to cleanup. Instead of removing them one by one, because they were a lot, I tried to find a command that removes all of them, by using their prefix (needless to say they were sharing the same prefix). The following command removed all containers with the prefix si:

    docker rm -f $(docker ps -aq --filter "name=si_")
    Bash

    Viewing Logs

    Logs are often the first place to look when something isn’t working. These commands help you inspect service output, debug errors, and monitor behavior in real time.

    docker compose logs
    docker compose logs -f service-a # -f keeps streaming logs in real time
    docker compose logs --tail=100 # Only the last 100 log lines
    Bash

    So if you wanted to see logs for a specific container, in real time you could use

    docker compose logs -f --tail=100 <container-name>
    Bash

    Copy Files From Container

    docker cp container_name:/path/in/container ./local-path
    Bash

    docker-compose vs docker compose

    You may see Docker Compose used in two different ways:

    • docker-compose
    • docker compose

    They do the same thing, but they’re not the same tool.

    docker-compose (Legacy)

    • Older, standalone CLI
    • Installed separately
    • Common in older projects and tutorials
    docker-compose up -d
    Bash

    docker compose (Recommended)

    • Built into the Docker CLI
    • Installed by default with modern Docker
    • Actively maintained and recommended
    docker compose up -d
    Bash

    Which One Should You Use?

    Existing projects: stick with whatever the project already uses

    New projects: use docker compose

    Quick Reference Card

    This section provides a compact overview of the most commonly used Docker and Docker Compose commands for quick access.

    ╔═══════════════════════════════════════════════════════════════╗
                     DOCKER COMMANDS QUICK REFERENCE               
    ╠═══════════════════════════════════════════════════════════════╣
     COMPOSE                                                       
       docker compose up -d          Start in background           
       docker compose down           Stop and remove               
       docker compose logs -f api    Follow service logs           
       docker compose up --build     Rebuild and start             
       docker compose exec api sh    Shell into service            
    ╠═══════════════════════════════════════════════════════════════╣
     CONTAINERS                                                    
       docker ps                     List running                  
       docker ps -a                  List all                      
       docker stop name              Stop container                
       docker rm -f name             Force remove                  
       docker exec -it name sh       Shell into container          
    ╠═══════════════════════════════════════════════════════════════╣
     IMAGES                                                        
       docker images                 List images                   
       docker rmi name               Remove image                  
       docker build -t name .        Build image                   
       docker pull name:tag          Pull from registry            
    ╠═══════════════════════════════════════════════════════════════╣
     LOGS & DEBUG                                                  
       docker logs -f name           Follow logs                   
       docker logs --tail 100 name   Last 100 lines                
       docker inspect name           Full container info           
       docker stats                  Resource usage                
    ╠═══════════════════════════════════════════════════════════════╣
     CLEANUP                                                       
       docker system prune           Remove unused                 
       docker system prune -a        Remove all unused             
       docker volume prune           Remove unused volumes         
       docker system df              Check disk usage              
    ╚═══════════════════════════════════════════════════════════════╝
    ```
    Bash

    Do you have any Docker or Docker Compose commands that have saved you in tricky situations, or ones you use every day?
    Feel free to share them—we’d love to expand this cheat sheet with more real-world examples.

  • Javascript Testing Tools Explained: What Beginners Really Need To Know

    If you just learned what testing is and you’re still a bit unsure how to start, you’re not alone. Many beginner developers feel overwhelmed by the amount of tools and libraries in the Javascript testing world. You might wonder: do I need Jest? What is Vitest? Why does everyone keep talking about mocking things?

    Let me help you make sense of it all.

    This post builds on the one you (hopefully) already read: Javascript testing for beginners: A simple, practical introduction. If not, it’s a good starting point to understand why testing matters in the first place. Here, we’ll talk about what tools are out there, why they exist, and how to choose the right one for your project.

    Why so many testing tools?

    The short answer is: because testing needs can be very different. Some developers need to test just one small function. Others need to simulate how a user clicks buttons on a real webpage. Some need to test backend logic or APIs. And some want all of that together.

    Different tools are created to solve different testing problems. Let’s look at the main ones you’ll hear about.

    What is a testing framework?

    Before going further, let’s clear something up. When people say “testing framework” or “testing library,” they sometimes mix up terms. In this post, we’ll use them loosely. Don’t worry too much about definitions.

    But just so we’re on the same page:

    • A testing framework usually provides the structure: how to describe a test, run it, and report results.
    • A testing library might focus on one specific part of the testing process (like simulating user actions or helping with mocking).

    Now let’s see what each popular tool actually does.

    Jest: The default for many projects

    Jest is probably the first tool you’ll hear about in Javascript testing. It’s widely used, especially in React projects. And for good reason—it comes with most things you need built in: test runner, assertion library, and mocking tools.

    • You can write simple tests using test() and expect().
    • You can mock functions easily (see what a mock is if you’re unsure).
    • It works out of the box with many setups.

    A basic test in Jest looks like this:

    import { sum } from './math';
    
    test('adds two numbers', () => {
      expect(sum(2, 3)).toBe(5);
    });
    JavaScript

    Jest is great for unit tests, which are explained more deeply in Integration and unit tests: How to choose the right one?. But it also supports more advanced setups.

    Still, Jest isn’t perfect for every case.

    Vitest: Fast and Vite-Friendly

    If you’re using Vite, you might prefer Vitest. It’s a newer test runner that works very similarly to Jest but is built for speed and modern dev setups.

    It supports:

    • ES modules by default
    • Fast startup thanks to Vite integration
    • Very similar API to Jest, so switching isn’t too hard

    If you’re just starting and you already use Vite for your project, Vitest is a great alternative. It feels lighter and quicker, especially for frontend apps.

    Testing Library (RTL): For testing UI like a real user

    React Testing Library (often called RTL) is a library for testing user interfaces. It doesn’t replace Jest—it works with Jest.

    RTL helps you simulate how users actually interact with your app:

    • Clicking buttons
    • Typing in inputs
    • Checking if the right text shows up

    Instead of testing if a certain component method was called, you test what the user sees. This makes your tests more realistic.

    It follows a rule: “The more your tests resemble the way your software is used, the more confidence they can give you.”

    Mocha, Chai, Sinon: The Classic Trio

    Before Jest became popular, many Javascript projects used this combo:

    • Mocha for running tests
    • Chai for writing assertions
    • Sinon for creating mocks and spies

    These tools are still good and used in some backend or legacy projects. They give you more flexibility, but also more setup.

    For example, to run tests with Mocha and Chai, you’ll usually need to install them separately and configure them more manually.

    If you’re just starting, you don’t need to go this route unless you’re joining a project that already uses them.

    What about Mocks, Spies, and Stubs?

    You’ll hear these words a lot when testing. Here’s what they mean in simple terms:

    • A mock is a fake function that replaces a real one during testing. It lets you test what happens without calling the real thing.
    • A spy is a function that records if and how it was called, but still lets the real function run.
    • A stub is like a mock but with more control—you can decide what it returns.

    If you’re confused, check the glossary entries for mock and spy.

    These tools are helpful in unit testing, when you want to isolate just one part of your code. For example, you might want to check that a function called another one, but without actually doing what the second one does.

    What should you use as a beginner?

    Here’s a simple suggestion:

    • Start with Jest. It’s well-documented, easy to set up, and covers most use cases.
    • If you’re using Vite, try Vitest instead.
    • If you’re building user interfaces, add Testing Library to test what the user sees.

    You don’t need everything at once. Focus on learning how to write a few tests. You’ll naturally learn the tools better as you write more code.

    A quick example: Putting it together

    Let’s say you have a small function like this:

    export function greetUser(name) {
      return `Hello, ${name}!`;
    }
    JavaScript

    A simple unit test using Vitest would be:

    import { describe, it, expect } from 'vitest';
    import { greetUser } from './greet';
    
    describe('greetUser', () => {
      it('greets by name', () => {
        expect(greetUser('Anna')).toBe('Hello, Anna!');
      });
    });
    JavaScript

    You could use Jest instead—the code would almost be the same. This test checks the return value, no mocking needed.

    Later, if your function becomes more complex (calls an API, uses another function), you might use a mock to isolate the behavior. You can then write more detailed tests, like we discuss in Integration and unit tests: How to choose the right one?.

    Final thoughts

    Don’t feel like you need to master every testing tool at once. Testing is a skill you build slowly. Start small, use a simple tool like Jest or Vitest, and practice writing real tests.

    If you’re ever stuck on what kind of test to write, go back to Javascript testing for beginners and Integration and unit tests: How to choose the right one? to refresh the theory.

    The tools are just tools—they’re here to help you write better, safer code. And soon, you’ll start to feel that they do.  🥳

  • Javascript Testing for Beginners: A Simple, Practical Introduction

    Learning Javascript often feels clear at the beginning. You write some code, refresh the browser, and see something working on the screen. That feedback is immediate and encouraging. But as soon as your code grows beyond a few files or functions, things start to feel less predictable.

    You change a small piece of logic, and something unrelated breaks. You fix that, and another issue appears somewhere else. At that point, many beginners feel stuck. They know something is wrong, but they don’t have a reliable way to understand what changed or why.

    This is where testing becomes useful.

    Javascript testing is not about writing perfect code or preventing every bug. Especially for beginners, testing is about building confidence and clarity. It gives you a way to check that your code behaves the way you think it does, and it gives you fast feedback when that behavior changes.

    This guide introduces Javascript testing in a practical, beginner-friendly way. It focuses on understanding the ideas first, without pushing tools or complexity before they make sense.

    What is Javascript testing?

    Javascript testing is the practice of writing code that checks other code.

    A test runs part of your Javascript program and verifies that the result matches what you expect. If the result is correct, the test passes. If it’s not, the test fails and shows you that something is wrong.

    Most tests are built around veassery simple expectations. You might expect a function to return a specific value, handle invalid input gracefully, or behave consistently when called multiple times. Testing gives you a repeatable way to verify those expectations instead of relying on manual checks.

    Testing is part of a broader idea known as software testing, which exists across all programming languages. Javascript testing applies the same principles to Javascript code, whether it runs in the browser, on a server, or inside a larger application.

    The key benefit of testing is not automation alone. It’s trust. When you have tests, you don’t have to wonder whether something still works. You can check.

    Why Javascript testing matters for beginners

    Many beginners believe testing is something you add later, once you are “good enough” at Javascript. In reality, testing is often most helpful when you are still learning.

    When you write tests, you are forced to be precise about what your code should do. That process often exposes misunderstandings early. A test might fail not because your code is broken, but because your assumption about how something works was incorrect.

    Without tests, debugging tends to rely on trial and error. You log values, refresh the page, and hope you notice what went wrong. With tests, failures give you direct signals. They tell you that something changed and help narrow down where the problem lives.

    Testing also makes change safer. Beginners often avoid refactoring because they’re afraid of breaking something they already fixed. Tests reduce that fear by giving you quick feedback when behavior changes.

    How Javascript testing works at a basic level

    At a basic level, Javascript testing follows a simple pattern.

    You provide some input, run the code you want to test, and then check the result. That final check is done using something called an assertion. An assertion compares what actually happened with what you expected to happen and decides whether the test should pass or fail.

    To make this more concrete, here’s a very small example using Jest.

    Imagine you have a simple function that adds two numbers:

    export const add = (a, b) => {
      return a + b;
    };
    JavaScript

    Now you want to test that this function works as expected. A basic Jest test might look like this:

    import { add } from './add';
    
    test('adds two numbers correctly', () => {
      expect(add(2, 3)).toBe(5);
    });
    JavaScript

    In this example:

    • test defines a test case
    • add(2, 3) runs the code being tested
    • expect(add(2, 3)).toBe(5) is the assertion

    The assertion checks whether the actual result matches the expected result. If add(2, 3) returns 5, the test passes. If it returns anything else, the test fails.

    You don’t need to understand every detail of the syntax right away. What matters is the idea: tests describe expected behavior and automatically verify it.

    Types of Javascript testing you should be aware of

    Javascript testing includes different approaches, but beginners don’t need to use all of them immediately.

    The most common starting point is unit testing. Unit tests focus on small, isolated pieces of code, usually individual functions. They are fast to run, easy to understand, and easier to debug when something goes wrong.

    Other testing types exist, such as integration testing and end-to-end testing. These focus on how different parts of an application work together or how the entire application behaves from a user’s perspective.

    One common question beginners ask is whether to focus on unit tests or integration tests first, and how to choose between them.

    As a beginner, it’s enough to understand that these testing types exist and serve different purposes. You can explore them gradually as your projects grow in size and complexity.

    Javascript testing tools and why they exist

    To run tests, you need a testing tool. A Javascript testing tool provides a way to execute your tests, make assertions, and show clear feedback when something fails.

    At a basic level, testing tools take care of the repetitive work. They find your test files, run them, and report which tests passed or failed. This lets you focus on writing and understanding tests instead of building your own testing system from scratch.

    Different tools exist because they solve slightly different problems.

    Some tools, like Jest and Vitest, are all-in-one solutions. They include a test runner, an assertion system, and helpful features like watching for file changes. These tools are often a good starting point for beginners because everything works together out of the box.

    Other tools focus on specific parts of the testing process. For example, Chai is an assertion library that helps you express expectations clearly, while Sinon is commonly used for creating mocks and spies when you need more control over how code behaves during tests.

    In frontend-focused projects, especially those using frameworks like React, you may also encounter React Testing Library (RTL). Its goal is to help you test components in a way that reflects how real users interact with them, rather than testing internal implementation details.

    It’s important to understand that you don’t need all of these tools at once. Many beginners start with a single, integrated tool and add others only when a specific need appears. The concepts behind testing matter far more than the number of libraries you use.

    Testing tools exist to support learning and confidence. They should make testing feel easier, not heavier.

    Not sure what tool to start with? I broke down the main ones like Jest and Vitest in a separate post: Javascript Testing Tools Explained, so you can pick without the overwhelm.

    How testing changes the way you write Javascript

    Over time, testing influences how you approach writing code.

    When you write tests, you naturally start thinking in terms of inputs and outputs. You tend to write smaller, clearer functions because they are easier to test. This leads to code that is easier to read, reason about, and maintain.

    Tests also act as a form of documentation. They show how your code is expected to behave in real situations, which is helpful when you return to a project later or share it with others.

    Some developers take this further by writing tests before writing code, a practice often called test-driven development. You don’t need to follow this approach strictly, but understanding it helps put testing into a professional context.

    Common beginner worries about testing

    It’s normal to feel unsure when starting with testing. Many beginners worry about writing tests the wrong way or not testing enough.

    The truth is that imperfect tests are still useful. Testing is a skill that improves with repetition. Early tests may feel awkward, but they still provide feedback and build understanding.

    Avoiding testing because it feels unfamiliar only delays that learning. Progress matters more than getting everything right.

    Final thoughts

    You don’t need a large project to begin testing. One function is enough.

    Write a test. Let it fail. Fix the code. Run the test again and see it pass. That small loop is where learning happens.

    As you gain experience, you can add more tests, improve structure, and adopt better practices. But the foundation remains the same: define expected behavior and verify it automatically.

    Javascript testing is not about rigid rules or unnecessary complexity. It’s about clarity, confidence, and understanding how your code behaves over time.

    For beginners, testing provides structure in a learning process that can otherwise feel chaotic. It helps you move from guessing to knowing, and from hesitation to confidence.

    This post is meant to be a foundation. You don’t need to master everything at once. Testing will grow with you, quietly supporting your progress as your skills develop.

  • How to Install Java on Mac: Step-by-Step Guide

    How to Install Java on Mac: Step-by-Step Guide

    If you’ve ever tried running a Java program on a Mac without setting anything up, you’ve probably seen an error about a missing Java Runtime. That’s because, unlike JavaScript, Java doesn’t come built into your computer — you need to install a Java Development Kit (JDK) first.

    In this guide, we’ll go step by step:

    • Check if Java is already installed (so you don’t install it twice by mistake)
    • Learn what a JDK kit is and why most developers use it
    • Install Java on a Mac using either Homebrew or the official Oracle download
    • Set up your environment so the java command works anywhere in your terminal
    • Verify the installation, uninstall if needed, and fix common issues

    Whether you’re new to Java or just coming from another language like JavaScript, this guide will give you a clear path to getting Java up and running on macOS.

    Check if Java is Already Installed

    Before installing Java, it’s worth checking if it’s already on your Mac. Maybe you’re not on your personal machine, or you installed it months ago for a side project and completely forgot.

    To check if Java is already installed:

    1. Open your Terminal
    2. Type java -version
    3. If Java is installed, you’ll see something like:
    OpenJDK version 11.x
    Bash

    If it’s not installed, you’ll get a message like:

    The operation couldn’t be completed. Unable to locate a Java Runtime.
    Please visit http://www.java.com for information on installing Java.
    Bash

    If you see the “Unable to locate” message, don’t worry — just continue with this guide to install Java on your Mac.

    What is a JDK?

    If this is your first programming language, or if you’re like me, coming from another one — in my case, Javascript — you might not know much about the Java ecosystem. And honestly, you don’t really need to at first, right?

    Still, because of assumptions, you might expect the installation to be as simple as running brew install java. But when you look it up, you’ll quickly see that the recommended way is to install a JDK instead. Before we continue, let’s take a quick look at what that actually is.

    JDKJava Development Kit is an open-source implementation of Java, maintained by big tech companies such as Oracle, Red Hat, and others.

    When we refer to an open-source implementation, it simply means software built according to official rules. In this case, the rules come from the Java SE Specification.

    So what does the JDK provide? It contains:

    • Compiler – turns your .java files into an executable form called bytecode.
    • Runtime (JVM) – executes that bytecode on any computer (Windows, Mac, Linux, etc.).
    • Standard library – a huge set of built-in tools to help you out with your code.

    It essentially has everything you need to use Java on your machine. The JDK is considered an essential tool for developers working with Java, and the OpenJDK project and Oracle distribute it.

    Install Java on Mac

    You can install Java on macOS in two main ways:

    1. Install Using Homebrew – quick and beginner-friendly
    2. Install by Downloading from Oracle

    If you’re new to Java or simply want the fastest setup, the Homebrew method is the best choice. (We have a separate post that walks you through installing Homebrew if you don’t have it yet.)

    In this guide, we’ll use the Homebrew method.

    To find out which is the latest version of Java, you can visit this page.

    Install Java using Homebrew

    To install Java using Homebrew:

    1. Update Homebrew
      Open your terminal and run: brew update
      This makes sure you’re working with the latest package list.
    2. Install OpenJDK 21
      After updating, run:
      brew install openjdk@21
    3. Verify installation
      Open your terminal and run:
    java -version
    Bash

    At the time of writing this guide, version 21 is the latest long-term support (LTS) release. If you want to install a different version, just replace 21 with the version number you need (for example, openjdk@17).

    Optional: Read More About the Package
    You can check out the official Homebrew formula page for OpenJDK here.

    Set JAVA_HOME Environment Variable

    After installing OpenJDK, you could have tried to verify the installation and found out that you still get

    The operation couldn’t be completed. Unable to locate a Java Runtime.
    Please visit http://www.java.com for information on installing Java.
    Bash

    In that case, you will need to add the Java home directory to your PATH. Since we installed OpenJDK@21, the command to add this to our PATH is

    echo 'export PATH="/opt/homebrew/opt/openjdk@21/bin:$PATH"' >> ~/.zshrc
    Bash

    You’ll also see this message in the Homebrew installation logs for OpenJDK, near the end of the process.

    What this command essentially does is prepend the existing list of paths with the directory where OpenJDK is installed. So when you ask it to run a java program, it will search first there.

    If you installed a different version, change the version accordingly to the command above.

    Verify Installation

    To verify our installation regardless of the method we used we should type java --version. By now you should be seeing

      ~ java -version
    openjdk version "21.0.8" 2025-07-15
    OpenJDK Runtime Environment Homebrew (build 21.0.8)
    OpenJDK 64-Bit Server VM Homebrew (build 21.0.8, mixed mode, sharing)
    Bash

    Uninstalling Java (Homebrew)

    If you want to remove a specific version of OpenJDK installed via Homebrew, run:

    brew uninstall openjdk@21
    Bash

    Checking Installed Versions

    To see all the Java versions (and other packages) you currently have installed, run:

    brew list --versions
    Bash

    You might see something like this:

    ...
    openjdk@17 17.0.12
    openjdk@21 21.0.4
    ...
    Bash

    This means you have both Java 17 and Java 21 installed on your system.

    Choosing an IDE for Java

    Now that you’ve installed Java, the next step is picking an Integrated Development Environment (IDE) to support your learning. An IDE helps you compile code, catch mistakes, and debug programs more easily — making your path to mastering Java smoother.

    Some popular free choices include:

    • IntelliJ IDEA Community Edition, published by JetBrains. This is my personal recommendation, since it’s beginner-friendly and offers a free edition.
    • Eclipse, maintained by the Eclipse Foundation
    • NetBeans, maintained by the Apache Foundation

    Pick one of these tools, set it up, and you’ll be ready to start coding your very first Java programs with confidence!

    Troubleshooting Common Issues

    Below are some common issues you might face when installing or using Java on macOS.
    If you’re dealing with a different problem and haven’t figured out the solution, drop it in the comments — we’ll try to help you out.
    Also, if you’ve solved a tricky Java issue yourself, share it in the comments so other readers can benefit too.

    Wrong Java Version Running

    Cause: Multiple Java versions are installed, and the wrong one is first in your PATH.
    Fix: Check which Java is being used

    which java
    Bash

    Then adjust your PATH so the version you want comes first. You can do that by typing:

    export PATH="/opt/homebrew/opt/openjdk@<version-you-want>/bin:$PATH"
    Bash

    brew install fails

    Cause: Homebrew may be outdated or missing.

    Fix: Update Homebrew:

    brew update
    Bash

    If Homebrew is not installed, see our homebrew installation guide.

    java Command Not Found

    Cause: OpenJDK is installed but not linked to your environment.

    Fix: Link the installed version so the java command is available:

    brew link --force --overwrite openjdk@21
    Bash

    If you installed a different version, replace 21 with that version number.

  • MacOS Shortcuts – Cheatsheet for New Users

    MacOS Shortcuts – Cheatsheet for New Users

    If you’re a new Mac user (like me!), knowing a few common shortcuts can save you tons of time. Here’s a simple cheatsheet of macOS shortcuts — including some of the ones I’ve searched for myself.
    You might want to bookmark this — I’ll keep adding more as I come across new and useful shortcuts.

    🔄 Basic Editing MacOS Shortcuts

    👨‍💻 Developer – Focused macOS Shortcuts

    💻 Productivity MacOS Shortcuts

    🔤 Other Useful Shortcuts

    Since I’m still fairly new to macOS after switching from Ubuntu Linux, I’ve been collecting these shortcuts to help myself — and hopefully to help you too.

    You might also find other posts where I share not just shortcuts, but tips for developers and guides on installing tools or setting things up on macOS. These aren’t just for Mac beginners — they’re for anyone adjusting to new workflows. Feel free to check them out here.

  • 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! 💬👇

  • How to Do the Copyright Symbol on Mac

    How to Do the Copyright Symbol on Mac

    If you’re wondering how to type the copyright symbol on a Mac, the solution is quick and easy. Mac keyboards come with built-in shortcuts for special characters, including the copyright symbol.

    Why use the copyright symbol?

    The copyright symbol © shows that your work is protected by copyright law. You can put it in blog posts, documents, or any other type of creative work. It shows people that your work belongs to you.

    Some people also add the year and their name next to it, for example:

    © 2025 John Doe

    This makes it even clearer who owns the content and when it was created. However, the symbol by itself may not be enough to fully protect your rights in all situations — it’s best to include clear terms and conditions for your website or publications, and seek professional legal advice if you need comprehensive protection.

    Typing the Copyright Symbol on macOS

    To type the © symbol on a Mac, simply press:

    Option (⌥) + G

    That’s all you need to do! This shortcut works across most apps on macOS — whether you’re writing in Pages, Word, Google Docs, or even in your browser.

    If you are new to Mac and do not know the Option key: it is next to the Command (⌘) key. On most keyboards, there is one Option key on the left side and one on the right side.

    If the shortcut mentioned above doesn’t work, you can use the Character Viewer:

    • Press Control + Command + Space
    • Search for “copyright”
    • Double-click the symbol to insert it.

    Related Tips: Typing Other Special Symbols on Mac

    Mac has shortcut for many symbols. There are some you might also like:

    • Trademark (™) – Press Option (⌥) + 2
    • Registered Trademark (®) — Press Option (⌥) + R
    • Degree (°) — Press Shift + Option (⌥) + 8
    • Ellipsis (…) — Press Option (⌥) + ;
    • Section (§) — Press Option (⌥) + 6

    These shortcuts work almost everywhere on macOS. If you forget them, you can either open the Character Viewer and search for the symbol you want or bookmark this post.

    Extra tips for Mac beginners

    When I first switched from Ubuntu Linux to macOS, I felt a bit lost. Many things were different. On Linux, I used different key combinations for special characters, and sometimes I had to copy and paste them. On Mac, once I learned the shortcuts, my work became faster. You might be in the same situation — maybe not from Ubuntu, but perhaps you are coming from Windows? Or maybe you are just a newcomer to the computer world.

    Regardless, these simple, everyday shortcuts might also help you:

    • Command + C to copy
    • Command + V to paste
    • Command + Z to undo
    • Command + Shift + 4 to take a screenshot of a selected area

    I’m a new Mac user and have been having questions about shortcuts, processes, and other little details in macOS since I switched from Ubuntu Linux. I started adding these posts to help me remember — and hopefully, they’ll help you too.

    Since moving to macOS, I’ve been collecting tips and shortcuts to make my daily work easier. I share them here so they’re easy to find — and maybe they’ll help you too.

  • How to Close a Full Screen on Mac

    How to Close a Full Screen on Mac

    If you’re new to Mac, like I am, you might be wondering: How do I close full screen on Mac? Don’t worry, it’s very simple once you know how!

    Here are three quick and easy methods you can use to exit full-screen mode on your Mac:

    A. Use the Green Button

    Move your mouse to the top of the screen until you see the menu bar and the three window buttons (red, yellow, green) appear in the top-left corner of the window.

    Click the green button to exit full screen and return to normal window size. You can also click it again if you want to go back into full screen.

    How to Close Full Screen on Mac: Green icon on top left is for expanding/minimizing windows on mac.
    The green icon is used to expand or minimize windows on a Mac.

    Tip: In macOS, the green button is not just for full screen — it’s also used to resize or tile windows. If you hold down the Option key while clicking, you can maximize the window without entering full screen.

    B. Press and Hold Esc

    In some apps, you can simply press and hold the Esc key to exit full screen. This works in many media apps, like QuickTime or YouTube, when viewed in Safari.

    While this doesn’t work in every app, it’s worth trying. Often, when you move your mouse to the top of the screen, you might see a small message saying: “To exit full screen, press and hold Esc.”

    Hold Esc for about 3 seconds, and you should see the app switch back to windowed mode.

    C. Keyboard Shortcut

    For a faster method, press Control + Command + F. This shortcut works in most Mac apps and will toggle between full screen and windowed mode instantly.

    Tip: If you’re using a MacBook with the Touch Bar, you might see a dedicated “Exit Full Screen” button appear when you’re in full screen. Tapping it is the same as using the keyboard shortcut.

    When Full Screen Won’t Exit

    There could be a case that your app may not respond to the methods mentioned above. In this case, try pressing Command + Tab to switch to another app, then close the full-screen one from the Dock.

    You can also right-click the app icon in the Dock and select Options > Exit Full Screen if available.

    If nothing works, press Command + Option + Esc to force quit the app, then reopen it in normal mode. This is rare, but it’s good to know if a program freezes while in full screen.

    Looking for more beginner-friendly Mac tips? Check out our other quick guides for macOS beginners.

  • How to Install Postgres on MacOS

    How to Install Postgres on MacOS

    If you’re working on a Node.js project and run into errors like ECONNREFUSED ::1:5432, chances are PostgreSQL isn’t running — or it isn’t even installed. Here’s a quick guide to install postgres on macOS using Homebrew, the most reliable and straightforward method.

    Before installing PostgreSQL, make sure you already have Homebrew installed on your Mac. Homebrew is the package manager we’ll be using to install and manage PostgreSQL.

    Don’t have Homebrew yet? No worries, we got you covered. Check out our guide: How to Install Homebrew on macOS.

    Once you’ve got Homebrew set up, you’re ready to continue.

    Step 1: Install PostgreSQL via Homebrew

    With Homebrew installed, adding PostgreSQL is easy:

    brew install postgresql
    Bash

    If you want to install a specific version of postgres, e.g, version 17 type:

    brew install postgresql@17       
    Bash

    Step 2: Start the PostgreSQL Service

    Once installed, start PostgreSQL as a background service:

    brew services start postgresql
    Bash

    To confirm it’s running:

    brew services list
    Bash

    You should see something like:

    Name        Status   User       File
    postgresql  started  your-name  Library/LaunchAgents/[email protected]
    Bash

    Step 4: Confirm the Installation

    Check that PostgreSQL is installed correctly:

    psql --version
    Bash

    psql is the interactive command-line tool when working with Postgres

    Expected output:

    psql (PostgreSQL) 17.5 (Homebrew)
    Bash

    In case you are getting a command not found: psql error you have to explicitly link it. For my example, in which i installed version 17, I just had to type

    brew link postgresql@17 --force
    Bash

    By typing psql --version you should now see the postgreSQL you just installed.


    Step 5: Connect to PostgreSQL

    You can now open a PostgreSQL shell:

    psql postgres
    Bash

    Or create your own database:

    createdb mydb
    psql mydb
    Bash

    Step 6 (Optional): Choosing a GUI

    If you prefer a graphical interface over the terminal, consider installing

    These tools make managing your databases even easier.

  • 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 Restart Your Node App Without Nodemon

    If you’ve built anything with Node.js, you’ve probably used nodemon to automatically restart your app when files change. It’s been a go-to developer tool for years — but did you know you no longer need it?

    With Node.js 18.11 and above, there’s a built-in --watch option. It tells Node to monitor your source files and automatically restart the process when changes are detected.

    node --watch app.js
    Bash

    That’s it. No configuration, no dependencies, no waiting for external tools to kick in.

    It works great when:

    • You’re building small or medium apps.
    • You don’t need advanced features like custom delay or file filters.
    • You want to keep your environment minimal and lean.

    Keep in mind that, large projects with complex file structures might still benefit from nodemon or more advanced tools.

  • 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.


  • How to install Homebrew – MacOS for beginners

    How to install Homebrew – MacOS for beginners

    If you are making your first steps on macOS, you may have never heard of Homebrew before. Homebrew is a powerful package manager, similar to npm if you’ve worked with it before. It allows you to easily install, update, and remove software packages directly from your terminal, making it an incredibly handy tool for developers. In this post, you’ll find a step-by-step guide to install Homebrew on MacOS.

    Why is it essential to install Homebrew?

    Homebrew is widely regarded as the most popular package manager for macOS. It’s the go-to choice for developers and power users because of its simplicity and active community support.

    Homebrew lets you easily get the tools and libraries you need for development or daily tasks, from developer tools like Git and Node.js to simple everyday utilities. It saves time by skipping the trouble of manual downloads and setup. It’s simple, fast, and perfect for customizing your Mac.

    If you haven’t used a tool like Homebrew before, don’t overlook it – it could completely transform the way you manage software on your Mac.

    Check if Homebrew is already installed

    Just to make sure you haven’t already installed Homebrew in the past, let’s check it out. Open your terminal and type:

    brew help

    If you have it installed, you should see something like

    Example usage:
      brew search TEXT|/REGEX/
      brew info [FORMULA|CASK...]
      brew install FORMULA|CASK...
      brew update
      brew upgrade [FORMULA|CASK...
      ....

    otherwise, you will get the following result

    command not found: brew

    How to install Homebrew

    Ready to install Homebrew? Here’s everything you need to know. Open your terminal (Cmd + Space and type Terminal“) and type

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 
    

    Oh, you say! What is this command? Let me explain. This command asks bash (which is a command-line shell language commonly used in macOS and Linux) to execute a script.

    Here’s how it works:

    • /bin/bash: specifies the bash shell, ensuring the command is executed using bash, even if your default shell is something else (like zsh).
    • -c: This flag tells bash to execute the command provided in quotes.
    • $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh): This part fetches the Homebrew installation script directly from GitHub using curl (a tool for transferring data).

    In simple terms, this command downloads the Homebrew installer script from GitHub and immediately runs it using bash to set up Homebrew on your system.

    You will be asked for your super user password:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
    Checking for `sudo` access (which may request your password)...
    
    Password:
    

    After typing your password, you’ll see a message prompting you to press ENTER to proceed with the installation. Simply press ENTER, and the installation will continue.

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
    Checking for `sudo` access (which may request your password)...
    
    Password:
    
    ==> This script will install:
    /opt/homebrew/bin/brew
    /opt/homebrew/share/doc/homebrew
    ....
    /opt/homebrew
    ==> The following new directories will be created:
    /opt/homebrew/bin
    /opt/homebrew/etc
    /opt/homebrew/include
    ....
    /opt/homebrew/Frameworks
    
    Press RETURN/ENTER to continue or any other key to abort:

    Wait for the installation process to complete—it may take a few minutes. Once it’s done, you’ll see the message “Installation successful!”. However, to ensure everything was installed correctly, let’s verify it by typing the following command in the terminal:

    brew help

    If it was successfully installed, you should see the following response.

    Example usage:
      brew search TEXT|/REGEX/
      brew info [FORMULA|CASK...]
      brew install FORMULA|CASK...
      ....

    Homebrew doesn’t work after installing it

    If you’ve already followed all the steps described to install Homebrew but see a “command not found” error when running, e.g., brew help it typically means that the Homebrew binary is not properly added to your system’s PATH.

    To resolve the issue, revisit the logs from the Homebrew installation script. At the end of the script, you’ll typically find specific instructions for finalizing the installation.

    Warning: /opt/homebrew/bin is not in your PATH.
      Instructions on how to configure your shell for Homebrew
      can be found in the 'Next steps' section below.
    ==> Installation successful!
    ...
    ...
    ...
    ==> Next steps:
    - Run these commands in your terminal to add Homebrew to your PATH:
        echo >> /Users/<your username>/.zprofile
        echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/<your username>/.zprofile
        eval "$(/opt/homebrew/bin/brew shellenv)"

    copy the last part of the Homebrew installation instructions —starting from the command that begins with echo — and paste it into your terminal. This command typically adds Homebrew to your system’s PATH.

    By now, you should have Homebrew installed on your system successfully. Congratulations! This is just the first small step on your exciting journey to mastering powerful tools and workflows as you grow your skills.If you’re exploring ways to automate parts of your development workflow next, you might find Git tools like Husky pre-commit hooks especially helpful.

  • How to Add Sass to A Create-React-App Project

    How to Add Sass to A Create-React-App Project

    In this post, we’ll be sharing all the steps you need to follow to learn how to add Sass to a Create-React-App project. We’ll take it step by step and make it crystal clear for you! Let’s do it!

    Setup a Create-React-App project

    To build your initial project structure, you have two options, either install create-react-app (CRA) package globally and use that, or use npx and avoid installing create-react-app in your system.

    To check if you already have CRA installed, type in your terminal:

    create-react-app --version
    Bash

    If you see a version logged, something like 5.0.1 then you are just fine and can start the project initialization process. Otherwise, you need to decide whether to proceed by installing CRA or not. Both decisions are valid and it depends on your coding style and whether you like to keep global packages or not.

    Installing Create-React-App

    If you want to install create-react-app in your terminal type:

    npm install create-react-app --global
    Bash

    After installing the package, check its version to verify the installation by typing create-react-app --version.

    Now that you have installed CRA, you can create your project by typing

    create-react-app my-project
    Bash

    Using npx – Avoid installing Create-React-App

    If you want to avoid installing create-react-app and just use npx, you can just type

    npx create-react-app my-project
    Bash

    Basic difference between npx and npm is that npm is a package manager and npx is a package executor.

    Using npx doesn’t install the package you want permanently but rather temporarily so that it gets the job done. That’s why if you check the version of the package used after using npx, you will get nothing back, compared to the classic installation with npm in which you’ll get the installed package’s version. Try it out!

    You may ask how npx was added to my system. Since npm version 5.2.0, npx is pre-bundled with npm.

    Add Sass to Create-React-App

    Now that we have our project’s basic structure, let’s start adding some Sass code. Our first step is installing Sass:

    npm install sass
    Bash

    Now that we have the Sass package installed, the next step would be to rename our App.css file to App.scss and add some Sass styling there like so:

    body {
      background-color: red;
    }
    Sass

    Now I know what you are thinking, and yes, this is not solid styling for our app; it’s just to verify our changes are applied as expected. One final step before verifying everything works. We have renamed our App.css to App.scss so we will be getting an error if we run our app because the importing in the App.js file is using the previous extension import './App.css';.

    Let’s change that too by making it import './App.scss';

    Now, check out your browser, and you should see the applied changes! Keep in mind, though, that based on your already applied stylings, you may not actually see our styles on the browser because they will probably get overridden by yours. You can still see if everything worked as expected and if our style was “passed” to the browser either by checking your browser’s dev tools or by increasing your style’s specificity.

    Sass VS SCSS – What’s the difference?

    For those of you who are paying extra attention, you may have already seen that we have installed a Sass package to handle new code styling, but we have used .scss file extension. What’s with that?

    Well, first of all, sass package encompasses both the Sass and SCSS syntax, so we are fine with that regardless of the style we want to use, Sass or SCSS.

    The difference between Sass and SCSS is basically their syntax. Sass is more concise and doesn’t use curly braces, whereas SCSS (Sassy CSS) has a more CSS-like syntax.

    Both serve the same purpose of allowing maintainability and efficient CSS usage, however .scss extension is more popular in the Sass community, and that’s why we have chosen in this post to use the .scss file extension.

    Remove Create-React-App

    If, after finishing your project, you’d like to remove CRA from your system, you can just type

    npm uninstall --global create-react-app
    Bash

    Remember, if you have used npx for your project’s initialization, nothing was installed, so you’ll be just fine, no reason for uninstalling anything.

  • How to Install npm on MacOS

    How to Install npm on MacOS

    Installing Node.js and npm (Node Package Manager) on your Mac is super simple. With these tools, you can manage Javascript packages, create powerful web applications, and dive deep into modern web development. Start by following these steps:

    Step 1: Verify that npm is installed

    Open your terminal and type

    node -v
    npm -v
    Bash
    • If you see version numbers (e.g., v16.13.0 for Node.js and 8.1.0 for npm), they’re already installed.
    • If you see errors or no versions, continue to the next step.

    Step 2: Install Node.js (includes npm)

    The easiest way to install Node.js and npm is by using Homebrew. If you don’t have Homebrew installed, install it first.

    Then run:

    brew install node
    Bash

    Step 3: Verify the Installation

    After the installation completes, type the following command to check the versions and ensure everything is installed properly:

    node -v
    npm -v
    Bash

    You should see version numbers for both. 🎉

    Step 4: Update npm (Optional)

    npm updates frequently, so ensure you have the latest version:

    npm install -g npm@latest
    Bash

    🎉 You’re all set! Now, you can use Node.js and npm to manage and build amazing projects. Happy coding! 😊

    Why Use Node.js and npm?

    • Fast & Scalable: Node.js enables fast, scalable network applications with non-blocking I/O.
    • Massive Ecosystem: npm offers access to over 1 million open-source packages.
    • Cross-Platform: Develop once and deploy anywhere.

    These tools are essential for any web developer aiming to build modern, high-performance applications.