Nix에서 Git 쉘 프롬프트 설정하기
최근에 Julia Evans의 git에 관한 최신 zine을 읽었는데, 그중 한 가지 팁은 터미널 쉘 프롬프트를 설정해 git 상태를 표시하는 것이었습니다.
Julia Evans의 터미널 프롬프트는 이렇게 생겼습니다.
main은 Julia Evans가 현재 작업 중인 git 브랜치입니다. bisect나 merge 같은 git 작업을 진행 중일 때는 터미널이 이렇게 바뀝니다.
쉘 프롬프트를 커스터마이즈할 생각은 한 번도 해본 적이 없었지만, 그 가치를 바로 알 수 있었습니다.
저는 현재 어떤 브랜치에 있는지 기억하려고 수시로 git status를 실행하고, git merge를 진행 중이라는 사실도 자주 잊어버립니다.
터미널에 git 프롬프트 설정하기
Julia Evans의 zine을 보고 터미널 쉘에 git 상태를 표시하도록 커스터마이즈해야겠다고 마음먹었지만, 방법을 바로 알기는 어려웠습니다. git-prompt.sh라는 파일이 필요하다는 것 같았는데, 제가 사용하는 Debian의 git 2.30.2에는 그 파일이 없었습니다.
$ find / -name 'git-prompt.sh' -type f -print
# No results다른 방법은 GitHub에서 git-prompt.sh의 공식 파일을 직접 다운로드하는 것이었습니다.
# Download git-prompt.sh
curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > ~/.git-prompt.sh
# Add it to my .bashrc
echo '. ~/.git-prompt.sh' >> ~/.bashrc
# Reload .bashrc
. ~/.bashrc제대로 동작하는지 테스트하기 위해 임시 git 저장소를 하나 만들었습니다.
mkdir examplerepo && \
cd examplerepo && \
git initgit-prompt.sh가 제대로 동작한다면 __git_ps1 명령어가 현재 git 브랜치를 표시해야 합니다.
$ __git_ps1
(master)좋습니다! 잘 동작합니다.
하지만 __git_ps1을 매번 수동으로 호출하고 싶지는 않았습니다. Julia Evans가 보여준 것처럼 브랜치가 터미널 프롬프트에 자동으로 나타나길 원했습니다.
터미널 쉘에서 git 상태를 표시하는 가장 간단한 방법은 bash 세션에서 PS1 변수를 덮어쓰는 것입니다.
$ export PS1='$(__git_ps1 "(%s)") \$ '
(master) $이제 git 명령어를 실행하면 터미널이 상태를 반영해 바뀝니다.
(master) $ echo 'hi' > hello.txt && git add -A && git commit -m "Test commit"
[master (root-commit) 7b14d2a] Test commit
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
(master) $ git checkout -b branchA && echo 'hey' > hello.txt && git add -A && git commit -m "test A"
Switched to a new branch 'branchA'
[branchA 65b3d63] test A
1 file changed, 1 insertion(+), 1 deletion(-)
(branchA) $ git checkout master
Switched to branch 'master'
(master) $ git checkout -b branchB && echo 'hello' > hello.txt && git add -A && git commit -m "test B"
Switched to a new branch 'branchB'
[branchB 198c875] test B
1 file changed, 1 insertion(+), 1 deletion(-)
(branchB) $ git merge branchA
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
(branchB|MERGING) $멋집니다, 잘 동작하는 것 같습니다.
하지만 쉘 프롬프트에서 작업 디렉터리가 보이지 않아 아쉬웠기 때문에 PS1을 이렇게 바꿨습니다.
$ export PS1='\w $(__git_ps1 "(%s)") \$ '
~/examplerepo (branchB|MERGING) $색상도 없어서 아쉬웠기 때문에 색상도 추가했습니다.
export PS1='\[\033[01;34m\]\w\[\033[00m\]\[\033[01;32m\]$(__git_ps1 " (%s)")\[\033[00m\]\$ '이 정도 되면 PS1 명령어를 직접 수정하는 것이 꽤 복잡해지므로, Bash Prompt Generator 같은 무료 도구를 이용해 명령어를 생성하고 색상을 추가하는 것을 추천합니다.
최종적으로 완성된 제 터미널 프롬프트는 이렇게 생겼습니다.
이 설정을 영구적으로 적용하기 위해 export PS1 라인을 ~/.bashrc 파일에 추가했고, 이제 bash 쉘을 시작할 때마다 커스텀 터미널을 사용할 수 있습니다.
Nix에서 bash 쉘 프롬프트에 git 연동하기
위 과정의 문제는 제가 Nix와 Home Manager를 사용한다는 점입니다. 편리하긴 하지만 bash 설정을 다루는 모든 과정이 더 복잡해집니다. .bashrc에 단순히 한 줄을 추가할 수 없는 이유도 Home Manager를 다음에 실행하면 제가 추가한 내용이 사라지기 때문입니다.
다행히 Jeff Kreeftmeijer의 글 덕분에 git-prompt.sh 솔루션을 Nix에 맞게 적용하는 방법을 이해할 수 있었습니다.
Home Manager용 home.nix 파일을 다음과 같이 수정했습니다.
programs.bash = {
enable = true;
enableCompletion = true;
initExtra = ''
# Load __git_ps1 bash command.
. ~/.nix-profile/share/git/contrib/completion/git-prompt.sh
# Also load git command completions for bash.
. ~/.nix-profile/share/git/contrib/completion/git-completion.bash
# Show git branch status in terminal shell.
export PS1='\[\033[01;34m\]\w\[\033[00m\]\[\033[01;32m\]$(__git_ps1 " (%s)")\[\033[00m\]\$ '
'';
};파일을 업데이트한 뒤 home-manager switch를 실행하자 .bashrc가 업데이트되었고, 모든 것이 예상대로 동작했습니다.
개발 환경에서 Nix 터미널의 불필요한 표시 제거하기
그래도 커스텀 bash 터미널 프롬프트에는 마지막으로 하나 더 손볼 부분이 남아 있었습니다.
저는 모든 개발 작업을 프로젝트별 Nix 쉘에서 진행합니다. nix develop으로 개발 환경을 불러오니 Nix가 터미널에 추가 접두사를 붙여 놓은 것을 볼 수 있었습니다.
~/examplerepo (branchB|MERGING) $ nix develop
...
(nix:nix-shell-env) ~/examplerepo (branchB|MERGING) $
^^^^^^^^^^^^^^^^^^^ why?그 접두사 때문에 프롬프트가 차지하는 공간이 너무 커졌습니다. 터미널 프롬프트의 거의 절반이 제가 Nix 환경에 있다는 것을 알리는 데 사용되고 있었습니다.
특정 프로젝트에서는 Nix의 쉘 프롬프트 접두사가 더 길었습니다. PicoShare에서는 이렇게 표시되었습니다.
~/examplerepo (branchB|MERGING) $ nix develop
...
(nix:nix-shell-x86_64-unknown-linux-musl-env) ~/picoshare (master)$
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ too much!이제 그 쉘 접두사 때문에 화면 공간을 너무 많이 차지하게 되었습니다. 어떻게 없앨 수 있을까요?
알고 보니 nix develop에는 터미널 쉘 접두사를 이렇게 커스터마이즈할 수 있는 --bash-prompt-prefix 플래그가 있었습니다.
$ nix develop --bash-prompt-prefix 'nix:'
nix:~/picoshare (master)$아예 표시하지 않으려면 빈 문자열로 설정하면 됩니다.
$ nix develop --bash-prompt-prefix ''
~/picoshare (master)$하지만 nix develop을 실행할 때마다 이런 추가 플래그를 붙이고 싶지는 않았습니다.
이 불필요한 표시가 사실은 제 nix.conf 파일에서 온다는 것을 알게 되었습니다. 제 Debian 시스템에서는 /etc/nix/nix.conf에 있는 파일입니다. 아마 Determinate Systems Nix installer가 저를 위해 그 접두사를 설정해 둔 것 같습니다.
$ grep 'bash-prompt-prefix' /etc/nix/nix.conf
bash-prompt-prefix = (nix:$name)이 라인을 더 간결한 nix: 접두사로 바꿨습니다.
bash-prompt-prefix = nix:그리고 변경 사항을 적용하기 위해 Nix를 재시작했습니다.
sudo systemctl restart nix-daemon이제 Nix 개발 환경에 있을 때는 이렇게 짧고 유용한 접두사가 표시됩니다.
요약
소프트웨어 개발을 할 때, 매 쉘 프롬프트마다 디렉터리의 git 상태를 볼 수 있도록 터미널 쉘을 커스터마이즈해 두면 매우 유용합니다.
이 글이 일반 bash 시스템은 물론, Nix와 Home Manager로 bash 설정을 관리하는 시스템에서도 저와 비슷한 설정을 원하는 분들께 도움이 되기를 바랍니다.
글을 무작위로 읽기