Skip to content

Instantly share code, notes, and snippets.

@ben-axnick
Created January 22, 2016 00:33
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ben-axnick/a0307d464b7534593eac to your computer and use it in GitHub Desktop.
Save ben-axnick/a0307d464b7534593eac to your computer and use it in GitHub Desktop.
How to manage dotfiles with YADM

Background

Solutions I've tried

  • Git repo directly checked out in home directory

    • Noisy
    • Have to ignore *, everything is a --force
    • Juggling machine variations is a pain
  • Homesick / Homeshick

    • Unreliable symlink behaviour, particularly with submodules
    • Getting files "into" homeshick a massive chore
    • Keeping synced painful
  • YADM

What I was looking for in a dotfile manager

  • Minimal dependencies
  • Runs without issue under OSX
  • Ability automatically encrypt/decrypt key files
  • Zero friction

What I didn't care about

  • Multiple repos
  • Sharing dotfiles

YADM

YADM is a fairly unknown project by a fairly unknown developer. Despite that, it's an excellent lightweight solution that checks off the boxes I care about.

The YADM philosophy is to get out of the way and let Git do what it does best.

What is it, exactly?

It's a bash script that wraps access to a git repository with a detached work tree. The purpose of the script is to allow you to execute git commands as though you were inside of the Git repository, wherever you happen to be.

It succeeds perfectly with one caveat in regards to git submodules.

Can I use my existing dotfiles?

Yes, so long as the structure of your repo is home-relative, you'll be fine. If you already have dotfiles in place that you manually copied/symlinked, you'll get some loud complaints during the cloning process, nothing that can't be fixed with a yadm checkout -f, just make sure you're not starting this process with unsaved changes that you'll lose!

To kick off the process, just do a:

yadm clone <url>

I personally use bitbucket as they provide free private repositories.

What about starting fresh?

This is well captured on the GH README. It's as simple as:

yadm init
yadm remote add origin <url>
yadm push -u origin master

I generally find it easier to create the repo and then clone it, rather than initializing it locally and pushing it up.

How do I keep up to date?

All the ways you usually do with git -

Pushing:

yadm add foo
yadm commit -av
yadm push

Pulling:

yadm pull --rebase origin master

What about submodules?

You need to actually be in your home directory for this.

yadm submodule add <url> path
yadm submodule update --init --recursive

How about encryption

This is the one area of special handling provided by YADM. It takes a list of files at ~/.yadm/encrypt. You encrypt a file by appending it to the file list and running a command:

echo ".home_relative_path/file" >> ~/.yadm/encrypt
yadm encrypt
yadm commit -av -m 'heres a list and a binary blob'
yadm push

You can get at your files again by:

yadm decrypt

All files are decrypted at once to their listed locations. The encryption itself is symmetric with a passphrase. Since your pushing this to a third party, pick a strong passphrase and/or ensure that the files themselves are protected from unauthorized usage (as is usually the case for ssh, gpg keys).

If you're planning on making your dotfiles public, you probably shouldn't use this feature at all, unless you like pitting the entire internet against your sensitive data.

Bonus: bootstrapping

Getting YADM itself can be a pain, since there's no Debian package. It is just a single script, so installing it manually isn't difficult, but you can also store a bootstrap script like the following in an accessible place:

OSX

if [[ "$OSTYPE" == "darwin"* ]]; then
  echo "Doing OSX install of yadm"

  # Brew can be fiddly, install separately:
  # ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  hash brew 2>/dev/null || (echo "install brew first" && exit 1)

  if hash yadm 2>/dev/null; then
    echo "yadm appears to be installed"
  else
    brew tap TheLocehiliosan/yadm
    brew update
    brew install git yadm
  fi
fi

Debian

if [[ "$OSTYPE" == "linux-gnu" ]]; then
  echo "Doing Debian install of yadm"

  if hash yadm 2>/dev/null; then
    echo "yadm appears to be installed"
  else
    echo "installing git"
    sudo apt-get install -y git

    echo "installing yadm"
    sudo apt-get install alien dpkg-dev debhelper build-essential

    VERSION="1.02-1"
    curl -fLO https://dl.bintray.com/thelocehiliosan/rpm/yadm-${VERSION}.noarch.rpm
    sudo alien -k yadm-${VERSION}.noarch.rpm
    sudo dpkg -i yadm_${VERSION}_all.deb
  fi
fi

# Have ensured that yadm is available
hash yadm 2>/dev/null || (echo "yadm install failed" && exit 1)

An aside: My bootstrapping solution

https://github.com/bentheax/dotfile-bootstrap

  • Uses Docker Compose and Docker Machine to run nginx on a server
  • Manually assigned DNS
  • Serves only http so no piping... Manually verify and then run, hope to eliminate this step eventually
  • Docker Machine is totally amazing for this personal-project use-case, very low maintenance and trivial to setup
Copy link

ghost commented May 12, 2017

if [[ "$OSTYPE" == "linux-gnu" ]] will return true for a lot non-Debian hosts as well. lsb_release -is will give you more fine-grained control (but will not cover OS X).
Anyway... thanks for the info. Never heard of YADM before. Gonna give it a shot.

@mnowotnik
Copy link

mnowotnik commented Nov 2, 2017

Nice writeup.
I have one suggestion:

You need to actually be in your home directory for this.

The prerequisite is only correct path. It's correct in the home directory or in any other directory if absolute path is used ( e.g., $PWD/path)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment