COBI-98
은로그
COBI-98
  • 은로그 (79)
    • Back-End (1)
      • Java (5)
      • Spring (16)
      • DB (1)
      • 알고리즘 (7)
      • ETC (2)
    • 개발 일기 (0)
    • 회고 (4)
    • Project (1)
      • 협업프로젝트 (7)
      • 국비프로젝트 (2)
    • Web (2)
      • Server (2)
    • Git (2)
    • CS (0)
    • 코딩테스트 (24)
      • 백준 (17)
      • 프로그래머스 (7)
    • 우아한 테크코스 (5)

블로그 메뉴

  • ✨깃허브
  • 홈
  • 방명록

공지사항

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
COBI-98

은로그

[Git] Git Hooks,  git commit 전 코드를 수정해보자.
Git

[Git] Git Hooks, git commit 전 코드를 수정해보자.

2023. 4. 23. 18:08

프로젝트 효율성 높이기 위한 방안 탐색

프로젝트의 스파게티 코드 리팩토링을 진행하는 도중,
코드의 서식이 맞지 않아 가독성이 떨어지는 것 과 사용되지 않는 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)
좌) 코드서식을 임의로 띄워놓음 우) 새로 import 선언한 것과 사용하지 않는 import문

git commit을 진행해 보자.

 

코드를 판단하여 자동으로  서식, 줄맞춤, import문이 자동으로 제거되어 커밋이 되는 것을 볼 수 있다.

만약 사용하고 싶지 않다면 해당 파일을 삭제하면 된다. 얼마나 간단한가..

 

😎 후기

구상한 대로 적용이 되는 것을 확인하고 사용하니 정말 간편하다는 것을 느꼈다.

hook을 사용한 자동화는 개발 환경에서 반복되는 일들, 사람이 하나씩 체크해야 하는 일들은 팀에게도 도움이 될 것이다.

설정은 한 번이지만 팀의 수가 늘어나도 설정을 바탕으로 높아진 효율은 유지된다.
또 개발환경 설정을 바탕으로 컨벤션을 자동화하고 코드 품질을 높기에 적극적으로 사용을 할 것 같다.

 

이 글을 읽는 여러분들도 사용해보세요 ! 

 

 

 

'Git' 카테고리의 다른 글

[Git] GitHub 저장소의 특정 파일, 디렉토리 커밋기록을 모두 제거하기  (2) 2023.03.05
    'Git' 카테고리의 다른 글
    • [Git] GitHub 저장소의 특정 파일, 디렉토리 커밋기록을 모두 제거하기
    COBI-98
    COBI-98
    배운 것을 응용하기 위해 기록하는 것을 선호하며 백엔드를 공부하고 있습니다.

    티스토리툴바