Dotfiles in git

Mit wachsender Anzahl potentieller Arbeitscomputer in verschiedenen (Uni) Systemen und auf meinen eigenen Computern, wurde das  aktuell halten meiner Konfigurationsdaten auf allen Systemen langsam etwas aufwendig. Die Lösung für dieses Problem wurde schon von diversen Personen vor mir genutzt, dennoch hat mein Ansatz einige Besonderheiten, welche ich hier ausführen möchte.
Die Grundidee ist einfach, git als Werkzeug der Synchronisierung nutzen und alle Dateien mittels ln als Links an den erwarteten Stellen verlinken.
Der entscheidende Punkt ist nun, wie man die Links möglichst bequem anlegt und dies auf beliebig vielen Systemen installieren kann.

  1. In einem Skript einfach X Zeilen der Form ln -s $quelle $ziel nutzen, unbequem zu pflegen und unflexibel.
  2. Mit einer Schleife ln für jede Datei in einem Ordner aufrufen, bequem, aber unflexibel
  3. Listen als Quelle für ln nutzen, etwas aufwand in der Pflege, dafür aber sehr flexibel
    Meine Lösung gehört offensichtlich in die 3. Kategorie, dabei kommen auf jedem Host 3 Listen zum Einsatz.
    files enthält alle Dateien, welche ich auf allen Computern nutzen möchte$HOSTNAME enthält Dateien, welche ich speziell auf diesem System haben möchte."$HOSTNAME"-not enthält Dateien, welche eigentlich in der Liste stehen, dennoch auf diesem System nicht installiert werden sollen.Da die Listen alle eigene Dateien sind, lassen sie sich auch ohne Editor erweitern.Die allgemeine Logik, wie mit der Liste umgegangen wird, stammt aus onthoughtbots dotfiles, meine derzeitige Version gibt es hier oder zum lesen jetzt auch einfach im Anschluss
=1: #!/bin/bash
=2: 
=3: #read content of files to decide, which files should be installed
=4: #files contains files for all hosts
=5: #$HOSTNAME contains host specific files
=6: #$HOSTNAME-not contains files excluded for this host, 
=7: #overwrites everything else
=8: 
=9: DOTFILES="`cat files`"
10: 
11: 
12: **if** [ -f $HOSTNAME ]; **then**
13:   DOTFILES="$DOTFILES `cat $HOSTNAME`"
14: **else**
15:   touch $HOSTNAME
16: **fi**
17: 
18: **if** [ -f "$HOSTNAME"-not ]; **then**
19:   **if** [ -f $HOSTNAME ]; **then**
20:     DOTFILES=$(comm -3 cat files $HOSTNAME|sort) sort "$HOSTNAME"-not))
21:   **else**
22:     DOTFILES=$(comm -3 sort "files") sort "$HOSTNAME"-not))
23:   **fi**
24: **else**
25:   touch "$HOSTNAME"-not
26: **fi**
27: 
28: 
29: 
30: cutstring="DO NOT EDIT BELOW THIS LINE"
31: 
32: **for** name **in** $DOTFILES; **do**
33:   target="$HOME/.$name"
34:   #echo "trying to install $HOME/.$name"
35:   **if** [ -e "$target" ]; **then**
36:     **if** [ ! -L "$target" ]; **then**
37:       cutline=`grep -n -m1 "$cutstring" "$target" | sed "s/:.*//"`
38:       **if** [ -n "$cutline" ]; **then**
39:         cutline=$((cutline-1))
40:         echo "Updating $target"
41:         head -n $cutline "$target" > update_tmp
42:         startline=`sed '1!G;h;$!d' "$name" | grep -n -m1 "$cutstring" | sed "s/:.*//"`
43:         **if** [ -n "$startline" ]; **then**
44:           tail -n $startline "$name" >> update_tmp
45:         **else**
46:           cat "$name" >> update_tmp
47:         **fi**
48:         mv update_tmp "$target"
49:       **else**
50:         echo "WARNING: $target exists but is not a symlink."
51:       **fi**
52:     **fi**
53:   **else**
54:     **if** [ "$name" != 'install.sh' ]; **then**
55:       echo "Creating $target"
56:       **if** [ -n "$(grep "$cutstring" "$name")" ]; **then**
57:         cp "$PWD/$name" "$target"
58:       **else**
59:         ln -s "$PWD/$name" "$target"
60:       **fi**
61:     **fi**
62:   **fi**
63: **done**
64: 
65: