개발

Git 브랜치 원격이랑 동기화 시키는 방법 (feat. Toolgit 사용법)

hyunta 2024. 12. 20. 15:35

배경

개발을 하다보면 로컬 환경의 브랜치 목록과 원격(Github, Gitlab 등 원본 저장소)에 저장된 브랜치가 싱크가 안맞는 경우가 발생합니다.

여기서 싱크가 안맞다고 하는 부분은 크게 2가지를 의미 합니다.

첫번째는 fast-forward가 안되어 있는 경우가 있습니다. 로컬에 브랜치를 받아온 이후에 동료가 해당 브랜치에 커밋을 쌓는 경우 발생합니다.

두번째는 브랜치 목록이 다를 수 있습니다. 저희는 원격 저장소에 merge가 되는 시점에 해당 브랜치를 삭제하는 방법을 사용하고 있습니다. 하지만 로컬 브랜치를 매번 삭제하지 않으니 로컬에는 존재하지만 원격에는 브랜치가 존재하는 경우가 있습니다.

이 두가지 언싱크된 부분을 해결하기 위해서는 조금 귀찮지만 각각 브랜치에서 작업을 해줬어야 했습니다.

그래서 거의 몇개월에 한번씩 브랜치가 너무 많았을 때 대략적으로 정리를 했었는데 이번에 Toolgit을 알게되면서 조금 편리하게 관리할 수 있게 되어서 공유드리려고 합니다.

 

Toolgit?

https://github.com/ahmetsait/toolgit

 

GitHub - ahmetsait/toolgit: Git Productivity Toolkit

Git Productivity Toolkit. Contribute to ahmetsait/toolgit development by creating an account on GitHub.

github.com

툴깃은 한 터키 개발자분이 만드신 오픈소스 코드입니다. (24년 11월까지 업데이트된 이력이 있습니다.)

코드가 그렇게 대단한 내용을 담고 있지는 않고 git을 편리하게 사용할 수 있는 쉘스크립트를 여럿 담고 있습니다.

아래는 제가 자주 쓰는 git-forward 쉘스크립트의 내용입니다.

#!/usr/bin/env bash

app_name="$(basename "${BASH_SOURCE[0]}")"
app_dir="$(dirname "${BASH_SOURCE[0]}")"

print_help() {
	expand -t 4 << EOF
Usage:
	$app_name [REMOTE]
		Fetch and fast forward all remote tracking branches.
		If a remote is given, tries to update from remote branches with the same name.

Options:
	-?, --help
		Show this help information and exit.
EOF
}

args=()

for ((i = 1; i <= $#; i++)); do
	opt="${!i}"
	case "$opt" in
		-\?|--help)
			print_help
			exit 0
			;;
		--)
			args+=("${@:i+1}")
			break
			;;
		-*)
			echo "$app_name: [Error] Unknown option: $1" >&2
			exit 1
			;;
		*)
			args+=("$opt")
			;;
	esac
done

if [[ ${#args[@]} -eq 1 ]]; then
	remote="${args[0]}"
elif [[ ${#args[@]} -gt 1 ]]; then
	echo "$app_name: [Error] Too many arguments." >&2
	echo "Try '$app_name -?' for more information." >&2
	exit 2
fi

git rev-parse --git-dir > /dev/null || exit $?

interrupt () {
	echo "Interrupted."
	exit 1
}

trap interrupt INT

git fetch --all &&
current_branch="$(git rev-parse --abbrev-ref HEAD)" &&
for branch in $(git branch --list --format="%(refname:short)"); do
	if [[ -v remote ]]; then
		upstream="$remote/$(git rev-parse --verify --quiet --abbrev-ref "$branch")"
		has_upstream=0
	else
		upstream="$(git rev-parse --verify --quiet --abbrev-ref "$branch@{upstream}")"
		has_upstream="$?"
	fi
	if [[ has_upstream -eq 0 ]]; then
		branch_sha="$(git rev-parse --quiet --verify "$branch")" &&
		upstream_sha="$(git rev-parse --quiet --verify "$upstream")" &&
		if git merge-base --is-ancestor "$upstream_sha" "$branch_sha"; then
			echo "'$branch' is already up to date with '${upstream%/$branch}'."
			continue
		fi &&
		if [[ "$branch" == "$current_branch" ]]; then
			git pull --ff-only --quiet
		else
			git fetch . --quiet "$upstream:$branch"
		fi &&
		echo "Updated '$branch' -> '$upstream'" ||
		echo "Cannot fast forward '$branch' to '$upstream'"
	fi
done

 

현재는 이런 커맨드들이 있는데 저는 git-forward, git-delete-gone-branches를 주로 사용합니다.

 

설치 방법

사실 딱히 설치를 하는 것은 아닙니다. 명령어를 조금 쉽게 칠 수 있도록 환경변수에 설정하는 작업 이외에는 할 것이 없습니다.

alias 기능을 안쓰기 때문에 저는 alias 설정은 따로 안했습니다.

 

우선 해당 Repository를 다운 받아야 합니다. 저는 Mac 환경이라 Tarball 로 다운받았습니다.

해당 폴더의 압축을 풀고 경로를 환경변수에 설정해주면 됩니다.

저는 Zsh 쉘을 사용하고 있어서 ~/.zshrc 파일에 경로를 설정해주고 저장했습니다.

vi ~/.zshrc

# 아래 내용을 해당 파일에 작성합니다.
export PATH= "$PATH: {제가 설치한 경로}/toolgit"

# 저장한 뒤에 변경 사항 적용
source ~/.zshrc

 

환경변수에 해당 경로를 설정해두면 어디에서든 git-forward 명령어를 통해서 쉘스크립트를 실행할 수 있습니다.

 

사용 방법

1. git-forward

해당 기능은 프로젝트의 모든 브랜치를 최신화하는 기능입니다.

우선 로컬 브랜치 중에서 원격을 따르는 브랜치를 찾아서 전부 업데이트를 시도합니다.

 

2. git-delete-gone-branches

해당 기능은 원격 브랜치에 존재하지 않는 로컬 브랜치를 삭제하는 기능입니다.

원격 브랜치를 따르고 있는지를 확인하기 때문에 로컬에서만 생성하여 아직 원격에 반영하지 않은 경우 삭제되지 않습니다.

저는 주기적으로 해당 기능을 실행시켜서 불필요한 브랜치들을 삭제해주고 있습니다.

 

 

Reference

https://github.com/ahmetsait/toolgit