
🖇️ 관련 글 : 코딩 컨벤션 설정 | Spotless, Checkstyle ⚙️✨
지난 글에서 Spotless 설정을 했다.
하지만 매번 Spotless Apply / Spotless Check를 통해
컨벤션을 적용하고 확인하는 작업이 번거롭다는 생각을 했다.
컨벤션이 지켜지지 않을 때 build가 실패하게 되는데 만약 적용하는 것을 깜빡하고 커밋을 하게 된다면?
CI workflow에서 체크해 줘서 머지할 때 오류는 없겠지만.. 그래도 커밋할 때부터 이 오류를 잡아줄 순 없을까?
이런 휴먼 에러를 방지하고, 반복되는 작업을 Git Hooks를 활용하여 자동화함으로써 개발 생산성을 높이려고 한다.

⚙️ 프로젝트 환경
- java : 11
- Spring Boot : 2.7.11
- 멀티 모듈 프로젝트
- Build Tool: Gradle
- Spotless 플러그인
✅ 요구사항
- 자동화로 개발 환경에서 반복되는 일들, 사람이 하나씩 체크해야 하는 일들을 덜어주자.
- build.gradle에 task를 등록하여 개발자가 환경 설정에 신경 쓰지 않고 컨벤션이 적용된 프로젝트를 수행할 수 있도록 하자.
⛳️ 목표와 기대효과
- 1~2초의 간단한 반복이지만, 이를 줄인다면 앞으로 개발 기간이 쌓여갈 때 절약된 시간은 의미 있을 것이다.
- 팀 전체 개발 생산성 향상
- 많은 개발자들이 프로젝트에 적용된 컨벤션에 대해 신경을 쓰지 않더라도 소스 코드의 품질을 유지
🐰 : 근데 Git Hooks로 자동화한다고 했자녀~ 그래서 깃훅?! 그게 뭔데? 그거 어떻게 하는 건데?
🤖 : 'commit이나 push 등의 특정 동작 전에 특정 스크립트를 실행할 수 있는 기능'이다!!! 토끼야!
🐰 : 오케이. 오늘도 두괄식 서술 아주 마음에 들어.
0. Git Hooks
commit이나 push 등의 특정 동작 전에 특정 스크립트를 실행할 수 있는 기능
Git Hooks은 따로 설치할 필요 없이 git repository에서 지원해주고 있다.
.git/hooks에 접근해서 파일을 확인해 보자.
현재는 13가지 정도의 동작을 지원한다.

각각의 파일을 어떻게 커스텀할지는 공식문서를 참고하자.
지금은 .sample 확장자로 되어 있는 파일은 .sample 확장자를 지우면 바로 적용된다.
나는 .sample 코드는 그대로 두고 작업했다.
1. 스크립트 작성
이제 스크립트를 작성해 보자.
[ Pre-commit script ]
커밋 전 실행할 내용을 스크립트로 작성해 보자. 크게 3가지 부분으로 나눌 수 있다.
✔️ scripts > pre-commit
scripts 폴더를 프로젝트 루트에 위치시켰다.

일단 전체 스크립트!
#!/bin/sh
# 1. 변경된 파일들 이름만 추출하여 저장
stagedFiles=$(git diff --staged --name-only)
# 2. SpotlessApply 실행
echo "Running spotlessApply. Formatting code..."
./gradlew spotlessApply --daemon
# 3. 변경사항이 발생한 파일들 다시 git add
for file in $stagedFiles; do
if test -f "$file"; then
git add "$file"
fi
done
- #!/bin/bash : bash 쉘을 사용하겠다는 의미로 이후 스크립트는 bash로 해석
1) 스테이징 된 파일을 변수에 할당
변경된 파일들 이름만 추출하여 변수에 저장한다.
# 1. 변경된 파일들 이름만 추출하여 저장
stagedFiles=$(git diff --staged --name-only)
2) 컨벤션 적용
SpotlessApply를 실행해서 컨벤션을 적용한다.
- --daemon: 데몬 프로세스를 사용하면 실행 속도를 높일 수 있다.
# 2. SpotlessApply 실행
echo "Running spotlessApply. Formatting code..."
./gradlew spotlessApply --daemon
3) 변경사항이 발생한 파일을 다시 git add
1번 단계에서 식별된 모든 파일은 git add로 준비된다.
준비된 파일이이 삭제되었을 수도 있기 때문에 파일이 존재하는지 확인하는 테스트도 진행한다.
# 3. 변경사항이 발생한 파일들 다시 git add
for file in $stagedFiles; do
if test -f "$file"; then
git add "$file"
fi
done
2. Gradle에 의존하기
git hooks을 사용하기 위해서는 위에서 작성한 스크립트가 .git/hooks 폴더에 들어가야 한다.
하지만 .git 폴더는 원격저장소에서 공유되지 않기 때문에 팀의 모든 사람이 각자 세팅을 해야 한다.
개발자 개개인이 수동으로 파일을 복사하는 프로세스는 오류가 발생할 가능성이 있다. 그래서 이 프로세스를 자동화하기 위해서는 Gradle 작업에 의존한다.
[ 방법 1]
외부에서 task를 작성하고 적용하는 방식으로 하려고 하다가 더 간단한 방법으로 변경했다.
✔️ gradle/install-git-hooks.gradle
tasks.create(name: 'gitExecutableHooks') {
Runtime.getRuntime().exec("chmod -R +x .git/hooks/");
}
task installGitHooks(type: Copy) {
from new File(rootProject.rootDir, 'scripts/pre-commit')
into { new File(rootProject.rootDir, '.git/hooks') }
}
gitExecutableHooks.dependsOn installGitHooks
clean.dependsOn gitExecutableHooks

✔️ build.gradle
플러그인 설치
apply from: rootProject.file('gradle/install-git-hooks.gradle')
[ 방법 2 ]
✔️ build.gradle
tasks.register('updateGitHooks', Copy) {
from './scripts/pre-commit'
into './.git/hooks'
fileMode 0775
}
compileJava.dependsOn updateGitHooks
task를 정의해 주고 build 해주면 아래와 같이 파일이 복사된 걸 확인할 수 있다.

그리고 스크립트가 잘 실행되는지 확인해 보자!
일부러 컨벤션에 맞지 않는 코드를 작성했다.

체크하면 실패한다.

그리고 커밋을 하면..

SpotlessAply을 한 번 돌리고 커밋해서 git에 올라간 코드는 컨벤션이 적용되었다. 🎉
번외 : 🐛 Error 해결
1) 우쒸.. pre-commit 스크립트 있는데 왜 실행이 안되니..
로그 좀 읽을래? ㅎ... 권한 부여해야 한다.

tasks.register('updateGitHooks', Copy) {
from './scripts/pre-commit'
into './.git/hooks'
// 권한 추가
fileMode 0775
}
compileJava.dependsOn updateGitHooks
자동으로 실행되는 스크립트를 보다 안전하게 사용하기 위해서 소유자와 그룹 사용자만 읽기, 쓰기, 실행 권한을 주고 기타 사용자는 읽기와 실행 권한만 부여했다.
1. 읽기 Reading - 4
2. 쓰기 Writing - 2
3. 실행 Executing - 1
📌 Reference
'프로젝트 개발 기록 > Git' 카테고리의 다른 글
[Git] Submodule로 민감 정보 관리하기 (.yml 파일) (0) | 2023.05.11 |
---|---|
[Git] 한 repository 여러 프로젝트 월세주기 🏡 (0) | 2023.04.24 |
댓글