CLI tool
necolas/dotfiles avatar
necolas/dotfiles

necolas dotfiles: a macOS zsh setup built on symlinks and two hooks

OS X dotfiles: bash, git, vim, etc.

797 stars140 forksShellMIT

At a glance

What is it?
The necolas dotfiles repository is a personal macOS zsh configuration installed with a single curl command that pulls in Homebrew, Git, a set of packages, and a directory of symlinks. Almost every file is symlinked, but the two files other tools also write to, ~/.zshrc and ~/.gitconfig, keep a real file with a hook at the top, and the repository has no releases at all.
Who is it for?
necolas dotfiles fits a macOS developer who wants a working zsh, git, and vim setup quickly and intends to make it their own, since the README is explicit that forking it means replacing the username in the install command and in the two variables at the top of the script. It does not fit a Linux user, a user who cannot accept a script that installs Homebrew and writes to their home directory, or a team that needs a versioned, tagged release to track.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 80 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One curl command, and a warning about what it overwrites

The repository is a personal set of macOS dotfiles for zsh, described in one line as OS X dotfiles covering bash, git, and vim among others. The primary language is shell.

The installation is a single command that pipes a script into zsh.

bash
$ zsh -c "$(curl -fsSL https://raw.githubusercontent.com/necolas/dotfiles/main/bin/dotfiles)"

The README states the requirement plainly, and it is the one to read before running anything. The installation step requires the XCode Command Line Tools, and it may overwrite existing dotfiles in your HOME and .vim directories.

The script lives in the bin directory of the repository, and forking is explicitly supported. If you want to fork the project and maintain your own dotfiles, you must substitute the original username for your own in that command and in the two variables found at the top of the bin/dotfiles script. So this is a template with a specific shape rather than a package you configure, and the fork is the intended path to making it yours.

The install directory is chosen at run time, with a prompt that defaults to ~/.dotfiles, or the existing config if there is one, and the answer is saved to ~/.config/dotfiles/config for future runs. That config file is what makes the update command work later.

Twelve steps, including Homebrew and a git identity prompt

The README enumerates exactly what the installation does, in order, and the sequence is worth reading because it explains why the setup behaves the way it does.

First it prompts for the install location, defaulting to ~/.dotfiles, then saves that config to ~/.config/dotfiles/config, then downloads the repository to the chosen location if it is not already present. After that it installs Homebrew if it is not already installed, installs Git through Homebrew, initialises a Git repository and connects it to the remote, and syncs with the remote to pick up the latest changes.

Then it installs packages through Homebrew, and creates the symlinks. The list is short and specific: ~/.curlrc, ~/.gitattributes, ~/.gitignore, ~/.gvimrc, ~/.vim, ~/.vimrc, ~/.zprofile, and ~/.zshenv, each pointing into a subdirectory of the dotfiles repository.

After the symlinks come two steps that are not mechanical. It adds a hook to the top of ~/.zshrc, and it asks for your git author identity and writes it to ~/.gitconfig with an include of the dotfiles gitconfig file. The last step applies macOS defaults, and that one is optional and comes with a confirmation prompt.

Two things stand out. The installer will install Homebrew for you, which means a machine that did not have a package manager now has one, and the git identity is captured once and stored locally, which is what makes the dotfiles repository itself free of personal data.

Why two files are hooks instead of symlinks

The design decision in this repository is the one worth copying, and it is explained in the README under hooked files.

Most of your configuration is symlinked. ~/.vimrc points at the vim directory, ~/.zprofile and ~/.zshenv point at the shell directory, and the git attribute and ignore files point at the git directory. Edit a file in the repository and the change takes effect, because there is only one copy of it.

Two files are different. ~/.zshrc and ~/.gitconfig are real files, not symlinks, and each holds a hook at the top that reads the dotfiles config: the zshrc hook sources shell/zshrc, and the gitconfig hook includes git/gitconfig.

The reason is stated plainly: other tools write to both files, and an append follows a symlink, which would send those writes into this repository. A tool appending to your zshrc would end up appending to the dotfiles repository, and the next sync would push your stray line to the remote.

The placement of the hook is the second half of the trick, and it has a behavioural consequence. The hook goes at the top, and zsh and git both take the last value they read, so a setting placed below the hook overrides a dotfiles default. That is the opposite of the usual arrangement, where the system file is read last and wins, and it means your machine-local settings should live below the hook, where they take precedence.

The result is that the repository owns the defaults and your machine owns the overrides, without either overwriting the other.

The git identity is asked for once and never stored in the repo

The git identity handling is unusually careful, and it is a good pattern for anyone copying this.

Your name and email live in ~/.gitconfig. That file is not tracked, and the repository stores no identity. The installer asks for it once, with a prompt that shows what the identity is for, since every commit carries that name and email.

bash
$ git config --global user.email "[email protected]"

The second half of the design is what makes the first half safe. The dotfiles gitconfig sets user.useConfigOnly to true, and the README explains what that does: git then refuses to commit until an identity exists, and never guesses one from the operating system.

The consequence is stated in a sentence that is worth borrowing verbatim. A forgotten identity stops the commit, and it cannot mislabel one. So the failure mode is a blocked commit rather than a commit attributed to the wrong person, which is the failure mode that matters on a shared or work machine.

