Skip to content
Shell settings, trying to be shell agnostic, supporting Emacs Eshell, fish, bash and zsh.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.bin
.clojure
.config
.ctags.d
.gnupg
.hammerspoon
.images
.iterm2
.lein
.packages
.pip
.scripts
.terminfo/65
.vim/plugin
.aliases
.bash_profile
.bashrc
.closhrc
.env
.gemrc
.gitconfig
.gitignore_global
.irbrc
.minirc.dfl
.minttyrc
.npmrc
.tmux.conf
.vimrc
README.org
TODO.org
TODO.org_archive

README.org

Some dotfiles

This setup is mostly shell agnostic, supporting Eshell, fish, bash, and zsh.

In the past, I spent most of my time in fish. However, lately, as I transition more of my workflows to Emacs, I am using Eshell and rarely use a terminal outside of Emacs.

Most scripts are written in bash because it is the lowest common denominator and I’m twisted enough to think trying to write programs in pure bash is fun.

NOTE: The master repository is on GitLab but since most people use GitHub it has been cloned there. Feel free to create issues or pull requests on either (but I do prefer GitLab).

Tour

Applications & Utilities

Included are configurations for some programs, such as:

Fish Shell

Emacs

The Emacs config lives in its own repo, at https://gitlab.com/mnewt/dotemacs

Tmux

Vim / NeoVim

Install

This procedure will establish a git repository to hold dotfiles in $HOME/.config/repos/$repo, while pointing the workdir at $HOME. To make this function without causing problems, we will configure the repo to not show untracked files (since we don’t want to track most of what is under $HOME). Then we explicitly add just the files we want.

This is inspired by the bare repo technique outlined in Nicola Paolucci’s blog. However, it does not use a bare repo. Instead, it incorporates modications suggested by Jonas Bernoulli for use with Magit (but really this is the best way to do it even without Magit because it allows any git-based program to interact with the repo). This technique is deceptively simple and yet powerful enough to handle complex dotfile configurations with multiple repos. The beauty is that our dotfiles are in their proper locations and we explicitly choose which files to track and everything else is ignored by git. No symlinks, no duplication, no scripts to manage the repo.

Further, we can have multiple repos tracking different sets of files, all with their workdirs pointing to $HOME. I use this to merge my private settings with my public ones.

The Short Version

Set up a a local repo from an existing remote

We already have a repo and we know what we’re doing. No need to back anything up. Overwrite existing files.

curl 'https://gitlab.com/mnewt/dotfiles/raw/master/.scripts/bootstrap' | bash -s 'https://gitlab.com/mnewt/dotfiles.git'

Or on Windows:

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://gitlab.com/mnewt/dotfiles/raw/master/.scripts/bootstrap.ps1'))

The Long Version (discussing various scenarios)

If we want to set up a repo, we’ll want to consider how to transition from whatever is in place at the moment. Here are some basic plans for the main scenarios. To learn about the factors at play, follow along here.

STEP 1: Initialize or Clone

Choose one of the following.

Initialize a new repo

Create a repository locally.

mkdir -p $HOME/.config/repos
rm $HOME/.git # if necessary
git init --separate-git-dir $HOME/.config/repos/dotfiles $HOME

Clone an existing repo

Clone a remote repository.

git clone --separate-git-dir $HOME/.config/repos/dotfiles https://gitlab.com/mnewt/dotfiles.git --no-checkout $HOME/.config/repos/temp
mv $HOME/.config/repos/temp/.git $HOME
rm -rf $HOME/.config/repos/temp
git fetch
git reset --mixed HEAD

STEP 2: Configure the Repo

Now we need to configure the repo, regardless of whether we have initialized it anew or cloned a remote.

Don’t show untracked files

Configure the repo to not show untracked files since there will always be lots of stuff in $HOME that we don’t want in our repo.

env GITDIR=$HOME/.config/repos/dotfiles git config --local status.showUntrackedFiles no

Link the repo

The git-home-link function creates writes a .git file in $HOME pointing to one of the repos. By using this function, we can “activate” one of the repos such that we can use normal git comamnds in $HOME without specifying GITDIR.

Put this function in our .bashrc or similar (It’s in my .aliases file).

git-home-link () {
  # Link repo specified by $1 to $HOME using a .git file link
  if [ -n "$1" ] && [ -e "$HOME/.config/repos/$1" ]; then
    echo "gitdir: .config/repos/$1" >"$HOME/.git"
  else
    echo "repo \"$1\" not found in $HOME/.config/repos/"
    echo "ls $HOME/.config/repos/:"
    ls $HOME/.config/repos/
  fi
}

Start working

