ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Github Actions에서 발생하는 detached HEAD 문제 해결하기
    Project 2023. 12. 9. 19:37

     

    현재상황

    현 프로젝트에서 develop 브랜치에 머지하기 위해서는 반드시 PR을 통해 머지해야한다. 

    따라서 Github Actions의 Java CI with Gradle 작업을 활용하여 CI를 다음과 같이 자동화시켰다. 

     

    name: Java CI with Gradle
    
    on:
      push:
        branches: [ "develop" ]
      pull_request:
        branches: [ "develop" ]
    
    permissions:
      contents: read
    
    
    jobs:
      build:
        runs-on: ubuntu-latest
        permissions: write-all
    
        steps:
          - name: Checkout repository
            uses: actions/checkout@v3
            with:
              fetch-depth: 0
    
          - name: Formatting with google java
            uses: axel-op/googlejavaformat-action@v3
    
          - name: Set up JDK 11
            uses: actions/setup-java@v3
            with:
              java-version: '11'
              distribution: 'temurin'
    
    -- 중략

     

     

    develop 브랜치로 PR 요청이 오거나 푸시 이벤트가 발생하면 자동으로 해당 스텝들이 순차적으로 수행된다. 

     

    먼저 checkout 을 통해 레포에 올려둔 최신 코드를 CI 서버로 내려받은 후에 특정 브랜치로 전환한다. 

    -> 다음으로는 코드컨벤션인 Google Java Format 작업을 진행하며 코드 포맷팅 작업을 수행한다. 
    -> 이후로 빌드 테스트를 진행하는 방식으로 진행된다. 

     

     

     

    문제상황

     

    그러나 develop으로 PR을 올릴때마다 특정경우에 checkout 다음 단계인 포맷팅 스텝에서 다음과 같은 에러가 발생했다.

     

    실패처리된 Github Actions의 로그를 들여다보면 메시지는 다음과 같다.

    Committing changes
    /usr/bin/git commit --all -m Google Java Format
    [detached HEAD 1f34099] Google Java Format
    1 file changed, 1 deletion(-)
    /usr/bin/git push
    fatal: You are not currently on a branch.
    To push the history leading to the current (detached HEAD)
    state now, use


    git push origin HEAD:<name-of-remote-branch>

    Error: The command 'git' failed with exit code 128

     

    현재 작업내용이 브랜치에 없으니 히스토리를 현재 브랜치로 가져오기 위해 푸시하라는 내용이다. 

     

    처음엔 포맷팅에 문제가 발생한 줄 알았으나 GIthub Repo에 Network 설정을 확인하고 현재상황을 이해할 수 있었다. 

     

    Github 레포의 Insights 탭에있는 Network로 현재 브랜치 상황을 한눈에 볼 수 있다. 

     

     

     

    병합 대상인 refactor/42-권한확인 브랜치가 develop보다 앞서있는 상황에서 develop에 머지하려니 head가 분리되었다는 에러메시지가 뜬다.

     

    actions/checkout 액션을 통해 가져온 커밋이 refactor/42-권한확인 브랜치 히스토리에 없기 때문에

    HEAD는 브랜치가 아닌 해당 커밋 자체를 직접 가리키게 되고 이것이 "detached HEAD"상태인 것이다. 

     

     

    똑같이 develop에서 분기되었지만 develop보다 이전인 feat/31-주문확인서비스 브랜치에는 develop으로 요청한 PR에서 해당 에러가 발생하지 않았다. 해당 경우는 브랜치 히스토리에서 체크아웃 커밋을 확인할 수 있기 때문이다. 

     

     

    따라서 해당 에러가 발생하지 않으려면 현재 PR을 올린 브랜치 기준으로 작업내용을 새로 받아와서 체크아웃 해줘야한다. 

     

    브랜치 기준으로 작업내용을 받아오도록 checkout 스텝에 설정을 추가한다.

     

        steps:
          - name: Checkout repository
            uses: actions/checkout@v3
            with:
              fetch-depth: 0
              ref: ${{ github.event.pull_request.head.ref }}

     

     

    ref 옵션을 활용하여 특정 브랜치를 명시해주는데, PR이벤트가 발생한 head의 브랜치명을 가져와서 설정해준다. 

     

    42 브랜치에서 새로운 PR을 생성하면, ${{ github.event.pull_request.head.ref }}은 42번 브랜치를 명시할 것이다.

     

    따라서 워크플로우는 42번 브랜치의 모든 히스토리를 가져와서 체크아웃하기 때문에 그 브랜치의 최신 커밋을 HEAD가 가리키도록 설정될 것이다. 

     

    추가로 fetch-depth 설정을 0으로 하여 해당 브랜치에서 기존에 있는 모든 히스토리들을 가져올 수 있도록 함께 설정한다. 

     

     

     

    다음과 같이 yml 파일을 수정하고 push 하면 이제 Network 상황이 다음처럼 변하면서 detached branch 에러는 발생하지 않게된다.

     

    Github Action 수행로그 확인

     

    Reference: https://github.com/actions/checkout/issues/124

Designed by Tistory.