A small related convention handles Vim. Any special case Vim directives that are local to one machine go into a ~/.vimrc.local file on that machine, and the directives are automatically imported into the master .vimrc. The repository stays generic, and the machine keeps its exceptions in a file the repository never sees.

Updating is a command, and a faster one for local edits

The update story is where a dotfiles repository either works or becomes a chore, and this one is built around the observation that most files are symlinked.

You should run the update when you want to pull changes from the remote repository, or when you want to update the Homebrew formulae. You do not need to run it after editing a file in the repository, because every file is either symlinked or included, so an edit takes effect in the next shell. That single sentence removes the most common reason people stop maintaining a dotfiles setup.

The update command is just the command name.

bash
$ dotfiles

Three options are documented. The help flag prints the usage. The link flag is a quick update that refreshes the symlinks only, skipping the sync, the packages, and the macOS defaults. The macos flag applies the macOS system settings only, which is also how those settings are applied independently of the rest of the process.

bash
$ dotfiles --macos

For local development there is a dedicated mode.

bash
$ dotfiles --link

This refreshes the symlinks and the hooks without syncing or updating packages, and the README makes a promise about it that is worth checking: it never removes a line that this repository did not write. That is the property that makes the hook approach safe to run repeatedly, because the hook can be re-applied without eating the settings you have added below it.

There is also a backup script, which uses rsync to incrementally back up your data to an external, bootable clone of the computer's internal drive. Before using it you have to make sure the value of DST in the bin/backup script matches the name of your backup drive, and then run the command.

bash
$ backup

A prompt that shows what git is doing

The zsh prompt is a small piece of work that carries more weight than it looks like, and the README describes it in enough detail to reimplement.

When the current working directory is a Git repository, the prompt displays the name of the checked out branch. During a rebase, a merge, or a bisect, it also shows the action, in the form main|rebase-i.

The state of the working tree is shown with single characters. A plus sign means uncommitted changes in the index, an exclamation mark means unstaged changes, a question mark means untracked files, and a dollar sign means stashed files.

The implementation detail is the part that makes it fast. The prompt is built on zsh's own vcs_info, with one git status call per prompt, and the details live in the shell/prompt file.

That last point is the design decision. A shell prompt that runs several git commands on every render is the reason people disable fancy prompts, and a prompt that gets the branch name from the shell's built in mechanism and the dirty state from a single status call stays cheap enough to keep.

The rest of the setup is small and worth listing. The Homebrew formulae installed are GNU core utilities, git, node, and bun, which is a deliberately short list for a working developer machine. The vim configuration is symlinked, with a .gvimrc and the .vim directory, and the shell configuration covers zprofile, zshenv, and the prompt, with the curlrc as well.

On maintenance, the project is not archived, the last push was on 2026-08-04, and there are no GitHub releases, which is the usual arrangement for a dotfiles repository where the default branch is the distribution. The licence is MIT, and the README closes by acknowledging that code and inspiration came from several other dotfiles repositories, among them those of Mathias Bynens, Tom Ryder, Gianni Chiappetta, and Ben Alman.

Editorial conclusion

necolas dotfiles fits a macOS developer who wants a working zsh, git, and vim setup quickly and intends to make it their own, since the README is explicit that forking it means replacing the username in the install command and in the two variables at the top of the script. It does not fit a Linux user, a user who cannot accept a script that installs Homebrew and writes to their home directory, or a team that needs a versioned, tagged release to track. Verify first that the install location prompt defaults somewhere you want, since the chosen path is saved and reused, that you are prepared to have ~/.zshrc and ~/.gitconfig modified rather than replaced, and that the git identity the installer asks for is one you want on every commit from that machine.

Frequently asked questions

How do I install the necolas dotfiles?

The documented install is a single command that pipes the bin/dotfiles script into zsh, and it requires the XCode Command Line Tools. The script prompts for an install location, defaulting to ~/.dotfiles, and saves that choice to ~/.config/dotfiles/config for later runs.

Why are ~/.zshrc and ~/.gitconfig not symlinked like the other files?

Other tools write to those two files, and an append follows a symlink, which would send those writes into the dotfiles repository. They are therefore real files with a hook at the top that sources shell/zshrc and includes git/gitconfig, and because zsh and git take the last value they read, settings below the hook override the dotfiles defaults.

How do I update the necolas dotfiles after editing a file?

You do not need to run an update for a local edit, because every file is either symlinked or included, so the change takes effect in the next shell. Run the dotfiles command to pull remote changes and update Homebrew formulae, or dotfiles --link for a quick refresh of the symlinks and hooks alone.

How does the dotfiles repository handle my git identity?

The name and email live in ~/.gitconfig, which is not tracked, and the installer asks for them once. The dotfiles gitconfig sets user.useConfigOnly to true, so git refuses to commit until an identity exists and never guesses one from the operating system.

Can I fork the necolas dotfiles for my own use?

Yes, and the README says it is expected. You have to substitute the original username for your own in the install command and in the two variables at the top of the bin/dotfiles script, since the project is a personal configuration rather than a configurable package.

Official sources

  1. Issues
  2. License: MIT
  3. necolas/dotfiles on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/necolas-dotfiles.svg)](https://hysenlabs.com/projects/necolas-dotfiles)

Was this useful?