Skip to content

Commit fe14078

Browse files
feat(branch): add force param to overwrite existing branch
1 parent 110ec04 commit fe14078

5 files changed

Lines changed: 110 additions & 7 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "git-essentials",
3-
"version": "0.3.27",
3+
"version": "0.3.28",
44
"description": "The essential GIT commands",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/api/branch.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ type BranchParams = {
2020

2121
/** Update `HEAD` to point at the newly created branch. */
2222
checkout?: boolean
23+
24+
/** Instead of throwing an error if a branched named `ref` already exists, overwrite the existing branch. */
25+
force?: boolean
2326
}
2427

2528
/**
@@ -40,6 +43,7 @@ export async function branch({
4043
gitdir = join(dir, '.git'),
4144
ref,
4245
checkout = false,
46+
force = false,
4347
}: BranchParams): Promise<void> {
4448
try {
4549
assertParameter('fs', fs)
@@ -50,6 +54,7 @@ export async function branch({
5054
gitdir,
5155
ref,
5256
checkout,
57+
force
5358
})
5459
} catch (err: any) {
5560
err.caller = 'git.branch'

src/commands/branch.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type BranchParams = {
1010
gitdir: string
1111
ref: string
1212
checkout?: boolean
13+
force?: boolean
1314
}
1415

1516
/**
@@ -24,16 +25,19 @@ type BranchParams = {
2425
* console.log('done')
2526
*
2627
*/
27-
export async function _branch({ fs, gitdir, ref, checkout = false }: BranchParams): Promise<void> {
28+
export async function _branch(
29+
{ fs, gitdir, ref, checkout = false, force = false }: BranchParams): Promise<void> {
2830
if (ref !== cleanGitRef.clean(ref)) {
2931
throw new InvalidRefNameError(ref, cleanGitRef.clean(ref))
3032
}
3133

3234
const fullref = `refs/heads/${ref}`
3335

34-
const exist = await GitRefManager.exists({ fs, gitdir, ref: fullref })
35-
if (exist) {
36-
throw new AlreadyExistsError('branch', ref, false)
36+
if (!force) {
37+
const exist = await GitRefManager.exists({ fs, gitdir, ref: fullref })
38+
if (exist) {
39+
throw new AlreadyExistsError('branch', ref, false)
40+
}
3741
}
3842

3943
// Get current HEAD tree oid

tests/branch.test.ts

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Errors, branch, init, currentBranch } from '../src'
1+
import { Errors, branch, init, currentBranch, listFiles } from '../src'
22
import { makeFsFixture, FsFixtureData } from './helpers/makeFsFixture'
3-
import { expectToFailWithTypeAsync } from './helpers/assertionHelper'
3+
import { expectNotToFailAsync, expectToFailWithTypeAsync } from './helpers/assertionHelper'
44
import * as path from './helpers/path'
55

66
import branchFsFixtureData from './fixtures/fs/branch.json'
@@ -19,6 +19,89 @@ describe('branch', () => {
1919
expect(await currentBranch({ fs, dir })).toBe('main')
2020
})
2121

22+
it('branch force=false', async () => {
23+
// arrange
24+
const { fs, dir } = await makeFsFixture(branchFsFixtureData as FsFixtureData)
25+
26+
// act
27+
await branch({ fs, dir, ref: 'test-branch' })
28+
29+
// assert
30+
expect(await currentBranch({ fs, dir })).toEqual('main')
31+
expect(await fs.exists(path.resolve(dir, '.git', 'refs/heads/test-branch'))).toBeTruthy()
32+
33+
// act
34+
const action = async () => {
35+
await branch({ fs, dir, ref: 'test-branch' })
36+
}
37+
38+
// assert
39+
await expectToFailWithTypeAsync(action, Errors.AlreadyExistsError)
40+
})
41+
42+
it('branch force=false', async () => {
43+
// arrange
44+
const { fs, dir } = await makeFsFixture(branchFsFixtureData as FsFixtureData)
45+
46+
// act
47+
await branch({ fs, dir, ref: 'test-branch' })
48+
49+
// assert
50+
expect(await currentBranch({ fs, dir })).toEqual('main')
51+
expect(await fs.exists(path.resolve(dir, '.git', 'refs/heads/test-branch'))).toBeTruthy()
52+
53+
// act
54+
const action = async () => {
55+
await branch({ fs, dir, ref: 'test-branch', force: false })
56+
}
57+
58+
// assert
59+
await expectToFailWithTypeAsync(action, Errors.AlreadyExistsError)
60+
})
61+
62+
it('branch force=true', async () => {
63+
// arrange
64+
const { fs, dir } = await makeFsFixture(branchFsFixtureData as FsFixtureData)
65+
66+
// act
67+
await branch({ fs, dir, ref: 'test-branch' })
68+
69+
// assert
70+
expect(await currentBranch({ fs, dir })).toEqual('main')
71+
expect(await fs.exists(path.resolve(dir, '.git', 'refs/heads/test-branch'))).toBeTruthy()
72+
73+
// act
74+
const action = async () => {
75+
await branch({ fs, dir, ref: 'test-branch', force: true })
76+
}
77+
78+
// assert
79+
await expectNotToFailAsync(action)
80+
})
81+
82+
// it('branch with start point force', async () => {
83+
// // arrange
84+
// const { fs, dir } = await makeFsFixture('test-branch-start-point')
85+
86+
// // act
87+
// await branch({ fs, dir, ref: 'test-branch', startPoint: 'start-point' })
88+
89+
// // assert
90+
// expect(await currentBranch({ fs, dir })).toEqual('main')
91+
// expect(await fs.exists(path.resolve(dir, '.git', 'refs/heads/test-branch'))).toBeTruthy()
92+
93+
// // act
94+
// const action = async () => {
95+
// await branch({ fs, dir, ref: 'test-branch', force: true })
96+
// }
97+
98+
// // assert
99+
// await expectNotToFailAsync(action)
100+
// expect(await listFiles({ fs, dir, ref: 'test-branch' })).toEqual([
101+
// 'new-file.txt',
102+
// ])
103+
// })
104+
22105
it('branch --checkout', async () => {
23106
// arrange
24107
const { fs, dir } = await makeFsFixture(branchFsFixtureData as FsFixtureData)

tests/helpers/assertionHelper.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,14 @@ export async function expectToFailWithErrorAsync(action: () => Promise<void>, er
3939
expect(error).toEqual(err)
4040
}
4141

42+
export async function expectNotToFailAsync(action: () => Promise<void>) {
43+
let error: any
44+
45+
try {
46+
await action()
47+
} catch (e: any) {
48+
error = e
49+
}
50+
51+
expect(error).toBeUndefined()
52+
}

0 commit comments

Comments
 (0)