한 브랜치에서 다른 브랜치로 커밋 세트 복사 자동화

이 문서에서는 리포지토리의 한 분기에서 다른 분기로 일련의 연속 커밋을 복사하는 방법을 설명합니다.

Yancy MinUnsplash님의 사진

최종 스크립트



Code Link

bash 스크립트 copy_commits의 최종 버전은 다음과 같습니다.

copy_commits.sh -p <project_path> -s <source-branch> -t <target-branch> -f <commit-start> -e <commit-end>

두 개의 분기 dev1과 dev2가 있고 일련의 연속 커밋을 dev1에서 dev2로 옮기고 싶다고 가정해 보겠습니다.

dev1 분기에는 5개의 커밋이 있고 dev2 분기에는 1개의 커밋이 있습니다. 그리고 시작 커밋과 종료 커밋을 지정하여 dev1의 추가 커밋 4개를 dev2 분기에 복사하려고 합니다.

단계



작업을 자동화하기 위해 다음 단계를 수행합니다.
  • 먼저 스크립트 실행 시 전달된 매개변수를 구문 분석합니다. 값은 다음 5개 변수에 저장됩니다.
  • $PROJECT_PATH
  • $SOURCE_BRANCH
  • $TARGET_BRANCH
  • $FROM_COMMIT
  • $TO_COMMIT
  • 먼저 dev1 브랜치(소스 브랜치)를 확인하고 시작 커밋과 종료 커밋(포함) 사이의 모든 커밋을 배열로 가져옵니다.
  • 그런 다음 dev2 분기를 확인하고 배열에서 각 커밋을 가져와 dev2(대상 분기)의 커밋을 선별합니다

  • 1단계: 매개변수 구문 분석 및 매개변수를 변수에 저장



    while getopts ":p:s:t:f:e:" o; do
        case "${o}" in
        p)
                PROJECT_PATH="${OPTARG}"
                ;;
            s)
                SOURCE_BRANCH="${OPTARG}"
                ;;
            t)
                TARGET_BRANCH="${OPTARG}"
                ;;
            f)
                FROM_COMMIT="${OPTARG}"
                ;;
            e)
                TO_COMMIT="${OPTARG}"
                ;;
            *)
                abnormal_exit
                ;;
        esac
    done
    

    다음은 abnormal_exit() 함수의 코드입니다.

    # Prints usage
    usage() {                                      
      echo "Usage: $0 -p <project_path> -s <source-branch> -t <target-branch> -f <commit-start> -e <commit-target>  " 1>&2 
    }
    
    # Prints usage and exit
    abnormal_exit() {                              
      usage
      exit 1
    }
    

    2단계: 소스 브랜치에서 커밋의 해시를 가져와 어레이에 저장



    commits=($(git rev-list "$FROM_COMMIT^..$TO_COMMIT"))
    
  • git rev-list는 git 커밋을 역순으로 나열하는 데 사용됩니다. 따라서 최신 커밋은 어레이의 시작 부분에 있습니다.
  • <start_commit_hash>..<end_commit_hash>는 start_commit_hash(포함되지 않음)에서 end_commit_hash(포함됨)까지 시작하도록 지정하는 표기입니다. 결과에서 start_commit_hash를 얻으려면 시작 커밋의 부모를 지정해야 합니다. 시작 커밋의 부모는 커밋 해시의 끝에서 캐럿 ^을 사용하여 지정할 수 있습니다. 이것이 시작 커밋의 끝에 캐럿이 사용된 이유입니다.
  • $FROM_COMMIT^ : $FROM_COMMIT 의 부모에서 시작한다는 의미입니다. 캐럿(^)은 커밋의 상위를 지정하는 데 사용됩니다. 그렇지 않으면 $FROM_COMMIT가 최종 결과에 포함되지 않습니다.
  • $(some_command_here) : 이 표기법은 일부 명령을 실행하고 싶지만 명령의 출력을 변수에 저장하려는 경우에 사용됩니다. 따라서 출력을 왼쪽의 변수에 할당할 수 있습니다.
  • ($(some_command_here)): 일부 텍스트를 괄호로 캡슐화하면 bash는 텍스트를 IFS(Internal Field Separator)에 기반한 배열로 변환합니다. 기본적으로 공백입니다. 따라서 $(some_command_here)의 출력은 배열로 변환됩니다.

  • 3단계: 커밋 배열에서 커밋을 선택하여 대상 브랜치에 커밋 적용



    커밋 배열에 모든 커밋이 있습니다. 이제 대상 분기를 확인해야 합니다.

    git checkout $TARGET_BRANCH
    
    if ! [[ $? -eq 0 ]]
    then
        echo $'\u274c' "ERROR: Failed to checkout to $TARGET_BRANCH"
        exit 2
    fi
    

    각 커밋을 하나씩 선택하고 cherry-pick 명령을 실행해야 합니다. 그러나 최신 커밋이 배열의 시작 부분에 있기 때문에 커밋을 역순으로 선택해야 한다는 점을 기억하십시오. 이것이 커밋 배열의 길이 1 인덱스에서 커밋을 선택하기 시작하는 이유입니다.

    # For each commit
    for ((i=$((${#commits[@]}-1));i>=0;i--))
    do
        echo "Cherry Picking ${commits[i]} ..."
        git cherry-pick "${commits[i]}"
        # If the above command fails, then exit with proper message
        if ! [[ $? -eq 0 ]]
        then
            echo "ERROR: Cherry pick commit with ${commits[i]} failed, exiting..."
            exit 2
        fi
        # Show success message for the copied commit
        echo "DONE: Commit ${commits[i]} copied"
    done
    
  • #는 배열의 길이를 찾는 데 사용됩니다.
  • 루프는 length-1에서 시작하고 0보다 작아질 때까지 i를 감소시킵니다.
  • $?는 가장 최근에 실행된 명령의 종료 상태 코드를 가져오는 데 사용됩니다.

  • 최종 스크립트 스크린샷



    Git 프로젝트 커밋 로그

    스크립트 실행 시 스크린샷

    좋은 웹페이지 즐겨찾기