changesets: CI builds fail with "does master exist?"

Affected Packages

@changesets/cli @changesets/git

Problem

It seems that 2.13.0 of @changesets/cli broke our CI builds. (I’m assuming that’s because of the update to @changesets/git.) We now get this when running changeset status on PRs:

🦋  error Error: Failed to find where HEAD diverged from master. Does master exist?
🦋  error     at getDivergedCommit (/opt/hostedtoolcache/node/12.20.1/x64/lib/node_modules/@changesets/cli/node_modules/@changesets/git/dist/git.cjs.dev.js:58:11)
🦋  error     at async getChangedFilesSince (/opt/hostedtoolcache/node/12.20.1/x64/lib/node_modules/@changesets/cli/node_modules/@changesets/git/dist/git.cjs.dev.js:169:22)
🦋  error     at async Object.getChangedPackagesSinceRef (/opt/hostedtoolcache/node/12.20.1/x64/lib/node_modules/@changesets/cli/node_modules/@changesets/git/dist/git.cjs.dev.js:208:24)
🦋  error     at async getStatus (/opt/hostedtoolcache/node/12.20.1/x64/lib/node_modules/@changesets/cli/dist/cli.cjs.dev.js:953:27)
🦋  error     at async run$1 (/opt/hostedtoolcache/node/12.20.1/x64/lib/node_modules/@changesets/cli/dist/cli.cjs.dev.js:1197:11)

We’re running this on Ubuntu machines (“latest” version) in Azure Pipelines. Couldn’t reproduce the problem locally.

Confirmed that installing @changesets/cli version 2.12.0 fixed the problem.

Proposed solution

🤷‍♂️ No clue. Let me know if there is other info I can provide to help debug. Thanks!

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 10
  • Comments: 40 (24 by maintainers)

Commits related to this issue

Most upvoted comments

For those of you struggling with this in GitHub Actions workflows triggered by pull requests, here’s what works for me:

  1. Check out the branch rather than the result of merging main into your branch. Also get the full commit history.
    uses: actions/checkout@v3
    with:
      ref: ${{github.event.pull_request.head.sha}}
      fetch-depth: 0
    
  2. The workflow runner hasn’t checked out main locally, so refer to it as origin/main in the changeset status command.
    run: npx changeset status --since origin/main
    

For anyone struggling with this in GitLab, I ended up using this in my job:

  script:
    # Required so that Changesets can compare with main branch
    - git config --global --add safe.directory /builds/path/to/project-name
    - git pull -f origin main:main
    - npx changeset status

Please let me know if there’s any major downsides to this approach that I am not aware of 😬

@nategreen I don’t quite see in this log the moment in which changesets are invoked 🤔

@akphi it’s quite hard to tell what has gone wrong - all refs should be downloaded in your case as per the action’s source code: https://github.com/actions/checkout/blob/25a956c84d5dd820d28caab9f86b8d183aeeff3d/src/git-source-provider.ts#L128-L134

Could you try running those on your action before you invoke changeset?

git merge-base master HEAD
git merge-base origin/master HEAD
git branch -r

It seems like there are two different things that can cause the issue:

  • git clone’ing in a way that doesn’t fetch the master refer (to origin/master) at all
  • git clone’ing all the refs, but not actually creating a local branch

If you’re having the second problem (which I am, on CircleCI not GH Actions), it looks like there’s a much simpler solution: just pass --since=origin/master instead of master.

Another thought would be to put origin/master as the baseBranch in config.json. As far as I can tell from a quick glance in the source, the only thing the tool ever actually does with baseBranch is pass it to git merge-base BASE_BRANCH HEAD, which can be any ref, not just a branch, so this seems fine. (If it did things like check out the given baseBranch, that would be tougher.) This does have the downside of breaking for users who choose a different remote name locally, though.

I believe this is a compat issue with Github Check Action v2 and changeset status, specifically:

  • Creates a local branch - No longer detached HEAD when checking out a branch
  • Improved performance - Fetches only a single commit by default

In case this is helpful to others, this works for me:

- name: Check out repository code
  uses: actions/checkout@v1
  with:
    fetch-depth: 0

// ... install node, yarn install

- name: Check for Changesets
  run: |
    git pull -f origin main:main
    yarn changeset status --since=main

This could fix the issue mentioned in your comment but there are other ones mentioned in this thread and this would not fix them as in those cases “since” is an unknown ref (it has not been fetched at all).

I also have a similar problem with the following setup:

  • Default branch: develop
  • Production branch: main
  • In config.json I have set "baseBranch": "main"
  • Added fetch-depth: 0 to workflow

But I still get this error: error Error: Failed to find where HEAD diverged from main. Does main exist?

I tried adding git fetch origin main:main before the changeset cmd but it still gives the same error:

Run git fetch origin main:main
  git fetch origin main:main
  npx changeset status
  shell: /usr/bin/bash -e {0}
From owner/repo
 * [new branch]      main       -> main
 * [new branch]      main       -> origin/main
🦋  error Error: Failed to find where HEAD diverged from main. Does main exist?

Could this be due to the way checkout is done for PRs? Checkout step logs:

 /usr/bin/git checkout --progress --force refs/remotes/pull/117/merge
  Note: switching to 'refs/remotes/pull/117/merge'.
  
  You are in 'detached HEAD' state. You can look around, make experimental
  changes and commit them, and you can discard any commits you make in this
  state without impacting any branches by switching back to a branch.
  

Are you sure that your setup was/is working correctly with the @changesets/cli@2.12.0? I would suspect that it just always return success from the status command (if it’s not erroring).

I was able to reproduce your issue using the given git commands and they just don’t lead to a proper checkout - is it, maybe, done afterward in your pipeline? Your cwd is pretty much empty, without any files in it (well, not counting .git directory). You are on a local master branch that has no commits on it. I would expect you to sync your empty master branch with the correct remote by doing smth like:

git pull -f origin master:master

This won’t completely solve the issue yet - because the status compares the current HEAD to your base branch and you are not checked out on the correct commit yet! at this point. So I would expect that you’d run changeset status after doing a proper checkout.