A simple Bash script to manage macOS configuration files using Git and symlinks.
- Overview
- Getting Started
- Daily Usage
- Manual Backup Approach
- Important Notes
- Troubleshooting
- Environment
- Neovim
- Lazygit
- TMUX
This script simplifies managing dotfiles (configuration files) by either:
- Symlink-based management: Run
./dotfiles installto create symlinks from your home directory to the Git repository, making the repository the source of truth. Changes to your configs are instantly reflected in the repository, enabling real-time version control. - Manual backup: Run
./dotfiles backupto copy your configuration files to the repository for manual tracking without symlinks.
Run the script with one of these commands:
./dotfiles.sh install # Set up symlinks for new machine
./dotfiles.sh backup # Copy current configs to repository
./dotfiles.sh update # Commit and push changes to Git
./dotfiles.sh help # Show help messageTo start managing your dotfiles with this repository:
-
Copy existing configs to the repository:
./dotfiles.sh backup
-
Commit the configs:
git add . git commit -m "Initial dotfiles backup" git push
-
Switch to symlink-based management:
./dotfiles.sh install
This creates symlinks from your home directory to the repository, making it the source of truth.
To set up dotfiles on a new machine:
-
Install dotfiles before launching applications:
./dotfiles.sh install
-
Install your applications (e.g., Neovim, tmux, Kitty). They will automatically use the symlinked configurations.
With symlink-based management, edit your configs as usual:
nvim ~/.config/nvim/init.lua # Edits the file in the repositoryTo save changes to the repository:
./dotfiles.sh update # Quick commit and push
# OR
git add .
git commit -m "Detailed commit message"
git pushIf you prefer not to use symlinks, you can manually back up your configs:
-
Keep your configuration files in their default locations (e.g.,
~/.zshrc). -
Run the backup command whenever you want to save changes:
./dotfiles.sh backup
-
Commit and push the changes:
git add . git commit -m "Updated configs" git push
Note: This approach requires manual backups and does not provide real-time version tracking.
- Run
installbefore launching applications on a new machine to ensure symlinks are in place. - Use
backuponly once during initial setup if using symlinks. Afterinstall, edits happen directly in the repository. - Repository as source of truth: With symlinks, your repository files are directly used by applications.
- Backup safety: Existing files are backed up to
~/.dotfiles_backup_<timestamp>duringinstallif they are not already symlinks.
- Symlink errors: Ensure you have write permissions in
~/.configand other target directories. Check for existing files or symlinks that may conflict. - Missing dotfiles: If a dotfile (e.g.,
~/.zshrc) is not found duringbackup, ensure it exists in your home directory. - Git issues: Verify your repository is properly initialized (
git init) and configured with a remote (git remote add origin <url>). - Application config not updating: Confirm symlinks are correctly set up by running
ls -lin~/.configor~to verify links point to the repository.
Install Kitty terminal:
curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdinInstall Nerd Fonts:
brew install --cask font-jetbrains-mono-nerd-fontInstall Neovim:
brew install neovimInstall lazygit:
brew install lazygitInstall tree-sitter-cli:
brew install tree-sitter-cliInstall ripgrep (used for live grep):
brew install ripgrepInstall fd (used by Telescope for find):
brew install fdInstall fzf (used for fuzzy finder by Telescope):
brew install fzfInstall wget:
brew install wgetConfiguration for Neovim, Vim-based text editor.
Neovim key mapping, based on macOS.
| Command | Description |
|---|---|
:map |
Show all key mappings for all modes |
:map <key> |
Show mapping for specific key (e.g. :map <leader>xt) |
:nmap |
Show normal mode mappings only (e.g. :nmap <leader>gg) |
:imap |
Show insert mode mappings only |
:vmap |
Show visual mode mappings only |
:verbose map <key> |
Show mapping with source file location |
:help |
Open help system |
:help <topic> |
Get help on specific topic |
:WhichKey |
Show available keybindings (LazyVim) |
:Lazy |
Open plugin manager |
:LazyExtras |
Lazy extras |
:Mason |
Open LSP/tool installer |
:LspInfo |
Show LSP client information |
:TSInstallInfo |
All available Treesitter language parsers |
:TSInstall lang |
Install Treesitter parser for a specific language |
:Telescope keymaps |
Browse all keymaps in Telescope |
:checkhealth |
Run health checks for plugins/config |
:messages |
Show recent messages/errors |
:pwd |
Show current working directory |
:cd <path> |
Change working directory |
:e <file> |
Edit/open file |
:w |
Write/save current file |
:q |
Quit current window |
:qa |
Quit all windows |
:wq |
Write and quit |
:terminal |
Open terminal in current window |
:split | terminal |
Open terminal in horizontal split |
:vsplit | terminal |
Open terminal in vertical split |
:tabnew | terminal |
Open terminal in new tab |
:ls! |
List all buffers, including unlisted ones like term:// (shows buffer number) |
:buffer <number> |
Open buffer <number> in the current window, replacing its content |
:sbuffer <number> |
Open buffer <number> in a new horizontal split (like original plugin split) |
:vsplit | buffer <number> |
Open buffer <number> in a new vertical split |
:bdelete <number> |
Delete buffer <number>, terminating any running terminal job |
:set wrap |
Enable word wrap |
:set nowrap |
Disable word wrap |
:set wrap! |
Toggle word wrap on/off |
Leader key: Spacebar
| Mode | Input | Action |
|---|---|---|
| n | <leader> l |
Lazy (:Lazy) |
| n | <leader> cm |
Mason: Language servers, linters, and formatters (:Mason) |
| n | <leader> e |
Snacks Explorer: File system tree sidebar |
| n | <leader> ff |
Snacks Picker: Find files |
| n | <leader> cs |
Outline: Code outline (:Outline) |
| n | <leader> gg |
Lazygit: Terminal UI for git commands (:LazyGit) |
| n | <leader> ft |
Snacks Terminal: Toggle terminal |
| n | <leader> sr |
Ripgrep: Search and replace |
| n | <leader> sn |
Noice: UI notifications and messages |
| n | <leader> sh |
Search Help |
| n | <leader> sk |
Search Keymaps |
| n | <leader> qq |
Quit all |
| Mode | Input | Action |
|---|---|---|
| n | <leader> - |
Split window horizontal |
| n | <leader> | |
Split window vertical |
| n | <leader> wd |
Delete window: Close the current window |
| n | <leader> ww |
Other window |
| n | <C-h> |
Go to left window |
| n | <C-j> |
Go to lower window |
| n | <C-k> |
Go to upper window |
| n | <C-l> |
Go to right window |
| Mode | Input | Action |
|---|---|---|
| n | <S-H> |
Previous buffer (left) |
| n | <S-L> |
Next buffer (right) |
| n | <leader> fb |
Buffers |
| n | <leader> be |
Buffer explorer |
| n | <leader> bd |
Delete buffer: Close the current buffer |
| n | <leader> bl |
Delete buffers to the left |
| n | <leader> br |
Delete buffers to the right |
| n | <leader> bo |
Delete other buffers |
| n | <leader> fr |
Recent |
| n | <leader> fR |
Recent cwd |
| Mode | Input | Action |
|---|---|---|
| inv | <S-Up> |
Move one screen backward (page up) |
| inv | <S-Down> |
Move one screen forward (page down) |
| nv | zt |
Redraw current line at top of window |
| nv | zz |
Redraw current line at center of window |
| nv | zb |
Redraw current line at bottom of window |
| nv | zH |
Scroll screen half a screen width to the right |
| nv | zL |
Scroll screen half a screen width to the left |
| Mode | Input | Action |
|---|---|---|
| nv | h |
Move left |
| nv | j |
Move down |
| nv | k |
Move up |
| nv | l |
Move right |
| nv | b |
Previous word |
| nv | w |
Next word |
| nv | e |
Next end of word |
| nv | 0 |
First character in line |
| nv | ^ |
First non-blank character in line |
| nv | $ |
End of line |
| nv | { |
Previous empty line |
| nv | } |
Next empty line |
| nv | % |
Find next brace or bracket on the current line, and go to its match |
| nv | gM |
Goto middle of line |
| nv | gg |
Goto first line, beginning of document |
| nv | G |
Goto last line, end of document |
| nv | [number]gg |
Goto line number (also works with [number]G) |
| nv | [number]% |
Goto line at number percentage (as in 25%, 50%, or 100%) |
| n | <leader> ss |
Goto symbol |
| n | <leader> sS |
Goto symbol (Workspace) |
| n | <leader> sw |
Word (root directory) |
| n | <leader> sW |
Word (cwd) |
| n | gd |
Goto definition |
| n | gD |
Goto declaration |
| n | gI |
Goto implementation |
| n | gy |
Goto type definition |
| n | gr |
References |
| n | ]] |
Next reference |
| n | [[ |
Previous reference |
| n | K |
Hover |
| Mode | Input | Action |
|---|---|---|
| n | i |
Insert text before the cursor |
| n | I |
Insert text before first non-blank character |
| n | a |
Append text after the cursor |
| n | A |
Append text at end of line |
| n | o |
New line below the current line |
| n | O |
New line above the current line |
| n | x |
Delete character |
| n | dw |
Delete word |
| n | dd |
Delete current line |
| n | D |
Delete to end of line |
| n | dG |
Delete to end of file |
| n | dgg |
Delete to beginning of file |
| n | r |
Replace character |
| n | R |
Replace mode |
| n | u |
Undo |
| n | <C-r> |
Redo |
| inv | <OPTION-j> |
Move line down |
| inv | <OPTION-k> |
Move line up |
| nv | J |
Join lines (with next line, or highlighted lines) |
| v | gc |
Comment (multiple lines with number gc) |
| n | gco |
Comment below the current line |
| n | gcO |
Comment above the current line |
| v | > |
Indent |
| v | < |
Outdent |
| nv | <leader> ca |
Code action |
| n | <leader> cA |
Source action |
| n | <leader> co |
Organize imports |
| n | <leader> cM |
Add missing imports |
| n | <leader> cu |
Remove unused imports |
| nv | <leader> cf |
Format |
| n | <leader> cr |
Rename |
| n | <leader> cR |
Rename file |
| n | <leader> cp |
Markdown preview |
| n | <leader> uf |
Toggle auto format (Global) |
| n | <leader> uF |
Toggle auto format (Buffer) |
| n | <leader> us |
Toggle spelling |
| n | <leader> uw |
Toggle word wrap |
| n | <leader> ul |
Toggle line numbers |
| n | <leader> uL |
Toggle relative line numbers |
| nv | <C-n> |
Autocompletion select from dropdown |
| inxs | <C-c> |
Exit insert mode |
| inxs | <C-s> |
Save file |
| n | <leader> fn |
New file |
| Mode | Input | Action |
|---|---|---|
| v | v |
Enter visual mode, followed by vim movement (examples: v$, v^, or v8j) |
| v | V |
Select line |
| v | ggVG |
Select all |
| v | viw |
Inner word (select word) |
| v | vib |
Inner block (select block) |
| v | vit |
Inner tag block |
| v | vi" |
Inner quotes (select everything inside of " quotes) |
| v | vi{ |
Inner braces (select everything inside of {} braces) |
| v | vi[ |
Inner brackets (select everything inside of [] brackets) |
| v | vaw |
Outer word (select word) |
| v | vab |
Outer block (select block) |
| v | vat |
Outer tag block |
| v | va" |
Outer quotes (select everything including " quotes) |
| v | va{ |
Outer braces (select everything including {} braces) |
| v | va[ |
Outer brackets (select everything including [] brackets) |
| v | vt{char} |
Select until character (exclusive) |
| v | vf{char} |
Select until and including character (inclusive) |
| v | vT{char} |
Select backwards until character (exclusive) |
| v | vF{char} |
Select backwards until and including character (inclusive) |
| Mode | Input | Action |
|---|---|---|
| nv | y |
Yank into register (copy) |
| nv | yy |
Yank current line into register (copy, also mapped as <S-Y) |
| nv | y$ |
Yank from cursor to end of line register (copy) |
| nv | y^ |
Yank from cursor to first non-blank character of line (copy) |
| nv | d |
Delete (cut) |
| nv | dd |
Delete current line (cut) |
| nv | p |
Put register after cursor |
| nv | P |
Put register before cursor |
| nv | gp |
Put register after selection |
| nv | gP |
Put register before selection |
| nv | yiw |
Yank inner word (copy word) |
| nv | diw |
Delete inner word (delete word) |
| Mode | Input | Action |
|---|---|---|
| n | /pattern |
Search forward for pattern |
| n | ?pattern |
Search backward for pattern |
| n | n |
Go to next search match |
| n | N |
Go to previous search match |
| n | * |
Search forward for word under cursor |
| n | # |
Search backward for word under cursor |
| n | /<Enter> |
Repeat last search |
| n | /<C-r><C-w> |
Put word under cursor into search prompt |
| n | :nohl |
Clear search highlighting |
| n | <C-u> |
Clear search line from cursor to beginning |
| n | <leader> ff |
Find files from root directory (also: <leader><leader> |
| n | <leader> fF |
Find files from current working directory |
| n | <leader> fr |
Find recent files |
| n | <leader> fR |
Find recent files (cwd) |
| n | <leader> sg |
Live grep: search in all files |
| n | <leader> sG |
Live grep: search in cwd |
| n | s |
Flash: search window, use labels to jump to any location |
| n | :s/old/new/g |
Substitute old with new in current line |
| n | :%s/old/new/g |
Substitute old with new in entire file |
| Mode | Input | Action |
|---|---|---|
| n | <leader> rb |
Extract block |
| n | <leader> rf |
Extract block to file |
| v | <leader> rf |
Extract function |
| v | <leader> rR |
Extract function to file |
| v | <leader> rx |
Extract variable |
| nv | <leader> ri |
Inline variable |
| nv | <leader> rp |
Debug print variable |
| v | <leader> rs |
Refactor |
| n | <leader> rP |
Debug print |
| n | <leader> rc |
Debug cleanup |
| Mode | Input | Action |
|---|---|---|
| n | <leader> st |
Todos: All todos in the workspace |
| n | <leader> xt |
Todo (Trouble) |
| n | <leader> xT |
Todo (Telescope) |
| n | [t |
Previous Todo |
| n | ]t |
Next Todo |
| Mode | Input | Action |
|---|---|---|
| n | zc |
Close one fold under the cursor |
| n | zC |
Close all folds under the cursor |
| n | zm |
Fold more |
| n | zM |
Close all folds |
| n | zo |
Open one fold under the cursor |
| n | zO |
Open all folds under the cursor |
| n | zr |
Reduce folding |
| n | zR |
Open all folds |
| Mode | Input | Action |
|---|---|---|
| n | <leader> e |
Open file system tree sidebar |
| n | <CR> |
Open directory or file |
| n | <C-v> |
Open file in vertical split |
| n | <c-s> |
Open file in horizontal split |
| n | <C-t> |
Open terminal at path |
| n | a |
Add file |
| n | d |
Delete file |
| n | P |
Preview file |
| n | H |
Toggle hidden files |
| Mode | Input | Action |
|---|---|---|
| n | <leader> xx |
Diagnostics: error list |
| n | <leader> xX |
Buffer diagnostics: error list |
| n | <leader> sq |
Quickfix list |
| n | <leader> xq |
Quickfix list |
| Mode | Input | Action |
|---|---|---|
| n | <leader> gg |
Lazygit |
| n | <leader> gG |
Lazygit (cwd) |
| n | <leader> gl |
Git log |
| n | <leader> gL |
Git log (cwd) |
| n | <leader> gd |
Git diff (hunks) |
| n | <leader> gf |
Git current file history |
| n | <leader> gS |
Git stash |
| n | <leader> gb |
Git blame line |
| n | <leader> gB |
Open repo in the browser |
| n | <leader> fg |
Find git files |
| Mode | Input | Action |
|---|---|---|
| nv | <leader> a |
Copilot |
| nv | <leader> aa |
Toggle Copilot chat |
| nv | <leader> ad |
Diagnostic help |
| nv | <leader> ap |
Prompt actions |
| nv | <leader> aq |
Quick chat |
| nv | <leader> ax |
Clear chat |
| n | :Copilot enable |
Enable Copilot |
| n | :Copilot disable |
Disable Copilot |
| Mode | Input | Action |
|---|---|---|
| n | <C-g> |
Show current file name with path |
| n | ga |
Show ascii value of character under cursor |
| n | g8 |
Show utf-8 encoding byte sequence of character under cursor |
| n | g<C-G> |
Show cursor column, line, word, and byte position |
| Mode | Input | Action |
|---|---|---|
| n | <leader> ft |
Terminal (root dir) |
| n | <leader> fT |
Terminal (cwd) |
| n | <C-/> |
Toggle terminal |
| t | <C-\> <C-n> |
Exit terminal mode |
| t | <esc><esc> |
Enter normal mode |
| t | <C-c> |
Send SIGINT |
| Mode | Input | Action |
|---|---|---|
| n | <leader> ni |
Install a new dependency |
| n | <leader> nu |
Update dependency on line |
| n | <leader> nc |
Install different dependency version |
| n | <leader> nd |
Delete dependency on line |
| n | <leader> nh |
Hide dependency versions |
| n | <leader> ns |
Show dependency versions |
| n | <leader> nt |
Toggle dependency versions |
| n | <leader> nr |
Run npm script |
| Input | Action |
|---|---|
| : | Command line mode |
<leader> sC |
Commands |
<leader> : |
Command history |
<C-u> |
Clear command line from cursor to beginning |
<C-w> |
Delete word in front of the cursor |
<C-k> |
Enter digraph |
| Input | Action |
|---|---|
q |
Quit Lazygit |
<Esc> |
Cancel/go back |
<Tab> |
Switch between panels |
<Shift-Tab> |
Switch between panels (reverse) |
j / <Down> |
Move down in current panel |
k / <Up> |
Move up in current panel |
] |
Next tab |
[ |
Previous tab |
, |
Previous page |
. |
Next page |
< |
Scroll to top |
> |
Scroll to bottom |
<Shift+Down> |
Range select down |
<Shift+Up> |
Range select up |
<Enter> |
Confirm selection/open item |
0 |
Focus main view |
1 |
Go to files panel |
2 |
Go to branches panel |
3 |
Go to commits panel |
4 |
Go to stash panel |
5 |
Go to remote panel (if available) |
| Input | Action |
|---|---|
<Space> |
Stage/unstage file |
<Enter> |
Stage lines / Collapse directory |
a |
Stage/unstage all files |
d |
Discard |
D |
Reset |
g |
View upstream reset options |
c |
Commit |
A |
Ammend last commit |
e |
Edit file |
o |
Open file |
i |
Add file to .gitignore |
r |
Refresh files |
s |
Stash all changes |
S |
View stash options |
y |
Copy to clipboard |
<Ctrl-o> |
Copy path to clipboard |
<Ctrl-b> |
Filter files by status |
<Ctrl-f> |
Find base commit for fixup |
| Input | Action |
|---|---|
c |
Commit staged changes |
C |
Commit using git editor |
A |
Ammend last commit |
<Ctrl-c> |
Close commit message panel |
<Enter> |
Confirm commit (in commit message panel) |
| Input | Action |
|---|---|
<Space> |
Checkout branch |
c |
Checkout branch by name |
- |
Checkout previous branch |
F |
Force checkout branch |
n |
Create new branch |
d |
Delete branch |
D |
Force delete branch |
r |
Rebase branch |
R |
Rename branch |
M |
Merge branch |
f |
Fast-forward branch |
g |
View reset options |
u |
Set upstream branch |
o |
Create pull request |
O |
Create pull request options... |
T |
New tag |
s |
Sort order... |
g |
Reset |
u |
View upstream options... |
<Ctrl-y> |
Copy pull request URL to clipboard |
<Ctrl-o> |
Copy branch name to clipboard |
<Enter> |
View Commits |
| Input | Action |
|---|---|
<Space> |
Checkout commit |
<Enter> |
View commit files |
c |
Copy commit hash |
C |
Copy (cherry pick) |
r |
Reword commit |
R |
Rebase with editor |
e |
Edit (start interactive rebase) |
f |
Fixup commit |
F |
Create fixup commit |
S |
Apply fixup commits... |
s |
Squash commit |
d |
Drop commit |
D |
Delete commit |
p |
Pick (while rebasing) |
B |
Base as base commit for rebase |
<Ctrl-r> |
Cherry-pick commit |
<Ctrl-f> |
Reset copied (cherry-picked) commits selection |
<Ctrl-o> |
Copy commit has to clipboard |
<Ctrl-j> |
Move commit down one |
<Ctrl-k> |
Move commit up one |
<Ctrl-l> |
View log options... |
t |
Revert commit |
T |
Tag commit |
b |
View bisect options |
n |
Create new branch off of commit |
g |
Reset... |
| Input | Action |
|---|---|
<Space> |
Apply stash |
g |
Pop stash |
d |
Drop stash |
n |
Create new stash |
r |
Rename stash |
| Input | Action |
|---|---|
p |
Push to remote |
P |
Pull from remote |
f |
Fetch from remote |
<Ctrl-p> |
Push with force |
| Input | Action |
|---|---|
<Ctrl-r> |
Recent repositories |
<Ctrl-s> |
View filter-by-path options |
<Ctrl-w> |
Toggle ignore whitespace |
w |
View worktree options |
z |
Undo last action |
<Ctrl-z> |
Redo last action |
+ |
Next screen mode |
_ |
Previous screen mode |
: |
Execute custom command |
R |
Refresh all |
} |
Increase diff context size |
{ |
Decrease diff context size |
| Input | Action |
|---|---|
/ |
Start search in current panel |
<Esc> |
Clear search |
n |
Next search result |
N |
Previous search result |
Configuration for TMUX, terminal multiplexer.
TMUX key mapping, based on macOS.
Prefix: <CONTROL-b>
| Input | Action |
|---|---|
<prefix> c |
Create window |
<prefix> n |
Next window |
<prefix> p |
Previous window |
<prefix> 0 |
Select window 0 (or enter window number) |
<prefix> , |
Rename window |
<prefix> w |
List windows |
<prefix> % |
Split window vertically |
<prefix> " |
Split window horizontally |
<prefix> m |
Toggle window maximize |
<prefix> z |
Toggle pane zoom |
<prefix> Arrow |
Cycle window focus in direction |
<prefix> d |
Detach from session |
<prefix> s |
List sessions |
<prefix> q |
Show window numbers |
<prefix> & |
Kill window |
<prefix> x |
Kill pane |
<prefix> <CMD-Arrow> |
Resize pane in direction |
<prefix> I |
Install plugins |