프로젝트 효율성 높이기 위한 방안 탐색
프로젝트의 스파게티 코드 리팩토링을 진행하는 도중,
코드의 서식이 맞지 않아 가독성이 떨어지는 것 과 사용되지 않는 import문이 늘어나면서
프로젝트의 코드가 효율적으로 관리되지 못한다는 사실을 깨달았다.
현재 나는 이를 위해 인텔리제이의 단축키
- ctrl + alt + l (코드 서식 수정)
- ctrl + alt + o (사용하지 않는 import 문 제거)
를 사용하여 내 코드를 수정하며 git에 저장하고 있었다.
하지만 이 부분을 자동으로 git commit 명령 이전에 내 코드를 보고 수정해 주는 자동화 기능은 없을까?
라는 생각을 가지고 방안을 탐색하였고, git hook을 발견했다.
그래서 commit이나 push 등의 git 명령어 동작 전에 코드 품질을 점검하고 잘못된 상황을 체크할 수 있는
Git Hooks를 다뤄 보기로 했다.
목표
pre-commit 파일을 활용해서 사용하지 않는 import 문과 코드 서식을 정렬을 자동으로 해보자.
이 글을 다루는 코드들은 os, window 버전에서 작성되었습니다.
Git Hooks란?
Git도 다른 버전 관리 시스템처럼 어떤 이벤트가 생겼을 때 자동으로 특정 스크립트를 실행하도록 할 수 있다.
이 훅은 클라이언트 훅과 서버 훅으로 나눌 수 있다.
클라이언트 훅은 커밋이나 Merge 할 때 실행되고 서버 훅은 Push 할 때 서버에서 실행된다.
이번에 다루게 될 것은 클라이언트 훅이다.
이것은 이미 git repository에서 지원하고 있다. cd .git/hooks/ 로 확인해 보자.
git hooks에는 13개의 .sample이 있다.
특정 상황에 특정 스크립트를 실행을 하는데 특정 상황은 다음 표와 같다.
커밋 워크플로우 훅 | 특정 상황 |
applypatch-msg | 이메일 워크플로 훅 |
commit-msg | commit 메시지를 완성한 후 commit 을 최종 완료하기 전에 실행 |
fsmonitor-watchman | macOS 및 Linux에서만 작동하며, 파일 시스템 변경을 모니터링하는 최적화기능 제공 |
post-update | git push 명령을 사용하여 리모트 저장소에 변경 사항을 푸시 한 후에 실행 |
pre-applypatch | patch 적용 후 실행하며, patch 를 중단시킬 수 있음 |
pre-commit | 커밋할 때 가장 먼저 호출되는 훅으로 커밋 메시지를 작성하기 전에 호출 -> 새로 추가한 코드에 주석을 달았는지 검사하는 일은 이 훅으로 하는 것이 좋다. |
pre-merge-commit | 현재 브랜치를 다른 브랜치에 병합하려고 할 때 실행 |
pre-push | git push 명령 실행 시 동작하며 리모트 정보를 업데이트 하고 난 후 리모트로 데이터를 전송하기 전에 실행. push 를 중단시킬 수 있음 |
pre-rebase | 기타 훅 |
pre-receive | Push 하면 가장 처음 실행되는 훅은 pre-receive 훅 |
prepare-commit-msg | commit 메시지를 생성하고 편집기를 실행하기 전에 실행 |
push-to-checkout | 다른 브랜치로 체크아웃 할 때 실행 |
update | update 스크립트는 각 브랜치마다 한 번씩 실행 -> pre-receive 스크립트와 거의 같다 |
필요한 상황에 맞게 .sample이라는 확장자를 지우면 각 상황에 샘플이 바로 적용된다.
여기서 커밋할 때 가장 먼저 호출되는 훅인 pre-commit에 대해 다루도록 하겠다.
pre-commit hook 스크립트 작성
#!/bin/sh
exec 1>&2
# Spotless를 실행하여 코드 서식 지정
gradle spotlessApply
# Google Java 형식을 사용하여 사용하지 않는 import제거
java -jar "C:\Program Files (x86)\Google\google-java-format-1.16.0-all-deps.jar" -i $(git diff --cached --name-only --diff-filter=ACM -- '*.java' | tr '\n' ' ')
# 수정된 파일 준비
git add $(git diff --cached --name-only --diff-filter=ACM -- '*.java')
# 준비된 파일 커밋
git commit -m "Formatted code and removed unused imports."
- Gradle을 사용하여 코드 서식을 맞춘다. 이는 gradle spotlessApply 명령으로 실행된다.
- Google Java Format을 사용하여 사용하지 않는 import문을 제거하고 코드 서식을 맞춘다.
- 이는 java -jar "C:\Program Files (x86)\Google\google-java-format-1.16.0-all-deps.jar" -i 명령으로 실행
- 수정된 파일을 Git staging area에 추가한다. 이는 git add . 명령으로 실행
해당 스크립트를 pre-commit.sample에 저장하고 적용시키기 위해 .sample 확장자를 지운다.
이것을 실행하기 위해서는 gradle, spotless, google-java-format 라이브러리가 필요하다.
gradle 설치
https://gradle.org/releases/ 에서 binary-only 또는 complete을 선택하여 다운로드
환경변수 설정
시스템 환경 변수 편집 > 환경 변수 > 시스템 변수 > Path를 선택한 후 C:\gradle\gradle-8.1.1\bin을 추가
spotless 라이브러리 설치
해당 프로젝트의 build.gradle 파일에 아래와 같이 의존성을 추가한다.
plugins {
id "com.diffplug.spotless" version "5.14.0"
}
이후, 아래와 같이 Spotless를 구성
spotless {
java {
googleJavaFormat()
}
}
🔻pom.xml의 예시
라이브러리 추가
<plugins>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>5.14.0</version>
<executions>
<execution>
<id>spotless</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<configuration>
<formats>
<format>
<name>java-google-java-format</name>
<settings>
<url>https://github.com/google/google-java-format/releases/download/v1.12.0/google-java-format-1.12.0-all-deps.jar</url>
</settings>
</format>
</formats>
<java>
<googleJavaFormat>
<version>1.12.0</version>
</googleJavaFormat>
</java>
</configuration>
google-java-format 라이브러리 설치
아래 링크에서 google-java-format-1.x.x-all-deps.jar 파일을 다운로드한다.
https://github.com/google/google-java-format/releases
다운로드한 jar 파일을 C:\Program Files (x86)\Google\ 폴더에 저장한다.
파일 권한을 변경하여 실행 권한을 부여
bash
chmod +x .git/hooks/pre-commit
이렇게 실행권한까지 부여하면 이제 코드를 커밋하기 전,
pre-commit hook이 실행되며 코드 정리와 자동화가 수행된다. 확인해 보자.
동작확인
사용하고 있던 프로젝트에서 임의로 코드를 변경해 보자.
- 코드 서식의 띄워쓰기랑 줄맞춤을 변경하였다.
- import(Slf4j)을 추가 선언하였고,
- 사용하지 않은 import문은 회색처리되었다. (HashMap,StringTokenizer,UUID)
git commit을 진행해 보자.
코드를 판단하여 자동으로 서식, 줄맞춤, import문이 자동으로 제거되어 커밋이 되는 것을 볼 수 있다.
만약 사용하고 싶지 않다면 해당 파일을 삭제하면 된다. 얼마나 간단한가..
😎 후기
구상한 대로 적용이 되는 것을 확인하고 사용하니 정말 간편하다는 것을 느꼈다.
hook을 사용한 자동화는 개발 환경에서 반복되는 일들, 사람이 하나씩 체크해야 하는 일들은 팀에게도 도움이 될 것이다.
설정은 한 번이지만 팀의 수가 늘어나도 설정을 바탕으로 높아진 효율은 유지된다.
또 개발환경 설정을 바탕으로 컨벤션을 자동화하고 코드 품질을 높기에 적극적으로 사용을 할 것 같다.
이 글을 읽는 여러분들도 사용해보세요 !
'Git' 카테고리의 다른 글
[Git] GitHub 저장소의 특정 파일, 디렉토리 커밋기록을 모두 제거하기 (2) | 2023.03.05 |
---|