
Way to store your dotfiles: A bare Git repository (2016) - pcr910303
https://www.atlassian.com/git/tutorials/dotfiles
======
minaguib
I use something even simpler

My dotfiles git repo is meant to be cloned in my home directory. It comes with
this .gitignore committed in the repo:

    
    
      /*
      !/.vim/
      /.vim/.netrwhist
    

Basically it ignores everything in my home directory, unless I explicitly `git
add` it, which matches my workflow. For the few cases where I want to notice
changes (like the entire ~/.vim/ subdirectory), I explicitly un-ignore it as
you can see above.

The only downside I've experienced is my bash PS1 prompt shows the status of
the dotfiles repo (branch/dirty/etc) in any directory I'm in that's inside my
home dir - I've learnt to ignore it, and it doesn't interfere with CDing into
an actual directory that's its own git repo.

~~~
wrs
I think that method requires git to scan all the files in the directory so it
can then ignore them. The advantage of the “showUntrackedFiles no” method is
that git will only look at the tracked files, which is much faster if you have
a million files in your home dir, like I do. (Or so I believe.)

~~~
jaytaylor
I tried quickly looking into this to verify the claim, but haven't yet found
anything to explain why this would be the case. Do you have any details about
how or why git will scan everything in this case?

I did find a pretty neat stack overflow post on the subject of gitignore
whitelisting [0]. If we can get to the bottom of possible performance impact,
would be cool to add the info there.

[0]
[https://stackoverflow.com/a/15320746/293064](https://stackoverflow.com/a/15320746/293064)

~~~
minaguib
Without spending too much time on it, I think a cursory check shows git doing
"the smart thing" with ignore rules.

    
    
      $ mkdir foo
      $ cd foo
      $ mkdir $(seq 1 1000)
      $ git init .
      $ strace -c git status
        On branch master
    
        No commits yet
    
        nothing to commit (create/copy files and use "git add" to track)
        % time     seconds  usecs/call     calls    errors syscall
        ------ ----------- ----------- --------- --------- ----------------
         75.97    0.058830          57      1035        15 openat
         16.48    0.012764           6      2002           getdents
          3.87    0.002999           3      1021           close
          2.91    0.002254           2      1022           fstat
          0.19    0.000147           8        18        14 lstat
          0.13    0.000100           4        24           read
          0.12    0.000092           6        16        12 stat
          0.09    0.000072           3        21        14 access
          0.06    0.000048          10         5           write
          0.04    0.000033          33         1           unlink
          0.03    0.000020           3         8           rt_sigaction
          0.02    0.000018           2        12           mprotect
          0.02    0.000015          15         1           munmap
          0.01    0.000010           3         4           getcwd
          0.01    0.000006           0        16           mmap
          0.01    0.000006           6         1           ioctl
          0.01    0.000005           2         3           brk
          0.01    0.000004           4         1           chdir
          0.00    0.000003           2         2           getpid
          0.00    0.000003           3         1         1 readlink
          0.00    0.000002           1         2           rt_sigprocmask
          0.00    0.000002           2         1           set_tid_address
          0.00    0.000002           2         1           set_robust_list
          0.00    0.000002           2         1           prlimit64
          0.00    0.000000           0         1           execve
          0.00    0.000000           0         1           arch_prctl
        ------ ----------- ----------- --------- --------- ----------------
        100.00    0.077437                  5221        56 total
    

Now let's add an ignore-all and check:

    
    
      $ echo "/*" > .gitignore
      $ strace -c git status
        On branch master
    
        No commits yet
    
        nothing to commit (create/copy files and use "git add" to track)
        % time     seconds  usecs/call     calls    errors syscall
        ------ ----------- ----------- --------- --------- ----------------
         46.25    0.000568         284         2           getdents
         16.78    0.000206           6        35        14 openat
          7.41    0.000091           6        16        12 stat
          7.17    0.000088           4        21        14 access
          5.62    0.000069           3        25           read
          4.72    0.000058           3        18        14 lstat
          4.15    0.000051           2        22           close
          2.93    0.000036          36         1           unlink
          2.28    0.000028           1        23           fstat
          0.81    0.000010           3         4           getcwd
          0.65    0.000008           1         8           rt_sigaction
          0.41    0.000005           5         1           ioctl
          0.33    0.000004           4         1           chdir
          0.24    0.000003           2         2           getpid
          0.24    0.000003           3         1         1 readlink
          0.00    0.000000           0         5           write
          0.00    0.000000           0        16           mmap
          0.00    0.000000           0        12           mprotect
          0.00    0.000000           0         1           munmap
          0.00    0.000000           0         3           brk
          0.00    0.000000           0         2           rt_sigprocmask
          0.00    0.000000           0         1           execve
          0.00    0.000000           0         1           arch_prctl
          0.00    0.000000           0         1           set_tid_address
          0.00    0.000000           0         1           set_robust_list
          0.00    0.000000           0         1           prlimit64
        ------ ----------- ----------- --------- --------- ----------------
        100.00    0.001228                   224        55 total

------
syoc
I don't understand how the curl [http://site.com](http://site.com) | bash
anti-pattern has become so widespread. Especially with -k.

~~~
BluSyn
It originated as a way for people who aren't familiar with CLI to install
things. People have now been trained to expect this level of simplicity. I've
worked with people that will blindly copy and paste these lines into
terminals, having absolutely no idea what they do, and even blindly type in
sudo password when prompted. It's basically the worst of all worlds from a
security perspective. In my opinion this should be burned to the ground.

Normally when I see this I will manually download the bash script, read
through exactly what it does, and manually type in each command instead of
running the script directly. This way I know what it is doing, and it can't
hide command output by piping into /dev/null and doing something without my
knowledge.

Seriously people. Never. Trust. Bash Scripts.

~~~
type0
There's these cautionary tale you might find interesting

[https://www.vidarholen.net/contents/blog/?p=746](https://www.vidarholen.net/contents/blog/?p=746)

and seriously just Shellcheck it should be in your repos.

------
shreyansh_k
It's fair to say that the technique described by SneakyCobra is amazing. I
previously used this to manage my own dotfiles but there's still a few
problems with SneakyCobra's approach.

* initial setup can be tricky even for experienced users * Incorrect use can potentially destroy your home directory

So, I wrote a little utility call "SDF: Sane dotfile manager" that makes the
technique used by SneakyCobra approachable to a complete novice and hence more
reliable to use.

You can find the introductory text here ([https://shreyanshja.in/blog/sane-
dotfiles-management/](https://shreyanshja.in/blog/sane-dotfiles-management/))
And the source code here
([https://github.com/shreyanshk/sdf](https://github.com/shreyanshk/sdf))

Let me know how it works for you. :-)

------
mikewhy
Seems much more complicated compared to:

    
    
        git checkout https://github.com/my/dotfiles.git
        cd dotfiles
        # this is little more than `find . -maxdepth 1 -exec ln -sf {} ~/ \;`
        ./install
    

How are others here managing their dotfiles?

~~~
sametmax
I use stow. But honestly, I don't think it's better than git.

~~~
yjftsjthsd-h
It's orthogonal, isn't it? You keep your dotfiles in a repo, then have stow
"install" the checkout/clone thereof.

EDIT: Also on stow - I tried it a couple times and it never seemed flexible
enough. Can it handle things like keeping ~/.config/nvim and ~/.vim in the
same stow directory? (And for that matter, can it link them together? I like
having the same config for vim and neovim)

~~~
th3ant
Re: your edit, Yeah it can! Set up a folder, say 'vim' for your example, and
then inside of that folder you have a '.vim' file and a '.config/nvim' file.

Then when you run `stow vim` from the parent of the original 'vim' folder it
will symlink everything in there to ~.

You can even have more folders that have a '.config/foobar' inside of them,
and when you stow those it will all work itself out nicely!

Edit: You can find examples of this in my dotfiles
[https://github.com/AnthonyWharton/dotfiles/](https://github.com/AnthonyWharton/dotfiles/)
(I use stow if you didn't guess :P). For example look at the 'i3' folder and
the 'polybar' folder, they both add things to '~/.config '

------
lwhsiao
I'm still looking for a good way to I'm using this approach, but looking for a
way manage dotfiles for multiple machines. Having separate branches feels
clunky, since there is a lot of overlap and tweak may involve making the same
tweak on several branches. Any recommendations for managing this situation?

~~~
gkmcd
Surprised nobody has mentioned YADM - it can do per-device files and/or per-
device templating too (jinja2 syntax). It's just a thin wrapper around git so
you can use any git commands too.

[http://yadm.io](http://yadm.io)

~~~
thingfox
There's nothing really to gain from using git directly. Yadm is awesome.

I put up my dotfiles here
[https://github.com/thingfox/dotfiles](https://github.com/thingfox/dotfiles)
(sample documentation repository with examples), in it I show how I did the
templating for ssh hosts amongst other configs.

This allows me to remove the most sensitive data and use the
[https://yadm.io/docs/encryption](https://yadm.io/docs/encryption) option for
that.

The [https://yadm.io/docs/bootstrap](https://yadm.io/docs/bootstrap) feature
is also awesome as is
[https://yadm.io/docs/alternates](https://yadm.io/docs/alternates)

------
santadakota
I just use vcsh combined with (optionally) myrepos to handle this.

[https://github.com/RichiH/vcsh](https://github.com/RichiH/vcsh)

[https://myrepos.branchable.com/](https://myrepos.branchable.com/)

------
hectorm
I use exactly the same approach but for convenience I use the following script
as wrapper for git:
[https://gist.github.com/hectorm/8891f7f1916a4379f84dfaccc6fa...](https://gist.github.com/hectorm/8891f7f1916a4379f84dfaccc6fa117f)

------
pmoriarty
The problem with keeping all dotfiles in a single repo is that if you want to
get an older version of one particular dotfile, you'll also be getting older
versions of other dotfiles as well.

I want every dotfile I use to be independent of the rest and a log that shows
changes to just that one dotfile, so I store each of them in separate repos
and use GNU Stow[1] to manage them.

The above is actually a bit of an oversimplification of what I do, as I store
related dotfiles in a single repo as well, so that (for example) all my
weechat dotfiles are in a single repo, as I rarely want to checkout a single
file independantly of the rest there.

[1] = [https://www.gnu.org/software/stow/](https://www.gnu.org/software/stow/)

~~~
benley
> you want to get an older version of one particular dotfile, you'll also be
> getting older versions of other dotfiles as well.

That doesn't really follow; it is easy to check out old versions of a single
file with git:

    
    
        git checkout <revision> <filename>
    

for ".bashrc from two commits ago on the current branch", that would be:

    
    
        git checkout HEAD~2 .bashrc
    

Hopefully I'm not just misunderstanding your point here.

------
sam_lowry_
You need just 3 lines to start storing your dotfiles in git:

    
    
        cd ~
        git init
        echo "*" >.git/info/exclude
    

Enjoy!

~~~
arunix
Could you explain how this works/is meant to work?

~~~
agazso
You basically make your home dir a git repo and by default ignore everything
inside it. When you want to store a dotfile in that repo, you have to force
add it (`git add -f`) and it will be tracked.

You can learn more about how git ignores things here: [https://git-
scm.com/docs/gitignore](https://git-scm.com/docs/gitignore)

------
personjerry
This could lead to a potential security issue. Imagine there's a
misconfiguration in your dotfiles -- now it's public.

~~~
dewey
There's a lot of dotfiles on Github and it doesn't seem to be a problem
(Except if you check in private credentials, but that's not a problem unique
to dotfiles).

If you rely on your configuration to be secret to be secure it's just security
by obscurity and not worth much anyway.

~~~
personjerry
> If you rely on your configuration to be secret to be secure it's just
> security by obscurity and not worth much anyway.

What I had in mind is that the average person wouldn't be a target, but
publicly declaring their security vulnerability would attract attacks they
wouldn't receive otherwise.

~~~
intertextuality
Only key harvester bots on GitHub/etc would notice. If you’re being
consciously attacked by someone then you have bigger problems to deal with.

The solution isn’t particularly hard either, simply source a secrets file and
make sure you add that to the gitignore file.

