fix: handle detached head error

This commit is contained in:
copilot-swe-agent[bot]
2025-12-23 16:14:05 +00:00
committed by Emilien Escalle
parent 3984b38120
commit 945d269b25
2 changed files with 33 additions and 4 deletions

View File

@@ -285,6 +285,33 @@ describe('ref', () => {
expect(ref).toEqual('refs/heads/main');
});
it('infers ref from local branch when detached HEAD returns only "grafted, HEAD"', async () => {
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
const fullCmd = `${cmd} ${args?.join(' ')}`;
let result = '';
switch (fullCmd) {
case 'git branch --show-current':
result = '';
break;
case 'git show -s --pretty=%D':
result = 'grafted, HEAD';
break;
case 'git for-each-ref --format=%(refname) --contains HEAD --sort=-committerdate refs/heads/':
result = 'refs/heads/main\nrefs/heads/develop';
break;
}
return Promise.resolve({
stdout: result,
stderr: '',
exitCode: 0
});
});
const ref = await Git.ref();
expect(ref).toEqual('refs/heads/main');
});
it('infers ref from remote branch when no local branch contains HEAD', async () => {
jest.spyOn(Exec, 'getExecOutput').mockImplementation((cmd, args): Promise<ExecOutput> => {
const fullCmd = `${cmd} ${args?.join(' ')}`;

View File

@@ -124,18 +124,20 @@ export class Git {
const res = await Git.exec(['show', '-s', '--pretty=%D']);
core.debug(`detached HEAD ref: ${res}`);
if (res === 'HEAD') {
const normalizedRef = res.replace(/^grafted, /, '').trim();
if (normalizedRef === 'HEAD') {
return await Git.inferRefFromHead();
}
// Can be "HEAD, <tagname>" or "grafted, HEAD, <tagname>"
const refMatch = res.match(/^(grafted, )?HEAD, (.*)$/);
const refMatch = normalizedRef.match(/^HEAD, (.*)$/);
if (!refMatch || !refMatch[2]) {
if (!refMatch || !refMatch[1]) {
throw new Error(`Cannot find detached HEAD ref in "${res}"`);
}
const ref = refMatch[2].trim();
const ref = refMatch[1].trim();
// Tag refs are formatted as "tag: <tagname>"
if (ref.startsWith('tag: ')) {