사내에서 task 관리에 clickup을 사용한다.
clickup에서는 task 마다 고유한 taskid가 uid로 자동으로 생성된다.

이를 git branch 명으로 설정하여 작업을 한다. 이경우에 branch가 쌓일 경우 구분하기 어려운 문제가 발생한다.

작업중에 A 브랜치와 B 브랜치를 오가면서 작업할 일이 종종 생기는데, 위 이미지처럼 보인다면 매번 clickup에 다시 들어가 taskid를 복사해가며 작업해야했다.
이 문제를 해결하기 위해서 각 브랜치별로 어떤 상태인지 나타내는 cli 도구를 만들고자한다.
git 에서는 git branch --edit-description [<branchname>] 이라는 명령어를 통해 branch마다 설명을 추가하는 기능을 제공한다.
이걸 사용하여 git ll 이라는 명령어를 입력하면, 브랜치와 그 설명이 나오게 하려한다.
node나 py로 설치할경우, 실행 환경에 의존성이 생기기 때문에 shell script로 작성할 것이다.
브랜치 정보를 불러와서 description이 있는 브랜치와 없는 브랜치를 나누고, abc 순으로 정렬을 할 것이다.
# 브랜치 목록 불러오기
mapfile -t branches < <(git branch --format="%(refname:short)")
branches_with_desc=()
branches_without_desc=()
# 브랜치의 description을 안전하게 가져오는 함수
get_branch_description() {
local branch="$1"
local desc
desc=$(git config "branch.${branch}.description")
if [ -z "$desc" ]; then
echo "(no description)"
else
echo "$desc"
fi
}
# 각 브랜치에 대해 description을 확인하여 배열에 저장
for branch in "${branches[@]}"; do
description=$(get_branch_description "$branch")
entry="${branch}|${description}"
if [ "$description" = "(no description)" ]; then
branches_without_desc+=("$entry")
else
branches_with_desc+=("$entry")
fi
done
# 배열 정렬 (branch 이름 기준)
IFS=$'\n'
sorted_with=($(sort <<<"${branches_with_desc[*]}"))
sorted_without=($(sort <<<"${branches_without_desc[*]}"))
unset IFS
현재 브랜치나 - 를 통해 이전 브랜치로 이동하는 작업도 자주 하므로, 이 두 정보도 표시할 것이다.
# 현재 브랜치 가져오기
current_branch=$(git symbolic-ref --short HEAD)
# 이전 브랜치를 가져올 때 에러 출력을 무시하고, 결과가 "@{-1}" 또는 빈 값이면 이전 브랜치가 없다고 처리
previous_branch=$(git rev-parse --abbrev-ref '@{-1}' 2>/dev/null)
if [ "$previous_branch" = "@{-1}" ] || [ -z "$previous_branch" ]; then
previous_branch=""
fi
이전 브랜치가 없거나, 삭제되는 경우에 @{-1}이라고 뜨기때문에 그것에 대한 예외처리를 추가해줬다.
출력할때, description이 있는것만 출력할지, 없는 것만 출력할지 등의 옵션을 추가했다.
사실 이 옵션은 나중에 추가된 것이다.
사용해보니 description이 없는 코드리뷰용 브랜치나 임시 브랜치등을 제외하고 주로 사용하는 활성 브랜치들만 보고 싶은 경우가 있었기 때문이다.
# 옵션 초기화
show_all=false
show_desc_only=false
show_no_desc_only=false
while getopts "adn" opt; do
case "$opt" in
a) show_all=true ;;
d) show_desc_only=true ;;
n) show_no_desc_only=true ;;
*) usage ;;
esac
done
# 옵션이 하나도 지정되지 않은 경우 기본값: 모든 브랜치 출력
if ! $show_all && ! $show_desc_only && ! $show_no_desc_only; then
show_all=true
fi
# -d와 -n를 동시에 지정하면 모든 브랜치를 출력
if $show_desc_only && $show_no_desc_only; then
show_all=true
show_desc_only=false
show_no_desc_only=false
fi
cli 옵션을 -a,-d,-n 등을 받을 수 있도록 연결해주었다.
정렬된 브랜치를 포맷에 맞춰서 출력해주기만 하면된다.
# 브랜치 정보를 출력하는 함수
print_branch_info() {
local prefix="$1"
local branch="$2"
local description="$3"
local branch_color="$4"
printf "%b%s - %s\n" "$prefix" "${branch_color}${branch}${RESET}" "$description"
}
# 옵션에 따라 브랜치 출력 (기본적으로 알파벳 순 정렬)
if $show_all || $show_no_desc_only; then
for entry in "${sorted_without[@]}"; do
branch_name=$(echo "$entry" | cut -d'|' -f1)
branch_desc=$(echo "$entry" | cut -d'|' -f2-)
print_branch_info "" "$branch_name" "$branch_desc" "$PINK"
done
fi
if $show_all || $show_desc_only; then
for entry in "${sorted_with[@]}"; do
branch_name=$(echo "$entry" | cut -d'|' -f1)
branch_desc=$(echo "$entry" | cut -d'|' -f2-)
print_branch_info "" "$branch_name" "$branch_desc" "$PINK"
done
fi
# 이전 브랜치와 현재 브랜치 표시 (이전 브랜치가 유효할 경우에만)
if [ -n "$previous_branch" ] && [ "$previous_branch" != "$current_branch" ]; then
prev_description=$(get_branch_description "$previous_branch")
printf "%b*prev %s - %s\n" "$GRAY" "${PINK}${previous_branch}${RESET}" "$prev_description"
fi
curr_description=$(get_branch_description "$current_branch")
printf "%b*curr %s - %s\n" "$GREEN" "${PINK}${current_branch}${RESET}" "$curr_description"
출력할때, 색상이 들어가면 보기 좋을 것 같아 ANSI 코드를 통해 색상을 추가해주었다.
git ll로 호출하고 싶다면, git이 있는 bin 경로에 git-ll이라는 파일명으로 넣어두면 -이 공백으로 치환되어 적용된다.
bin 경로는
env | grep PATH를 통해 확인 가능하다.
또는witch git을 통해 나온 경로를 그냥 사용해도 무방하다.
sudo vi /usr/bin/git-ll로 파일을 만들고 안에 내용을 작성하자.sudo chmod +x /usr/bin/git-ll로 실행권한을 추가해주자.이후 git ll을 쳐보면 다음과 같이 출력되는 걸 볼 수 있다.

