gitlab ci 管道中的分离头 - 如何正确推送

Detached head in gitlab ci pipeline - how to push correctly

我在 CI 管道中的存储库的分离头遇到了一些问题。在管道的构建阶段,我是 运行 一个脚本,它更改了一个特定的文件。更改此文件后将推送到存储库。

before_script:
  - git config --global user.name "Bot"
  - git config --global user.email "ci@domain.com"
  - git status
script:
  - npx ts-node ./generate.ts
  - git push "https://git:${GIT_PUSH_TOKEN}@${CI_REPOSITORY_URL#*@}" "HEAD:main"
  - git status

运行 脚本给我输出

Fetching changes with git depth set to 50...
Initialized empty Git repository in /builds/fKSu5-y_/0/project/.git/
Created fresh repository.
Checking out 9b4a88be as main...

$ git status
HEAD detached at 9b4a88be

$ git push "https://git:${GIT_PUSH_TOKEN}@${CI_REPOSITORY_URL#*@}" "HEAD:main"
To https://gitlab.domain.com/project.git
9b4a88b..98be83e  HEAD -> main

$ git status
HEAD detached from 9b4a88b

我不明白为什么before_script中的第一个git status已经给我一个超脱的头。

我认为管道通过初始提取创建了一个分离的存储库。所以问题是如何以正确的方式处理我的推送。 在我的发布阶段,我是 运行 semantic-release,如果我执行上一次推送,它会因为头部分离而失败。如果我禁用推送,语义释放将按预期工作。但我当然需要推动。我没看到,我做错了什么。


更新

在 before_script 中添加 git checkout main 给我第一个 git status 预期的结果。但是在 push 命令之后我仍然有分离的头 - 我不明白。

$ git checkout main
Branch 'main' set up to track remote branch 'main' from 'origin'.
Switched to a new branch 'main'

$ git status
On branch main
Your branch is up to date with 'origin/main'.

$ git push "https://git:${GIT_PUSH_TOKEN}@${CI_REPOSITORY_URL#*@}" "HEAD:main"
To https://gitlab.domain.com/project.git
  336b065..8299e43  HEAD -> main

$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

尽管推送在发布状态下工作的所有内容 semantic-release 仍然无法正常工作。我得到:The local branch main is behind the remote one, therefore a new version won't be published.

I do not understand why the first git status in the before_script already gives me a detached head.

I think the pipeline creates a detached repository by initial fetching.

你是对的,GitLab CI 确实签出特定的提交而不是某个分支。但是,您可以将 git checkout "$CI_COMMIT_REF_NAME" 添加到 before_script:

before_script:
  - git config --global user.name "Bot"
  - git config --global user.email "ci@domain.com"
  - git checkout "$CI_COMMIT_REF_NAME"
  - git status

这可能会对某人有所帮助。基于gitlab.

The detached state is actually intended, as the runner is specifically designed to checkout the repository using a specific commit (the one that triggered the pipeline). When a specific commit is checked out, the repository is then considered to be in a "detached HEAD" state.

这是我的管道中的一个示例,在更改一些文件后,它将它们推送到 master(在新的 repos 中将 master 更改为 main)。

git remote set-url origin http://$user:$token@gitlab.com/<group>/<group>/$service.git
git add <file that changed>
git config --global user.email "<user email>"
git config --global user.name "<user name>"
git commit -m "Updated service $service"
git push -o ci.skip origin HEAD:master

-o ci.skip - 是在推送到 repo 后停止 运行 另一个管道。

在 gitlab 中,您可以执行以下操作以 select 来自 gitlab 变量的默认分支:

git push -o ci.skip origin HEAD:$CI_DEFAULT_BRANCH

要显示所有变量,请将 CI_DEBUG_TRACE: "true" 添加到变量部分。

我花了很多时间尝试解决同样的问题,最后我发现有git策略:https://docs.gitlab.com/ee/ci/runners/configure_runners.html#git-strategy

当设置 fetch 时,它 re-uses 本地工作副本(如果不存在则回退到克隆)。所以这就是为什么它第一次对我有用然后它停止工作并且我的签出分支落后并且提前提交的数量随着另一个提交而增加的原因。

那么解决起来就很简单了。您只需要将 GIT_STRATEGY 变量定义为 clone.

variables:
  GIT_STRATEGY: clone

我的 publish 工作示例:

publish:
  stage: publish
  rules:
    - if: $CI_COMMIT_BRANCH == "master"
      when: manual
  variables:
    GIT_STRATEGY: clone
  script:
    - git checkout -b $CI_COMMIT_BRANCH
    - echo "define what you want to change"
    - 'git commit -am "your commit message" || echo "No changes to commit"'
    - git push --set-upstream origin $CI_COMMIT_BRANCH

您还可以在全局变量或管道配置中定义 clone 策略 https://docs.gitlab.com/ee/ci/pipelines/settings.html#choose-the-default-git-strategy