Now use the repo pretty much how we would a normal one. However, note that .git in $HOME is just a file pointing to the actual directory at $HOME/.config/repos/dotfiles. So before we use $HOME as a repo, link it. Then when we’re done, unlink it so we don’t accidentally commit something in a project subdirectory in the dotfiles repo.

Further, note that files will not be tracked by default. We must manually add each new file to the repo. Changes will be tracked. This is the only tricky part as it’s easy to overlook a file that should be part of the repo but is really just sitting in place, not tracked. The config will work on the local computer but when cloned to the next one things will be broken. This is really a feature though since we don’t ever want files to be added accidentally.

git-home-link dotfiles
git add .bashrc
git commit -m "add .bashrc to new dotfiles repo"
git push -u origin master
rm $HOME/.git

Working in Emacs

There are Emacs Lisp commands called git-home-link and git-home-unlink in init.el. They make it easy to work with this setup in git tools such as Magit, Projectile. Note that the Emacs config is in a separate repo at https://gitlab.com/mnewt/dotemacs.

STEP 3: Housekeeping

Before we start committing we need to make sure that we are not going to destroy what we have created.

Back up conflicting dotfiles

If there are conflicting files between the repo and the existing files in $HOME then the git reset above will not have populated all the files in the branch. So, back up the conflicting files.

modified=$(git diff --name-status | awk '/^M/{print $2}')
[ -n "$modified" ] && mkdir -p $HOME/.dotfiles-backup && cp -R $modified $HOME/.dotfiles-backup

Remove symlinks to the old repository

If we currently have symlinked dotfiles, let’s remove them. Here are two possible ways of cleaning up the links to the old repo. Let’s be careful though!

Delete the old repository, then delete orphaned symlinks
rm -rf $HOME/dotfiles
find -L $HOME -maxdepth 3 -type l -print
find -L $HOME -maxdepth 3 -type l -exec unlink -- "{}" \;
Delete all symlinks
# Find links that we may want to delete
find $HOME -maxdepth 1 -type l -print
# Maybe go deeper and do some additional filtering. This is what I did on my macOS setup:
find $HOME -maxdepth 3 -type l -not -path "$HOME/Library/*" -print
# Delete them
find $HOME -maxdepth 3 -type l -not -path $HOME/Library/*" -delete

Overwrite conflicting files

If there were conflicting files or links and we’ve taken care of them, reset hard to overwrite.

git reset --merge HEAD

git-home-link “$repo” for f in $(git ls-files); do rm “$f” dir=”$(dirname “$f”)” [ -z “$(ls -A “$dir”)” ] && rmdir “$dir” done rm -rf “$HOME/.config/repos/$repo”

Delete a repo and its files

To delete a repo and all its files:

repo="dotfiles"
git-home-link "$repo"
for f in $(git ls-files); do
  rm "$f"
  dir="$(dirname "$f")"
  [ -z "$(ls -A "$dir")" ] && rmdir "$dir"
done
rm -rf "$HOME/.config/repos/$repo"

Update scripts

There are set of update scripts in the bin directory to keep all the different software on a given system up to date.

These are some of the things that can be updated:

Arch Linux (pacman)

Atom Editor Packages

Clojure (Leiningen)

Debian/Ubuntu (apt)

Emacs (straight.el)

Fish Shell (fisher)

iTerm2 Shell Integration

macOS App Store

macOS Homebrew

macOS MacPorts

Node.js Packages

Python Packages

Ruby Gems

Tmux Packages (tpm)

Vim/Neovim Packages (vim-plug)

The master update script runs all of these in succession. Each script is smart enough to figure out whether the appropriate software is installed on the current machine.

Application Notes

Atom

Install atom, then run this to install packages

apm install --packages-file ~/.atom/packages.txt

To save the list of currently installed packages

apm list --bare --installed --dev false > ~/.atom/packages.txt

Emacs

On macOS, it seems the version of makeinfo is too old and causes problems with ivy. Install a newer version, then install Emacs, edit init.el and m-packages.el, launch emacs, and have fun.

brew install git ripgrep texinfo
brew link --force texinfo
brew install emacs --with-cocoa --with-imagemagick@6 --with-librsvg --with-mailutils

Fish

To install and switch our shell to fish on macOS:

brew install fish
chsh -s $(which fish)
fish -l
curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs https://git.io/fisher
fisher "$HOME/.config/fish_config" mnewt/fix

Vim

Install Vim or Neovim, edit .vimrc, then run update-vim to install packages.

update-vim

License

All the stuff in this repository is licensed to the public domain under the unlicense:

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to http://unlicense.org/

You can’t perform that action at this time.