description을 등록할 때, 매번 입력하는 것이 불편한 점이 있어서 이를 위한 cli도 하나 추가하였다.
git-set-desc
#!/bin/bash
if [ "$#" -lt 2 ]; then
echo "Usage: git set-desc [target branch] [description]"
exit 1
fi
if [ "$1" = "." ]; then
TARGET_BRANCH=$(git symbolic-ref --short HEAD)
else
TARGET_BRANCH="$1"
fi
if ! git show-ref --verify --quiet "refs/heads/${TARGET_BRANCH}"; then
echo "Error: Branch '${TARGET_BRANCH}' does not exist."
exit 1
fi
shift
DESCRIPTION="$*"
if ! git config "branch.${TARGET_BRANCH}.description" "$DESCRIPTION"; then
echo "Error: Failed to set description for branch '${TARGET_BRANCH}'."
exit 1
fi
echo "Description for branch '${TARGET_BRANCH}' set to: $DESCRIPTION"
git --edit-description이 내부적으로는 config/branch..description 에 저장되는 것을 활용하여 만든 코드이다.
/bin에 git-ll처럼 등록하여 사용하면된다.
다음 이미지처럼 설명을 등록할 수 있다.

.을 사용하면 현재 브랜치 명으로 인식한다.

git ll을 입력하면 깔끔하게 현재 브랜치와 설명이 출력되는 걸 볼 수 있다.

