The fastest way to rewrite Git history

Ever pushed commits and then realized you messed up?

  • Wrong Git user/email.
  • Bad commit messages.
  • Accidentally committed secrets (API keys, passwords).
  • A huge file is bloating the repo.
  • ...and more.

Many developers try git rebase -i, but it’s slow, manual, and limited. A better way?

Use git-filter-repo, it’s faster, more powerful, and works across the entire repo.

Examples of Git problems and fixes

  • Fix author name/email in all commits

    git filter-repo --commit-callback '
      commit.author_name = "Correct Name"
      commit.author_email = "[email protected]"
    '
    
  • Edit commit messages in bulk

    git filter-repo --message-callback '
      commit.message = commit.message.replace(b"fix typo", b"Fix: corrected typo")
    '
    
  • Remove sensitive files from history

    git filter-repo --path secret-file.env --invert-paths
    
  • Delete large files from old commits

    git filter-repo --strip-blobs-bigger-than 100M
    
  • Erase all commits from a specific author

    git filter-repo --commit-callback '
      if commit.author_email == b"[email protected]":
          commit.skip()
    '
    

For more use cases, check out the full docs.

→ 2025/02/06 12:00 AM

You don’t need Husky

Do you use husky to manage Git commit hooks? Husky is a popular tool (50M+ downloads per month!), but did you know that Git already has built-in support for hooks?

With Githooks, you don’t need to install extra dependencies. Git provides 28 different hooks that allow you to automate git hooks tasks.

How to use?

  • Create a .git/hooks or .githooks directory (just like you’d configure .husky)

  • Configure Git to use your hooks scripts

    Tell Git to use this folder for hooks by adding the following postinstall script in your package.json. This ensures that Git hooks are always active after running npm install (or yarn, pnpm, bun).

    "scripts": {
      "postinstall": "git config core.hooksPath ./.githooks || true"
    }
    
  • Hook scripts Inside the .githooks folder, create scripts named according to the Git Hooks documentation (e.g., pre-commit, prepare-commit-msg).

    Example:

    # .githooks/pre-commit
    #!/bin/bash
    npm run lint
    
    # .githooks/prepare-commit-msg
    #!/bin/bash
    npx --no-install commitlint --edit "$1"
    
    # .githooks/post-commit
    #!/bin/bash
    npm test
    

→ 2025/02/05 12:00 AM

Display colors in Makefile

In a previous note, I shared how to create a help command in a Makefile.

This time, let’s make it visually appealing by adding colors to the output.

Here’s how to do it:

# COLORS
YELLOW = \033[33m
GREEN  = \033[32m
WHITE  = \033[37m
RESET  = \033[0m

help: ##@helper Display all commands and descriptions
	@awk 'BEGIN {FS = ":.*##@"; printf "\n${WHITE}Usage:${RESET}\n  make <target>\n"} \
	/^[.a-zA-Z_-]+:.*?##@/ { \
		split($$2, parts, " "); \
		section = parts[1]; \
		description = substr($$2, length(section) + 2); \
		sections[section] = sections[section] sprintf("  ${YELLOW}%-15s${RESET} ${GREEN}%s${RESET}\n", $$1, description); \
	} \
	END { \
		for (section in sections) { \
			printf "\n${WHITE}%s${RESET}\n", section; \
			printf "%s", sections[section]; \
		} \
	}' $(MAKEFILE_LIST)
  • YELLOW, GREEN, WHITE, and RESET are ANSI escape codes for terminal colors.
  • \033[33m sets the color to yellow, \033[32m to green, and \033[37m to white.
  • \033[0m resets the color to the terminal default.

It formats the output with colors:

  • Yellow for target names.
  • Green for descriptions.
  • White for the rest

→ 2025/01/23 12:00 AM

Display all Makefiles commands

Makefiles can be hard to navigate, especially as they grow. Adding a help command makes it easy to see all available targets and their purposes.

The magic help target

Add this awk snippet to your Makefile:

.DEFAULT_GOAL := help
.PHONY: help

help: ##@helper Display all commands and descriptions
	@awk 'BEGIN {FS = ":.*##@"; printf "\nUsage:\n  make <target>\n"} \
	/^[.a-zA-Z_-]+:.*?##@/ { \
		split($$2, parts, " "); \
		section = parts[1]; \
		description = substr($$2, length(section) + 2); \
		sections[section] = sections[section] sprintf("  \033[36m%-15s\033[0m %s\n", $$1, description); \
	} \
	END { \
		for (section in sections) { \
			printf "\n\033[1m%s\033[0m\n", section; \
			printf "%s", sections[section]; \
		} \
	}' $(MAKEFILE_LIST)

How it works

  • Use ##@ to group related targets
  • And place the description of each command after that group

Example Makefile


help: ##@helper Display all commands and their descriptions
	@awk 'BEGIN {FS = ":.*##@"; printf "\nUsage:\n  make <target>\n"} \
	/^[.a-zA-Z_-]+:.*?##@/ { \
		split($$2, parts, " "); \
		section = parts[1]; \
		description = substr($$2, length(section) + 2); \
		sections[section] = sections[section] sprintf("  \033[36m%-15s\033[0m %s\n", $$1, description); \
	} \
	END { \
		for (section in sections) { \
			printf "\n\033[1m%s\033[0m\n", section; \
			printf "%s", sections[section]; \
		} \
	}' $(MAKEFILE_LIST)


# You can split this in a separated file: validate.Makefile
install: ##@validate Install dependencies
	@pnpm install

typecheck: ##@validate Check static types
	@pnpm tsc --noEmit

lint: ##@validate Lint the codebase
	@pnpm run lint

test: ##@validate Run tests
	@pnpm run test

# You can split this in a separated file: deploy.Makefile
build: ##@deploy Build for production
	@pnpm run build

deploy: ##@deploy Deploy to production
	@pnpm run deploy

.PHONY: help install typecheck lint test build deploy
.DEFAULT_GOAL := help

Running make or make help shows:

 make

Usage:
  make <target>

deploy
  build           Build for production
  deploy          Deploy to production

helper
  help            Display all commands and their descriptions

validate
  install         Install dependencies
  typecheck       Check static types
  lint            Lint the codebase
  test            Run tests

→ 2025/01/22 12:00 AM

Supercharge Git with fzf

Working with Git branches can be annoying, especially with long names or when cleaning up old ones. Try fzf, a tool that makes managing branches easy.

Switch branches

Use fzf to select and switch branches interactively:

git branch | fzf --preview 'git log -p main..{-1} --color=always {-1}' | cut -c 3- | xargs git switch

Delete branches

Delete branch interactively with fzf:

git branch | fzf -m --preview 'git log -p main..{-1} --color=always {-1}' | cut -c 3- | xargs git branch -d

I setup them in my shell config to save time:

alias gs="git switch"
alias gsc="git witch -c"
alias gsi="git branch | fzf --preview 'git log -p main..{-1} --color=always {-1}' | cut -c 3- | xargs git switch"
alias gbd="git branch | fzf -m --preview 'git log -p main..{-1} --color=always {-1}' | cut -c 3- | xargs git branch -d"

→ 2025/01/21 12:00 AM

Better Git log

The default git log output can be hard to read. Here’s how I make it more visual and informative using aliases.

  • Add these aliases to the global .gitconfig:
[alias]
    # Tree-like log with relative dates
    logs = log --graph --date=relative --pretty=tformat:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%an %ad)%Creset'

    # Limit to 20 commits
    log = logs -n 20
  • Alternatively, set up aliases in your shell config:
alias glog="git log --graph --date=relative --pretty=tformat:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%an %ad)%Creset' -n 20"
alias glogs="git log --graph --date=relative --pretty=tformat:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%an %ad)%Creset'"
  • Example output
* c0eb700 - (HEAD -> master, origin/master, origin/HEAD) chore(fish): update alias (woula 26 minutes ago)
* 960e14f - chore(nvim): update plugins, active flash, disable cappuchine (woula 16 hours ago)
* bc1129d - feat(nvim): add disabled plugins list (woula 3 days ago)
* 6e14bad - feat(nix): update config for homebrew (woula 5 days ago)

That is a little bit better than this: git log --graph --oneline --decorate --all

 git log --graph --oneline --decorate --all
* c0eb700 (HEAD -> master, origin/master, origin/HEAD) chore(fish): update alias
* 960e14f chore(nvim): update plugins, active flash, disable cappuchine
* bc1129d chore(nvim): recrete list of disabled plugins
* 6e14bad feat(nix): update config for homebrew

And a lot more readable than the default: git log

 git log
* c0eb700 (HEAD -> master, origin/master, origin/HEAD) chore(fish): update alias
commit c0eb700 (HEAD -> master, origin/master, origin/HEAD)
Author: woula <[email protected]>
Date:   Sun Jan 26 10:02:37 2025 +0100

    chore(fish): update alias

commit 960e14f
Author: woula <[email protected]>
Date:   Sat Jan 25 18:32:42 2025 +0100

    feat(nvim): update plugins, active flash, disable cappuchine

commit bc1129d
Author: woula <[email protected]>
Date:   Thu Jan 23 07:00:58 2025 +0100

    feat(nix): update config for homebrew

→ 2025/01/20 12:00 AM

Managing multiple Git accounts

Working with multiple Git accounts (e.g., work, personal, open-source) can be tricky. Here’s how I manage them seamlessly using conditional includes in .gitconfig.

Global .gitconfig setup

Add conditional includes to the global .gitconfig:

[includeIf "gitdir:~/projects/company1/"]
    path = ~/projects/company1/.gitconfig

[includeIf "gitdir:~/projects/company2/"]
    path = ~/projects/company2/.gitconfig

[includeIf "gitdir:~/projects/oss/"]
    path = ~/projects/oss/.gitconfig

Local .gitconfig

In each project’s .gitconfig, specify the user and SSH key.

Here is example for ~/projects/company1/.gitconfig

[user]
    name = username1
    email = [email protected]

[core]
    sshCommand = ssh -i ~/.ssh/company1_rsa

Git will help us to automatically switch configurations based on the project directory.

→ 2025/01/19 12:00 AM

Git aliases

Git aliases are a must have for every developer. They save time, reduce typing, and make your workflow more efficient.

You can set them up in two ways: terminal shell aliases or .gitconfig.

Terminal shell aliases

Here’s a part how I set up my Git aliases in my shell config (e.g. .zshrc or fish.config ...etc.):

# Git
alias g="git"
alias gc="git commit -m"
alias gca="git commit -a -m"
alias gp="git push origin HEAD"
alias gpu="git pull origin"
alias gpf="git push --force-with-lease"
alias gst="git status"
alias gs="git switch"
alias gsc="git switch -c"
alias gdiff="git diff"
alias gco="git checkout"
alias gcob="git checkout -b"
alias gb="git branch"
alias gba="git branch -a"
alias gadd="git add"
alias ga="git add -p"
alias gre="git reset"

.gitconfig alias

Other way to manage git alias with global .gitconfig

[alias]
    # List all aliases
    aliases = !git config --get-regexp alias | sed -re 's/alias\\.(\\S*)\\s(.*)$/\\1 = \\2/g'

    # Command shortcuts
    st = status
    cm = commit -m
    co = checkout
    stl = stash list
    stp = stash pop stash@{0}
    sts = stash save --include-untracked
    sw = switch
    a = !git add .
    ca = !git commit --amend -C HEAD
    fetch = !git fetch --all --prune

    # Force-push safely (won’t overwrite others’ work)
    pf = push --force-with-lease

    # Update last commit with staged changes
    oups = !(git add . && git commit --amend -C HEAD)

    # Edit last commit message
    reword = commit --amend

    # Undo last commit but keep changes staged
    uncommit = reset --soft HEAD~1

    # Remove file(s) from Git but keep them on disk
    untrack = rm --cached --

    # Delete merged local branches
    delete-local-merged = "!git fetch && git branch --merged | egrep -v 'master' | xargs git branch -d"

    # Create an empty commit (useful for CI triggers)
    empty = commit --allow-empty

→ 2025/01/18 12:00 AM

Run a command if there are unstaged changes

A quick one-liner to run a command only if there are unstaged changes: the --quiet flag of git diff

The flag does two things:

  • Disables all output of the command
  • Exits with 1 if there are differences, and 0 if there are no differences.

That means you can combine it with boolean operators to only run another command if files have (or have not) changed:

# Run `command` if there are unstaged changes
git diff --quiet || command

# Run `command` if there are NO unstaged changes
git diff --quiet && command

Other tips

  • Check for untracked files

    git ls-files --others --exclude-standard | grep -q . && command
    
  • Include staged changes

    git diff --cached --quiet || command
    
  • Combine with entr for file watching

    git diff --quiet || entr -r command
    
  • Use in CI pipelines

    git diff --quiet || echo "Changes detected, running tests..." && npm test
    

→ 2025/01/17 12:00 AM

List all files tracked by Git

Sometimes you need a list of all files tracked by Git—for example, when using tools like entr to watch files for changes. Instead of fiddling with find, Git provides a clean and concise command git-ls-files:

git ls-files

This lists all files in the repository that are tracked by Git.

Other tips

  • Include ignored files:

    git ls-files --others --ignored --exclude-standard
    
  • Filter by file type:

    git ls-files '*.js' # List only JavaScript files
    
  • Use with entr to watch files:

    git ls-files | entr -r your-command
    

→ 2025/01/16 12:00 AM

Git Checkout vs. Git Switch

git checkout

  • Switch branches:

    git checkout <branch>        # Switch to an existing branch
    
  • Create and switch to a new branch:

    git checkout -b <new-branch> # Create and switch to a new branch
    
  • Restore files from a specific commit or branch:

    git checkout <commit> -- <file> # Restore a file from a specific commit
    

git switch (modern alternative)

  • Switch branches:

    git switch <branch>          # Switch to an existing branch
    
  • Create and switch to a new branch:

    git switch -c <new-branch>   # Create and switch to a new branch
    

Key differences

CommandPurposeNotes
git checkout <branch>Switch branchesOlder, more versatile command.
git checkout -b <branch>Create and switch to a new branchCombines branch creation and switch.
git checkout <commit> -- <file>Restore a file from a commitUseful for recovering files.
git switch <branch>Switch branchesModern, focused alternative.
git switch -c <branch>Create and switch to a new branchSimpler and more intuitive.

When to use?

  • git checkout:

    • Use for restoring files from a specific commit or branch.
    • Still works for switching branches, but git switch is preferred.
  • git switch:

    • Use for switching branches or creating new branches.
    • Cleaner and more focused than git checkout.

Pro tips

  • Recover deleted branches:

Use git reflog to find the branch’s last commit, then recreate it:

git switch -c <branch> <hash>
  • Use git switch for branch operations. It’s designed specifically for branches, making it more intuitive.

→ 2025/01/15 08:00 PM

Git Reset vs. Git Restore

git reset

  • Undo commits (keep changes staged):

    git reset --soft HEAD~        # Move HEAD but keep changes staged
    git reset --soft <commit>     # Move to specific commit, keep changes staged
    
  • Unstage changes (keep changes in working directory):

    git reset HEAD~              # Reset --mixed (default), move HEAD and unstage changes
    git reset <commit>           # Reset --mixed, move to specific commit and unstage changes
    git reset HEAD <file>        # Unstage a specific file
    
  • Discard commits and changes (destructive):

    git reset --hard HEAD~1      # Discard commits and changes permanently
    

git restore

  • Discard working directory changes:

    git restore <file>           # Revert file to its state in the last commit
    
  • Unstage changes:

    git restore --staged <file>  # Move changes from staging area to working directory
    
  • Restore a file from a specific commit:

    git restore --source=<commit> <file> # Restore file from a specific commit
    

Key differences

CommandBranch pointerStaging areaWorking directory
git reset <commit>MovesResets (unstages)Unchanged
git reset --soft <commit>MovesUnchangedUnchanged
git restore <file>UnchangedUnchangedResets file
git restore --staged <file>UnchangedResets (unstages)Unchanged

When to use?

  • git reset:

    • Move branch pointers or undo commits.
    • Unstage changes (though git restore --staged is more intuitive).
  • git restore:

    • Discard changes in the working directory.
    • Unstage changes (modern alternative to git reset HEAD <file>).

Pro tips

  • Recover from a hard reset: Use git reflog to find the lost commit and reset back:
git reflog
git reset --hard <hash>
  • Combine git reset and git restore: Reset to a specific commit but keep changes in the working directory:
git reset <commit>
git restore .
  • Avoid --hard unless necessary: Use --soft or --mixed to preserve changes.

→ 2025/01/15 12:00 AM

Ignore all .DS_Store files globally

If you use Git on a Mac, you’ve probably accidentally committed a .DS_Store file to a repo at least once. I used to add .DS_Store to every .gitignore file to avoid this, but there’s a better way!

You can create a global .gitignore file that applies to all your repositories. Just run this command:

git config --global core.excludesFile '~/.gitignore'

Then, add .DS_Store to your ~/.gitignore file:

echo ".DS_Store" >> ~/.gitignore

This command adds the following to your ~/.gitconfig:

[core]
    excludesFile = ~/.gitignore

Now, .DS_Store files will be ignored across all your projects, no more accidental commits!

You can directly edit the ~/.gitignore file to globally ignore many other files.

→ 2025/01/14 12:00 AM

Update all Git submodules to the latest commit

If you use Git submodules often, here's the one-liner to update them to the latest commit on origin (since Git 1.8.2):

git submodule update --remote --rebase

Prefer merging? Swap --rebase for --merge.

→ 2025/01/13 12:00 AM

Run Github actions locally

Run GitHub actions locally with act to skip the long feedback loop! It uses Docker to pull images and run workflows right on your machine.

# Run the `push` event
act

# Run a specific event or job
act pull_request
act -j test_unit

Need a GitHub token? Use the -s flag with the GitHub CLI:

act -s GITHUB_TOKEN="$(gh auth token)"

Quick, easy, and no more waiting for GitHub to run workflows!

→ 2025/01/12 12:00 AM

First attempt at migrating from Homebrew to Nix with Nix Home Manager

It didn’t go exactly as planned. I dived into Nix scripts, flakes, and started installing packages with nixpkgs while keeping Homebrew on the side. But... nothing seemed to work correctly. 😵

Tools like fish shell, fzf, and ghostty .etc... didn't work. I probably need to configure each program properly, manage environments, and link the ~/.config files with Nix...

During the migration, I enabled autoCleanUp Homebrew with "zap" without paying close attention. Big mistake! It wiped out everything I’d installed through Homebrew. 😱 Aie aie aie.

Thankfully, I had saved all my tools in a Brewfile in my dotfiles. A quick brew bundle restored everything (though it took time to install).

Lesson learned: I need to take it step by step with Nix, learning more about proper configurations before jumping in too deep.

For now, I’m sticking with Homebrew but I’ll give Nix another try someday.

→ 2025/01/10 08:09 PM

Tiling window management on macOS with aerospace

In the past, I was a rectangle user. I used it to move windows into corners or split the screen, basic functionality. Honestly, it never felt transformative. It was fine, but quite basic. I only used it during screen-sharing sessions on Teams calls. I always wanted something more controllable and better organized, with groupings of applications.

Recently, I explored raycast, and at first, it seemed like the solution I had been looking for. It offered intuitive window organization, powerful workspace controls, and a lot of cool features.
But then I discovered that many of the features I wanted required the Pro version. So I knew I had to look elsewhere.

That’s when I came across aerospace, thanks to all the people sharing it on YouTube. And wow! This is the tool I was looking for! (powerful, free, open-source, workspace management simple, entirely keyboard shortcuts)

Using aerospace has completely transformed my workflow. I now have workspaces neatly organized by task coding (C), terminal (T), browser (B), music (M)... and switching between them is really simple. I can even set apps to open in specific workspaces by default. So cool! Everything feels smoother, faster, and more focused.

For me, there’s only one drawback: aerospace doesn’t natively support the AZERTY keyboard layout, it might a bit inconvenient. However, I can map the QWERTY shortcuts on same location with AZERTY layout and that solution is ok for me.

→ 2025/01/08 10:00 PM

Manage better for my dotfiles

Up until now, I’ve been handling my dotfiles manually with a Makefile and shell scripts. I used commands like rsync to mirror files from my ~/.config directory to my ~/dotfiles folder, and then saved everything on GitHub. While this approach worked, it was tedious and had a lot of limitations:

  • rsync wouldn’t handle deletions properly, so if I deleted a file in ~/.config, it wouldn’t be removed from the dotfiles folder.
  • I had to run make sync every time I wanted to update my dotfiles
  • Restoring configurations wasn’t properly handled
  • I also wanted to directly manage the ~/.config folder with Git, but my current setup didn’t make that easy.

Then, I stumbled across a YouTube video about using GNU Stow to manage dotfiles. It’s such a simple yet powerful tool! Stow creates symlinks from your dotfiles folder to your ~/.config directory, so there’s no need for manual mirroring. Everything stays organized and up-to-date automatically.

Now, I manage my ~/dotfiles easily with Stow, and my ~/.config folder is directly synced via symlinks.

I love how clean and efficient this setup feels. Highly recommend giving Stow a try if you’re looking for a better way to manage dotfiles!

→ 2025/01/05 12:01 PM

CLI tools I love using

I’m a huge fan of Rust, and it’s no surprise that many of the tools I rely on in the terminal are written in rust.

Here’s a quick rundown of my favorites:

  • Fzf: Fuzzy finder that makes searching files or commands a breeze.
  • Eza: A modern, colorful alternative to ls that adds more functionality.
  • Zoxide: A smarter cd command that remembers your most-used directories.
  • Fish shell: A user-friendly shell with auto-suggestions and syntax highlighting.
  • Starship prompt: Fast, customizable prompt with support for all major shells.
  • Ripgrep: Lightning-fast search tool, a must-have for large codebases.
  • Sd: Simpler, more intuitive replacement for sed.
  • Fd: Faster, friendlier alternative to find with colorful output.
  • Jq: Power tool for processing JSON data in the terminal.
  • Lazygit: Terminal-based Git interface, perfect for lazy devs.
  • Lazydocker: Easy-to-use terminal tool for managing Docker containers.
  • Bat: Better cat with syntax highlighting and line numbers.
  • Git-delta: Enhanced git diff tool with better formatting.
  • Fnm: Fast, Rust-based Node.js version manager.

UPDATED LIST:

  • Neovim: + Lazyvim
  • Stow: Manages dotfiles.
  • Ghostty: Terminal emulator.
  • Aerospace: Window manager.
  • Hyperfine: Benchmarking tool.

→ 2025/01/03 03:00 PM

Returning to Neovim for coding

I’ve started using Neovim for coding again.

Early in my career, like many others, I tried to learn Vim. At first, it was difficult to get used to, but I found it fun and rewarding. For some, Vim can feel more "professional," and there's something satisfying about the cool things you can do with it.

I really liked Vim, but when it came to coding, I ran into many challenges. Configuring Vim with the right plugins, settings, and workflows took a lot of time. Back then, I was working with many different languages—Python, Ruby, JavaScript, TypeScript, HTML, CSS—and I could never quite get Vim to work smoothly across all of them. I faced too many issues, so eventually, I switched to VSCode and IntelliJ for most of my coding, using Vim only for occasional file edits.

Now, with modern terminals like Wezterm and Ghostty, I find myself enjoying the terminal environment more. I want to keep my hands on the keyboard as much as possible, so I decided to give Vim another try, but this time with Neovim. Neovim is a more modern and flexible alternative to Vim, with support for Lua-based scripting and plugins.

It’s taking some time to get fully comfortable with Neovim again, but I’m using LazyVim to manage my plugins, and it’s been fantastic. It supports many of the plugins I need for coding, especially the which-key plugin, which shows all available keybindings in Neovim—something I missed when using Vim before.

LazyVim makes it easy to add, remove, or configure plugins, and the documentation is top-notch, so I can quickly reference the keymaps I need.

I also tried Helix, a text editor built from scratch with Rust. It’s designed to provide a similar experience to Vim but with better performance. It’s still young and doesn’t support plugins yet, and it lacks features like a file explorer, which I rely on. However, I think it has potential, and in the future, it could be a solid alternative to Vim.

For now, I feel more comfortable with Neovim, but it's still not perfect. I continue using VSCode for larger projects, but I’ve enabled the Neovim extension in VSCode, which lets me use Vim keybindings and workflows within VSCode. It’s not the full Vim experience, but it’s been a great way to continue learning Vim while working in a modern IDE. At least now, I don’t need to use the mouse when coding in VSCode.

For smaller projects, I stick to using Neovim in the terminal.

For browsing, I now use Vim as well. With the Vimium extension, I can use Vim-like keybindings and perform almost everything without touching the mouse. It’s really fun and efficient to use.

→ 2025/01/03 03:00 PM

Ghostty?

Ghostty has just released its official production-ready version: 1.0, and it’s causing quite a hype among developers across all platforms. I’m really curious to try it out!

Ghostty is a terminal emulator built with Zig. Most terminal emulators I’ve used, like WezTerm, Warp, Alacritty, and Zellij, are written in Rust. So it’s exciting to see a terminal tool developed in Zig instead. (I really like both of 2 this languages: rust and zig)

I decided to give it a shot, even though I’ve been happily using WezTerm. And I have to say, I’m impressed.

It’s fast—faster than WezTerm in terms of startup time and when opening new tabs. It integrates smoothly with Fish shell, which I love.

The keybindings are easy to access, and the setup process is a really simple. Plus, it supports a variety of themes.

Some standout features include Quick Terminal and the ability to use Cmd + Triple-click for selection—simple yet powerful.

So, I’ve made the switch. My terminal is now Ghostty.

→ 2025/01/01 09:00 PM

I’ve started implementing notes on my website

The goal is to create a space for sharing shorter updates, thoughts, and progress on ongoing projects. I plan to update this space regularly with useful insights and updates.

Stay tuned for more posts soon.

→ 2024/12/26 08:09 AM