export async function getChangesSinceMergeBase()

in paths-filter/src/git.ts [54:133]


export async function getChangesSinceMergeBase(base: string, head: string, initialFetchDepth: number): Promise<File[]> {
  let baseRef: string | undefined
  let headRef: string | undefined
  async function hasMergeBase(): Promise<boolean> {
    if (baseRef === undefined || headRef === undefined) {
      return false
    }
    return (await getExecOutput('git', ['merge-base', baseRef, headRef], {ignoreReturnCode: true})).exitCode === 0
  }

  let noMergeBase = false
  core.startGroup(`Searching for merge-base ${base}...${head}`)
  try {
    baseRef = await getLocalRef(base)
    headRef = await getLocalRef(head)
    if (!(await hasMergeBase())) {
      await getExecOutput('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, head])
      if (baseRef === undefined || headRef === undefined) {
        baseRef = baseRef ?? (await getLocalRef(base))
        headRef = headRef ?? (await getLocalRef(head))
        if (baseRef === undefined || headRef === undefined) {
          await getExecOutput('git', ['fetch', '--tags', '--depth=1', 'origin', base, head], {
            ignoreReturnCode: true // returns exit code 1 if tags on remote were updated - we can safely ignore it
          })
          baseRef = baseRef ?? (await getLocalRef(base))
          headRef = headRef ?? (await getLocalRef(head))
          if (baseRef === undefined) {
            throw new Error(
              `Could not determine what is ${base} - fetch works but it's not a branch, tag or commit SHA`
            )
          }
          if (headRef === undefined) {
            throw new Error(
              `Could not determine what is ${head} - fetch works but it's not a branch, tag or commit SHA`
            )
          }
        }
      }

      let depth = initialFetchDepth
      let lastCommitCount = await getCommitCount()
      while (!(await hasMergeBase())) {
        depth = Math.min(depth * 2, Number.MAX_SAFE_INTEGER)
        await getExecOutput('git', ['fetch', `--deepen=${depth}`, 'origin', base, head])
        const commitCount = await getCommitCount()
        if (commitCount === lastCommitCount) {
          core.info('No more commits were fetched')
          core.info('Last attempt will be to fetch full history')
          await getExecOutput('git', ['fetch'])
          if (!(await hasMergeBase())) {
            noMergeBase = true
          }
          break
        }
        lastCommitCount = commitCount
      }
    }
  } finally {
    core.endGroup()
  }

  // Three dots '...' change detection - finds merge-base and compares against it
  let diffArg = `${baseRef}...${headRef}`
  if (noMergeBase) {
    core.warning('No merge base found - change detection will use direct <commit>..<commit> comparison')
    diffArg = `${baseRef}..${headRef}`
  }

  // Get changes introduced on ref compared to base
  core.startGroup(`Change detection ${diffArg}`)
  let output = ''
  try {
    output = (await getExecOutput('git', ['diff', '--no-renames', '--name-status', '-z', diffArg])).stdout
  } finally {
    fixStdOutNullTermination()
    core.endGroup()
  }

  return parseGitDiffOutput(output)
}