Dotfile 백업하고 관리하기 - GNU stow와 git
Dotfile이 뭐지?
리눅스에서는 모든 것이 텍스트다. 설정 파일도 그렇고 스크립트도 그렇다. 그래서 리눅스 생활을 하다보면, 텍스트 파일로 된 수 많은 설정 파일들을 건드리게 된다.
가령, 내 pc의 인터넷 연결은 다음과 같은 파일에 설정되어 있다.
[Match]
Name=eno2
[Network]
Address=192.168.252.111/24
Gateway=192.168.252.1
DNS=1.1.1.1시스템에 설치된 패키지 말고, 내가 직접 설치한 패키지들 (e.g. dwm, dmenu, rofi, kitty) 또한 텍스트 형태의 설정 파일을 사용한다.
리눅스 사용자들은 이들 설정 텍스트 파일을 dotfile이라고 부른다.
패키지들의 dotfile은 대개 $HOME/.config/<package_name>에 저장된다.
예외적으로 .bashrc나 .xinitrc의 경우처럼, $HOME에 dotfile을 저장하는 패키지도 있다.
Dotfile 백업은 rsync 보단 git
리눅스를 사용하다보면, 이런 dotfile들을 백업해두고 혹시나 PC가 고장나는 경우를 대비해야 한다는 생각이 든다. 물론, Rsync를 통한 리눅스 백업 시스템 구축에서 다룬 것처럼, rsync로 dotfile을 백업해도 된다.
그러나, 우리에게는 텍스트 기반 파일들을 관리하는데 더 적합한 툴인 git이 있다. git은 다음과 같은 기능을 가지고 있기 때문이다.
- Working tree로 과거 변화의 history를 기록해두기 때문에, 혹시나 config에 문제가 발생할 경우 손쉽게 roll back 할 수 있다.
- 원격 repository에 push 해둔다면, pc가 고장나더라도 다시 원격 repo로부터 이들을 내려받을 수 있다.
여러 경로에 흩어져 있는걸 하나의 git으로 관리하려면?: GNU stow
‘Dotfile이 뭐지?’에서 언급한 바와 같이, 일부 패키지들은 $HOME/.config이 아닌 다른 경로에 dotfile을 저장하기도 한다.
그러면, 각각의 경로마다 별도의 git repo를 관리해야할까?
아, 그건 너무 번거롭다. 한곳에 모아놓고, 단일 repo로 관리하는 것이 더욱 합리적이다. 이때 우리는 linux의 symlink를 사용하는 방법을 생각해볼 수 있다.
Symlink는 윈도우의 바로가기와 비슷한데, 좀 더 실제 파일처럼 다루는 방식이라고 생각하면 된다.
Symlink는 다음의 명령어를 통해 생성할 수 있다.
ln -s </path/to/file_or_directory> <path/to/symlink>우리는 symlink 파일을 사용하여 </path/to/file_or_directory>에 접근할 수 있게 되는 것이다.
이 symlink를 잘 활용하면, 모든 dotfile을 하나의 경로에 두고 관리할 수 있을 것 같지 않은가?
그러나, 이런 환경을 하나하나 symlink를 수동으로 만들고 관리하는 건 그것대로 문제를 내포하고 있다. dotfile이 한 수천개 된다면?
다행히, 이 문제를 해결해주는 패키지가 있다.
바로 stow다.
그럼, stow를 통해 수 많은 dotfile들의 symlink를 생성, 관리하는 방법을 알아보도록 하자.
stow의 설치와 기본 사용법
stow의 설치
우선 stow를 설치해주자.
# install stow
sudo pacman -S stowstow의 기본 사용법
실제 dotfile에 적용하기 전, 먼저 샘플을 만들어서 테스트를 해보도록 하자.
symlink 생성
$HOME에 stow_test 폴더를 생성하고, 임의의 config 파일을 만들어주자.
mkdir -p ~/stow_test/test # test는 내가 임의로 지정하는 패키지의 별명이다. 여기선 test로 지정했다.
touch ~/stow_test/test/sample.config그럼 다음 같은 형태로 파일 트리가 형성된다.
will@archlab:~/stow_test$ tree ~/stow_test
/home/will/stow_test
└─ test
└── sample.config자, 여기서 주목해야할 부분은 stow_test 폴더의 위치다.
이 폴더는 현재 $HOME에 있다.
우리는 이 위치를 root라고 부르겠다.
stow는 symlink를 생성할 때 바로 이 root를 기준으로 한다.
다음의 명령어를 실행하여 $HOME에 sample.config의 symlink를 생성해보자.
stow test결과는 다음 명령어로 확인하자.
ls -l ~/sample.config위 명령어는 이런 출력을 낸다.
lrwxrwxrwx 1 will will 28 Oct 9 13:11 sample.config -> stow_test/test/sample.config자, 이 출력은 이런 의미다.
root인
$HOME에 sample.config이라는 symlink 파일이 있는데, 이것의 실제 경로는stow_test/test/sample.config이다.
우리가 의도한대로, $HOME/stow_test/test에 있는 config 파일에 대해, root 경로인 $HOME에 symlink를 생성한 것을 확인할 수 있었다.
폴더를 포함한 symlink 생성
symlink 생성에서는 root 경로인 $HOME에 곧바로 config 파일의 symlink를 생성하는 예시였다.
이번엔 $HOME/dir-config이라는 경로를 생성하고 그 하부에 sample.config symlink를 생성해보자.
다음의 명령어를 통해 먼저 가상의 config 파일을 생성하자.
mkdir -p ~/stow_test/test2/dir-config
touch ~/stow_test/test2/dir-config/sample.config # test와 구분하기 위해 test2라고 별명을 지어줬다.그럼 다음 같은 형태로 파일 트리가 형성된다.
will@archlab:~/stow_test$ tree ~/stow_test
/home/will/stow_test
├── test
│ └── sample.config
└── test2
└── dir-config
└── sample.config자 그럼, 다음의 명령어로 test2에 대한 stow를 수행해보자.
stow test2결과는 다음 명령어로 확인하자.
ls -l ~/dir-config위 명령어는 이런 출력을 낸다.
lrwxrwxrwx 1 will will 26 Oct 9 13:27 /home/will/dir-config -> stow_test/test2/dir-config오! stow는 $HOME에 폴더까지 포함하여 symlink를 생성해주었다.
이 방식으로, 각 패키지 하에 좀 더 복잡한 디렉토리 구조를 가진 config 파일들을 symlink로 생성할 수 있다.
심지어, test2 경로 하에 다수의 폴더, 다층의 폴더, 그리고 다수의 config 파일들이 존재하더라도 다 처리할 수 있다.
symlink 제거
경우에 따라, 만들어둔 symlink를 제거해야할 때가 있다. 그럼, 앞서 만든 symlink들을 제거해보자. 이 작업은 symlink만 제거하고 원본은 그대로 유지한다.
stow -D test test2이렇게 동시에 test와 test2 모두의 symlink를 제거했다. (한 개씩 해도 무방하다.) 그러면, 다음의 명령어 결과에 아무것도 조회되지 않을 것이다.
ls -l ~/sample.config # test
ls -l ~/dir-config # test2결과는 이렇게 나온다.
ls: cannot access '/home/will/sample.config': No such file or directory
ls: cannot access '/home/will/dir-config': No such file or directorystow와 git으로 dotfile 관리 시스템 구축
지금부터 기존의 dotfile들을 stow와 git으로 관리하는 시스템을 구축해보자.
Dotfile용 git remote repo 생성, clone 하기
개인 github에서 dotfile 관리를 위한 repo를 생성해주자.
필자는 forgejo에서 repo를 생성했고, 다음 명령어로 clone 해주었다.
clone은 반드시 $HOME에서 수행해야 한다. (stow는 이 폴더의 바로 상위 폴더를 root로 사용한다.)
git clone ssh://git@192.168.100.10/will/.dotfiles.git이를 통해 생성된 git 폴더는 $HOME/.dotfiles이다.
백업할 dotfile들의 하부 폴더 생성하기
$HOME/.dotfiles에 백업할 패키지들의 폴더들을 생성해준다.
이름은 자유롭게, 개인이 알아볼 수 있도록 생성해주면 된다.
나는 다음처럼 하부 폴더들을 생성해줬다. (폴더명은 가능하면 패키지명과 일치시키되, 필요시 알아볼 수 있도록 postfix를 붙여줬다.)
will@archlab:~$ tree ~/.dotfiles
/home/will/.dotfiles
├── README.md # git의 README 파일
├── bash
├── btop
├── dunst
├── flameshot
├── i3
├── kitty
├── kmonad
├── lf
├── newsboat
├── nvim
├── pandoc
├── picom
├── polybar
├── qtile
├── ranger
├── scripts
├── suckless_archlab
├── suckless_common
├── sxhkd
├── xorg
├── yazi
└── zathura기존의 dotfiles mv하기
Warning
.config의 중요한 dotfile들이 유실되는 것을 방지하기 위해, .config 경로를 복제해둔 뒤 다음 절차들을 수행할 것을 강력히 권고함.
>> cp .config .config_backup
나는 총 23개 가량의 dotfile을 백업한다. 그래서 그냥 수작업으로, 경로를 생성하고 mv로 하나씩 옮겨줬다. 예를들어, 이렇게 옮긴단 말이다.
# kitty의 원래 경로를 생성하고, conf를 mv 함.
mkdir -p ~/.dotfiles/kitty/.config
mv ~/.config/kitty ~/.dotfiles/kitty/.config그러면 kitty 경로는 이렇게 구성되게 된다.
will@archlab:~$ tree -a -C ~/.dotfiles/kitty/
/home/will/.dotfiles/kitty/ # 관리를 위한 폴더 별명이 kitty
└── .config
└── kitty # 실제 kitty가 참조하게 될 폴더 이름이 kitty
├── current-theme.conf
├── kitty.conf
└── themes
├── diff-frappe.conf
├── diff-latte.conf
├── diff-macchiato.conf
├── diff-mocha.conf
├── frappe.conf
├── latte.conf
├── macchiato.conf
└── mocha.conf이 부분이 헷갈린다.
위의 kitty 예시에서 보면 $HOME/.dotfiles/kitty/ 폴더 하부에 다시 kitty 폴더가 등장한다.
이 둘은 다른 것이다.
앞의 kitty는 내가 stow로 관리하는 단위의 별명이고, 뒷 kitty는 실제 kitty가 참고하는 폴더의 이름이다.
(그러니까 앞의 kitty는 my-kitty-config처럼 다른 이름이라도 상관없으나, 뒷 경로는 반드시 원래 .config에 있는 이름으로 설정해야 한단 말이다.)
위와 같은 방식으로 모든 config들을 mv해주자. 그 수가 너무 많다면 chatGPT의 도움을 받아 쉘 스크립트를 작성하여 사용하자.
stow하기 (symlink 생성하기)
자, 모든 dotfile들이 원래 경로에서는 제거되었고, .dotfiles의 하부 경로에 위치하게 되었다. 혹시 모르니, 다시 한번 원래 경로에서 제거되었나 확인하자.
그리고나서, 다음 명령어를 통해 한 번에 모든 dotfile들의 symlink를 생성해주자.
# 반드시 .dotfiles에서 실행할 것
stow *모든 패키지들의 symlink가 필요없다면, 다음처럼 일부만 선택하여 symlink를 생성할 수도 있다.
# 반드시 .dotfiles에서 실행할 것
# 여기선 dwm, kitty, xorg, yazi, zathura만 생성
stow dwm kitty xorg yazi zathura결과 확인하기
자, 이제 $HOME/.config 경로를 보면, 이렇게 수많은 symlink가 생성된 것을 확인할 수 있다.
그리고 이들을 사용하는 패키지들은 마치 실제 dotfile이 .config 폴더에 존재하는 것처럼 잘 동작한다.
ls -l .config/will@archlab:~$ ls -l .config/
lrwxrwxrwx 1 will will 30 Oct 8 18:21 btop -> ../.dotfiles/btop/.config/btop
lrwxrwxrwx 1 will will 32 Oct 8 18:21 dunst -> ../.dotfiles/dunst/.config/dunst
lrwxrwxrwx 1 will will 34 Oct 8 18:21 dunstrc -> ../.dotfiles/dunst/.config/dunstrc
lrwxrwxrwx 1 will will 40 Oct 8 18:21 flameshot -> ../.dotfiles/flameshot/.config/flameshot
lrwxrwxrwx 1 will will 26 Oct 8 18:21 i3 -> ../.dotfiles/i3/.config/i3
drwx------ 3 will will 4096 Nov 27 2024 ibus
drwxr-x--x 13 will will 4096 Oct 8 19:16 inkscape
lrwxrwxrwx 1 will will 32 Oct 8 18:21 kitty -> ../.dotfiles/kitty/.config/kitty
-rw------- 1 will will 54 Jan 7 2025 kwalletrc
lrwxrwxrwx 1 will will 26 Oct 8 18:21 lf -> ../.dotfiles/lf/.config/lf
drwx------ 2 will will 4096 Aug 26 14:40 mpv
drwxr-xr-x 2 will will 4096 Nov 27 2024 neofetch
lrwxrwxrwx 1 will will 38 Oct 8 18:21 newsboat -> ../.dotfiles/newsboat/.config/newsboat
lrwxrwxrwx 1 will will 30 Oct 8 18:21 nvim -> ../.dotfiles/nvim/.config/nvim
drwx------ 15 will will 4096 Oct 8 22:25 obsidian
drwx------ 3 will will 4096 Feb 4 2025 pcmanfm
lrwxrwxrwx 1 will will 32 Oct 8 18:21 picom -> ../.dotfiles/picom/.config/picom
lrwxrwxrwx 1 will will 36 Oct 8 18:21 polybar -> ../.dotfiles/polybar/.config/polybar
lrwxrwxrwx 1 will will 32 Oct 8 18:21 qtile -> ../.dotfiles/qtile/.config/qtile
lrwxrwxrwx 1 will will 34 Oct 8 18:21 ranger -> ../.dotfiles/ranger/.config/ranger
lrwxrwxrwx 1 will will 49 Oct 9 10:55 suckless -> ../.dotfiles/suckless_archlab/.config/suckless
lrwxrwxrwx 1 will will 32 Oct 8 18:21 sxhkd -> ../.dotfiles/sxhkd/.config/sxhkd
lrwxrwxrwx 1 will will 33 Oct 8 18:21 themes -> ../.dotfiles/dunst/.config/themes
lrwxrwxrwx 1 will will 30 Oct 8 18:21 yazi -> ../.dotfiles/yazi/.config/yazi
lrwxrwxrwx 1 will will 36 Oct 8 18:21 zathura -> ../.dotfiles/zathura/.config/zathura지속적으로 관리하기
한번 symlink를 생성해주면, 우리가 할 일은 config이 바뀐 경우 git commit, git push 해주는 것 뿐이다.
혹시나, stow 내 앱의 폴더명(별명 말이다.)을 바꿔야 한다면, stow -D로 기존 링크를 제거하고 이름을 바꾼 뒤 다시 stow 해주면 된다.
마치며
오늘은 stow와 git을 통해, 텍스트 파일 기반의 dotfile들을 백업, 관리하는 시스템을 구축해봤다. 처음에 stow 개념이 굉장히 복잡해 보이지만, 한번 사용해보면 생각보다 훨씬 간단하게 동작하는 것을 알게 될 것이다.
그럼 유용하게 잘 활용해주시길…