Skip to content

Commit ce4cede

Browse files
committed
Add repo.currentBranch() method
1 parent a74444b commit ce4cede

File tree

7 files changed

+81
-25
lines changed

7 files changed

+81
-25
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## next
22

3+
- Added `repo.currentBranch()` method
34
- Added `repo.describeRef(ref)` method, which returns an information object about the reference
45
- Added `repo.isOid(value)` method to check if a value is an object ID
56

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ The algorithm to identify a default branch name:
5757
- `main`
5858
- `master`
5959

60+
#### repo.currentBranch()
61+
62+
Returns the current branch name along with its commit oid.
63+
If the repository is in a detached HEAD state, `name` will be `null`.
64+
65+
```js
66+
const currentBranch = repo.currentBranch();
67+
// { name: 'main', oid: '8bb6e23769902199e39ab70f2441841712cbdd62' }
68+
69+
const detachedHead = repo.currentBranch();
70+
// { name: null, oid: '8bb6e23769902199e39ab70f2441841712cbdd62' }
71+
```
72+
6073
#### repo.isRefExists(ref)
6174

6275
Checks if a `ref` exists.

fixtures/base/collect-data.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { fileURLToPath } from 'url';
44
import { createGitReader, parseTree } from '../../lib/index.js';
55

66
const repo = await createGitReader(fileURLToPath(new URL('_git', import.meta.url)));
7+
const defaultBranch = await repo.defaultBranch();
8+
const currentBranch = await repo.currentBranch();
79
const commits = await repo.log();
810
const stat = await repo.stat();
911
const objects = {};
@@ -38,6 +40,8 @@ fs.writeFileSync(
3840
fileURLToPath(new URL('data.json', import.meta.url)),
3941
JSON.stringify(
4042
{
43+
defaultBranch,
44+
currentBranch,
4145
commits,
4246
filesLists,
4347
filesDelta,

fixtures/base/data.json

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
{
2+
"defaultBranch": "main",
3+
"currentBranch": {
4+
"name": "test",
5+
"oid": "2dbee47a8d4f8d39e1168fad951b703ee05614d6"
6+
},
27
"commits": [
38
{
49
"oid": "2dbee47a8d4f8d39e1168fad951b703ee05614d6",

fixtures/clean/_git/HEAD

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ref: refs/heads/development
1+
ref: refs/heads/empty-branch

src/resolve-ref.ts

+33-23
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ export async function createRefIndex(gitdir: string) {
9090
}
9191

9292
const refInfo = await refResolver.resolve(expandedRef);
93-
9493
const [, scope, path] = expandedRef.match(/^([^/]+\/[^/]+)\/(.+)$/) || [
9594
'',
9695
'refs/heads',
@@ -163,6 +162,37 @@ export async function createRefIndex(gitdir: string) {
163162
.replace(/^ref:\s*/, '')
164163
);
165164

165+
const currentBranch = async function () {
166+
const { ref, oid } = await describeRef('HEAD');
167+
const name = ref ? (await describeRef(ref)).name : null;
168+
169+
return {
170+
name,
171+
oid
172+
};
173+
};
174+
175+
// inspired by https://usethis.r-lib.org/reference/git-default-branch.html
176+
const defaultBranch = async function () {
177+
const branches = (await listBranches()) as string[]; // FIXME: remove string[]
178+
179+
if (branches.length <= 1) {
180+
return basename(branches[0]);
181+
}
182+
183+
const branchRef =
184+
expandRef('refs/remotes/upstream/HEAD') ||
185+
expandRef('refs/remotes/origin/HEAD') ||
186+
expandRef('refs/heads/main') ||
187+
expandRef('refs/heads/master');
188+
189+
if (branchRef) {
190+
return branchRef.endsWith('/HEAD') ? readRefContent(branchRef) : basename(branchRef);
191+
}
192+
193+
return null;
194+
};
195+
166196
return {
167197
isOid,
168198
isRefExists: (ref: string) => expandRef(ref) !== null,
@@ -175,28 +205,8 @@ export async function createRefIndex(gitdir: string) {
175205
listBranches,
176206
listTags,
177207

178-
// inspired by https://usethis.r-lib.org/reference/git-default-branch.html
179-
async defaultBranch() {
180-
const branches = (await listBranches()) as string[]; // FIXME: remove string[]
181-
182-
if (branches.length === 1) {
183-
return basename(branches[0]);
184-
}
185-
186-
const branchRef =
187-
expandRef('refs/remotes/upstream/HEAD') ||
188-
expandRef('refs/remotes/origin/HEAD') ||
189-
expandRef('refs/heads/main') ||
190-
expandRef('refs/heads/master');
191-
192-
if (branchRef) {
193-
return branchRef.endsWith('/HEAD')
194-
? readRefContent(branchRef)
195-
: basename(branchRef);
196-
}
197-
198-
return null;
199-
},
208+
defaultBranch,
209+
currentBranch,
200210

201211
async stat() {
202212
const remotes = listRemotes();

test/resolve-ref.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ describe('resolve-ref', () => {
1616
describe('defaultBranch()', () => {
1717
const defaultBranches = {
1818
base: 'main',
19+
detached: 'main',
1920
cruft: 'main',
2021
'no-remotes': 'main',
2122
upstream: 'fork-main',
22-
clean: 'development' // FIXME
23+
clean: 'empty-branch' // FIXME
2324
};
2425

2526
for (const [repoName, expected] of Object.entries(defaultBranches)) {
@@ -34,6 +35,28 @@ describe('resolve-ref', () => {
3435
}
3536
});
3637

38+
describe('currentBranch()', () => {
39+
const defaultBranches = {
40+
base: { name: 'test', oid: '2dbee47a8d4f8d39e1168fad951b703ee05614d6' },
41+
detached: { name: null, oid: '2dbee47a8d4f8d39e1168fad951b703ee05614d6' },
42+
cruft: { name: 'main', oid: '7b84f676f2fbea2a3c6d83924fa63059c7bdfbe2' },
43+
'no-remotes': { name: 'main', oid: '293e1ffaf7158c249fc654aec07eca555a25de09' },
44+
upstream: { name: 'fork-main', oid: '293e1ffaf7158c249fc654aec07eca555a25de09' },
45+
clean: { name: 'empty-branch', oid: null } // FIXME
46+
};
47+
48+
for (const [repoName, expected] of Object.entries(defaultBranches)) {
49+
(repoName === 'clean' ? it.skip : it)(repoName, async () => {
50+
const repo = await fixtures[repoName].repo();
51+
const actual = await repo.currentBranch();
52+
53+
assert.deepStrictEqual(actual, expected);
54+
55+
return repo.dispose();
56+
});
57+
}
58+
});
59+
3760
describe('listBranches()', () => {
3861
it('local branches', async () => {
3962
const actual = await repo.listBranches();

0 commit comments

Comments
 (0)