옵션도 잘 작동한다.
이렇게 git branch를 다루는 cli를 sh로 작성해보았다.
대부분 gpt와 함께 하며 만들었지만, 그래도 만들고 나니 아주 편해졌다.
팀원들과 공유하여 사용하였고, 브랜치가 쌓이는 문제에 대한 공감대가 있어서 많은 분들이 계속 애용해주셔서 뿌듯하다.
#!/bin/bash
GREEN=$'\033[0;32m'
PINK=$'\033[0;35m'
GRAY=$'\033[1;30m'
RESET=$'\033[0m'
# 사용법 출력 함수
usage() {
echo "Usage: $0 [-a] [-d] [-n]"
echo " -a : Show all branches (default)"
echo " -d : Show only branches with a description"
echo " -n : Show only branches without a description"
exit 1
}
# 현재 디렉터리가 Git 리포지토리인지 확인
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: The current directory is not a Git repository."
exit 1
fi
# 옵션 초기화
show_all=false
show_desc_only=false
show_no_desc_only=false
while getopts "adn" opt; do
case "$opt" in
a) show_all=true ;;
d) show_desc_only=true ;;
n) show_no_desc_only=true ;;
*) usage ;;
esac
done
# 옵션이 하나도 지정되지 않은 경우 기본값: 모든 브랜치 출력
if ! $show_all && ! $show_desc_only && ! $show_no_desc_only; then
show_all=true
fi
# -d와 -n를 동시에 지정하면 모든 브랜치를 출력
if $show_desc_only && $show_no_desc_only; then
show_all=true
show_desc_only=false
show_no_desc_only=false
fi
# 현재 브랜치 가져오기
current_branch=$(git symbolic-ref --short HEAD)
# 이전 브랜치를 가져올 때 에러 출력을 무시하고, 결과가 "@{-1}" 또는 빈 값이면 이전 브랜치가 없다고 처리
previous_branch=$(git rev-parse --abbrev-ref '@{-1}' 2>/dev/null)
if [ "$previous_branch" = "@{-1}" ] || [ -z "$previous_branch" ]; then
previous_branch=""
fi
# 안전하게 브랜치 목록을 배열에 저장 (공백 포함 안전)
mapfile -t branches < <(git branch --format="%(refname:short)")
branches_with_desc=()
branches_without_desc=()
# 브랜치의 description을 안전하게 가져오는 함수
get_branch_description() {
local branch="$1"
local desc
desc=$(git config "branch.${branch}.description")
if [ -z "$desc" ]; then
echo "(no description)"
else
echo "$desc"
fi
}
# 각 브랜치에 대해 description을 확인하여 배열에 저장
for branch in "${branches[@]}"; do
description=$(get_branch_description "$branch")
entry="${branch}|${description}"
if [ "$description" = "(no description)" ]; then
branches_without_desc+=("$entry")
else
branches_with_desc+=("$entry")
fi
done
# 배열 정렬 (branch 이름 기준)
IFS=$'\n'
sorted_with=($(sort <<<"${branches_with_desc[*]}"))
sorted_without=($(sort <<<"${branches_without_desc[*]}"))
unset IFS
# 브랜치 정보를 출력하는 함수
print_branch_info() {
local prefix="$1"
local branch="$2"
local description="$3"
local branch_color="$4"
printf "%b%s - %s\n" "$prefix" "${branch_color}${branch}${RESET}" "$description"
}
# 옵션에 따라 브랜치 출력 (기본적으로 알파벳 순 정렬)
if $show_all || $show_no_desc_only; then
for entry in "${sorted_without[@]}"; do
branch_name=$(echo "$entry" | cut -d'|' -f1)
branch_desc=$(echo "$entry" | cut -d'|' -f2-)
print_branch_info "" "$branch_name" "$branch_desc" "$PINK"
done
fi
if $show_all || $show_desc_only; then
for entry in "${sorted_with[@]}"; do
branch_name=$(echo "$entry" | cut -d'|' -f1)
branch_desc=$(echo "$entry" | cut -d'|' -f2-)
print_branch_info "" "$branch_name" "$branch_desc" "$PINK"
done
fi
# 이전 브랜치와 현재 브랜치 표시 (이전 브랜치가 유효할 경우에만)
if [ -n "$previous_branch" ] && [ "$previous_branch" != "$current_branch" ]; then
prev_description=$(get_branch_description "$previous_branch")
printf "%b*prev %s - %s\n" "$GRAY" "${PINK}${previous_branch}${RESET}" "$prev_description"
fi
curr_description=$(get_branch_description "$current_branch")
printf "%b*curr %s - %s\n" "$GREEN" "${PINK}${current_branch}${RESET}" "$curr_description"