Skip to content

Commit bc77774

Browse files
committed
Update the regular expression for empty branches to respect empty local branches with remote tracking information
Closes #1020
1 parent 5888a51 commit bc77774

File tree

5 files changed

+74
-41
lines changed

5 files changed

+74
-41
lines changed

.changeset/forty-parts-chew.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"simple-git": minor
3+
---
4+
5+
Correctly identify current branch name when using `git.status` in a cloned empty repo.
6+
7+
Previously `git.status` would report the current branch name as `No`. Thank you to @MaddyGuthridge for identifying this issue.

simple-git/src/lib/responses/StatusSummary.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ const parsers: Map<string, StatusLineParser> = new Map([
136136
const behindReg = /behind (\d+)/;
137137
const currentReg = /^(.+?(?=(?:\.{3}|\s|$)))/;
138138
const trackingReg = /\.{3}(\S*)/;
139-
const onEmptyBranchReg = /\son\s([\S]+)$/;
139+
const onEmptyBranchReg = /\son\s(\S+?)(?=\.{3}|$)/;
140140

141141
let regexResult = aheadReg.exec(line);
142142
result.ahead = (regexResult && +regexResult[1]) || 0;
@@ -151,7 +151,9 @@ const parsers: Map<string, StatusLineParser> = new Map([
151151
result.tracking = filterType(regexResult?.[1], filterString, null);
152152

153153
regexResult = onEmptyBranchReg.exec(line);
154-
result.current = filterType(regexResult?.[1], filterString, result.current);
154+
if (regexResult) {
155+
result.current = filterType(regexResult?.[1], filterString, result.current);
156+
}
155157

156158
result.detached = /\(no branch\)/.test(line);
157159
},

simple-git/test/unit/__fixtures__/create-fixture.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type ResponseFixture = {
44
parserArgs: [string, string];
55
};
66

7-
export function createFixture(stdOut: string, stdErr: string): ResponseFixture {
7+
export function createFixture(stdOut: string, stdErr = ''): ResponseFixture {
88
return {
99
stdOut,
1010
stdErr,

simple-git/test/unit/__fixtures__/responses/status.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,16 @@ export function statusResponse(branch = 'main', ...files: Array<string | (() =>
3333

3434
return createFixture(stdOut.join(NULL), '');
3535
}
36+
37+
export const REMOTE_GONE = ' [gone]';
38+
export function emptyRepoStatus(branch = 'main', tracking = '', gone = '') {
39+
const stdOut = [
40+
`## No commits yet on ${branch}`,
41+
tracking && `...${tracking}`,
42+
gone
43+
].join('');
44+
45+
return createFixture(`${stdOut}${NULL}`);
46+
}
47+
48+

simple-git/test/unit/status.spec.ts

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
assertGitError,
55
closeWithError,
66
closeWithSuccess,
7+
emptyRepoStatus,
78
like,
89
newSimpleGit,
910
stagedDeleted,
@@ -122,29 +123,29 @@ describe('status', () => {
122123
path: 'UNKNOWN',
123124
},
124125
],
125-
})
126+
}),
126127
);
127128
});
128129

129130
it('Handles files with non ascii names', () => {
130131
expect(
131-
parseStatusSummary(statusResponse('main', stagedModified('😀 file.ext')).stdOut)
132+
parseStatusSummary(statusResponse('main', stagedModified('😀 file.ext')).stdOut),
132133
).toEqual(
133134
like({
134135
current: 'main',
135136
modified: ['😀 file.ext'],
136-
})
137+
}),
137138
);
138139
});
139140

140141
it('Handles files with spaces in their names', () => {
141142
expect(
142-
parseStatusSummary(statusResponse('main', stagedModified('foo bar.ext')).stdOut)
143+
parseStatusSummary(statusResponse('main', stagedModified('foo bar.ext')).stdOut),
143144
).toEqual(
144145
like({
145146
current: 'main',
146147
modified: ['foo bar.ext'],
147-
})
148+
}),
148149
);
149150
});
150151

@@ -154,7 +155,7 @@ describe('status', () => {
154155
...empty,
155156
ignored: ['ignored.ext'],
156157
files: [],
157-
})
158+
}),
158159
);
159160
});
160161

@@ -164,7 +165,7 @@ describe('status', () => {
164165
...empty,
165166
current: 'main',
166167
renamed: [{ from: 'file.ext', to: 'file.ext' }],
167-
})
168+
}),
168169
);
169170
});
170171

@@ -174,20 +175,20 @@ describe('status', () => {
174175
...empty,
175176
current: 'main',
176177
renamed: [{ from: 'from.ext', to: 'to.ext' }],
177-
})
178+
}),
178179
);
179180
});
180181

181182
it('Handles staged rename with un-staged modifications', () => {
182183
expect(
183-
parseStatusSummary(statusResponse('main', stagedRenamedWithModifications).stdOut)
184+
parseStatusSummary(statusResponse('main', stagedRenamedWithModifications).stdOut),
184185
).toEqual(
185186
like({
186187
...empty,
187188
current: 'main',
188189
renamed: [{ from: 'from.ext', to: 'to.ext' }],
189190
modified: ['to.ext'],
190-
})
191+
}),
191192
);
192193
});
193194

@@ -196,58 +197,68 @@ describe('status', () => {
196197
like({
197198
current: 'main',
198199
modified: ['staged-modified.ext'],
199-
})
200+
}),
200201
);
201202
});
202203

203204
it('Handles (un)staged deleted', () => {
204205
expect(
205-
parseStatusSummary(statusResponse('main', stagedDeleted, unStagedDeleted).stdOut)
206+
parseStatusSummary(statusResponse('main', stagedDeleted, unStagedDeleted).stdOut),
206207
).toEqual(
207208
like({
208209
current: 'main',
209210
created: [],
210211
modified: [],
211212
deleted: ['staged-deleted.ext', 'un-staged-deleted.ext'],
212213
staged: ['staged-deleted.ext'],
213-
})
214+
}),
214215
);
215216
});
216217

217218
it('Initial repo with no commits', () => {
218-
const statusSummary = parseStatusSummary(`## No commits yet on master`);
219+
const statusSummary = parseStatusSummary(emptyRepoStatus('master').stdOut);
219220

220221
expect(statusSummary).toEqual(
221222
like({
222223
current: `master`,
223-
})
224+
tracking: null,
225+
}),
224226
);
225227
});
226228

229+
it('parses cloned empty repo with no commits', () => {
230+
const actual = parseStatusSummary(emptyRepoStatus('main', 'origin/blah').stdOut);
231+
232+
expect(actual).toEqual(like({
233+
tracking: 'origin/blah',
234+
current: 'main',
235+
}));
236+
});
237+
227238
it('Complex status - renamed, new and un-tracked modifications', () => {
228239
const statusSummary = parseStatusSummary(
229240
statusResponse(
230241
'master',
231242
' M other.txt',
232243
'A src/b.txt',
233-
stagedRenamed('src/a.txt', 'src/c.txt')
234-
).stdOut
244+
stagedRenamed('src/a.txt', 'src/c.txt'),
245+
).stdOut,
235246
);
236247

237248
expect(statusSummary).toEqual(
238249
like({
239250
created: ['src/b.txt'],
240251
modified: ['other.txt'],
241252
renamed: [{ from: 'src/a.txt', to: 'src/c.txt' }],
242-
})
253+
}),
243254
);
244255
});
245256

246257
it('Handles renamed', () => {
247258
expect(parseStatusSummary(` R src/another-file.js${NULL}src/file.js`)).toEqual(
248259
like({
249260
renamed: [{ from: 'src/file.js', to: 'src/another-file.js' }],
250-
})
261+
}),
251262
);
252263
});
253264

@@ -258,7 +269,7 @@ describe('status', () => {
258269
tracking: 'origin/master',
259270
ahead: 3,
260271
behind: 0,
261-
})
272+
}),
262273
);
263274
});
264275

@@ -270,7 +281,7 @@ describe('status', () => {
270281
tracking: 'origin/master',
271282
ahead: 0,
272283
behind: 2,
273-
})
284+
}),
274285
);
275286
});
276287

@@ -281,7 +292,7 @@ describe('status', () => {
281292
tracking: 'origin/release/0.34.0',
282293
ahead: 0,
283294
behind: 0,
284-
})
295+
}),
285296
);
286297
});
287298

@@ -293,7 +304,7 @@ describe('status', () => {
293304
tracking: null,
294305
ahead: 0,
295306
behind: 0,
296-
})
307+
}),
297308
);
298309
});
299310

@@ -313,7 +324,7 @@ describe('status', () => {
313324
conflicted: [],
314325
deleted: [],
315326
...result,
316-
})
327+
}),
317328
);
318329
});
319330

@@ -322,7 +333,7 @@ describe('status', () => {
322333
like({
323334
current: 'this_branch',
324335
tracking: null,
325-
})
336+
}),
326337
);
327338
});
328339

@@ -346,37 +357,37 @@ describe('status', () => {
346357
modified: [],
347358
not_added: [],
348359
conflicted: [],
349-
})
360+
}),
350361
);
351362
});
352363

353364
it('staged modified files identified separately to other modified files', () => {
354365
const statusSummary = parseStatusSummary(
355-
`## master${NULL} M aaa${NULL}M bbb${NULL}A ccc${NULL}?? ddd`
366+
`## master${NULL} M aaa${NULL}M bbb${NULL}A ccc${NULL}?? ddd`,
356367
);
357368
expect(statusSummary).toEqual(
358369
like({
359370
staged: ['bbb', 'ccc'],
360371
modified: ['aaa', 'bbb'],
361-
})
372+
}),
362373
);
363374
});
364375

365376
it('staged modified file with modifications after staging', () => {
366377
const statusSummary = parseStatusSummary(
367-
`## master${NULL}MM staged-modified${NULL} M modified${NULL}M staged`
378+
`## master${NULL}MM staged-modified${NULL} M modified${NULL}M staged`,
368379
);
369380
expect(statusSummary).toEqual(
370381
like({
371382
staged: ['staged-modified', 'staged'],
372383
modified: ['staged-modified', 'modified', 'staged'],
373-
})
384+
}),
374385
);
375386
});
376387

377388
it('modified status', () => {
378389
const statusSummary = parseStatusSummary(
379-
` M package.json${NULL}M src/git.js${NULL}AM src/index.js${NULL} A src/newfile.js${NULL}?? test${NULL}UU test.js`
390+
` M package.json${NULL}M src/git.js${NULL}AM src/index.js${NULL} A src/newfile.js${NULL}?? test${NULL}UU test.js`,
380391
);
381392

382393
expect(statusSummary).toEqual(
@@ -387,14 +398,14 @@ describe('status', () => {
387398
not_added: ['test'],
388399
conflicted: ['test.js'],
389400
staged: ['src/git.js', 'src/index.js'],
390-
})
401+
}),
391402
);
392403
});
393404

394405
it('index/wd status', () => {
395406
const statusSummary = parseStatusSummary(
396407
statusResponse('main', ` M src/git_wd.js`, `MM src/git_ind_wd.js`, `M src/git_ind.js`)
397-
.stdOut
408+
.stdOut,
398409
);
399410
expect(statusSummary).toEqual(
400411
like({
@@ -403,15 +414,15 @@ describe('status', () => {
403414
{ path: 'src/git_ind_wd.js', index: 'M', working_dir: 'M' },
404415
{ path: 'src/git_ind.js', index: 'M', working_dir: ' ' },
405416
],
406-
})
417+
}),
407418
);
408419
});
409420

410421
it('Report conflict when both sides have added the same file', () => {
411422
expect(parseStatusSummary(statusResponse(`master`, `AA filename`).stdOut)).toEqual(
412423
like({
413424
conflicted: ['filename'],
414-
})
425+
}),
415426
);
416427
});
417428

@@ -425,8 +436,8 @@ describe('status', () => {
425436
'UD src/newfile.js',
426437
'AU test.js',
427438
'UA test',
428-
'AA test-foo.js'
429-
).stdOut
439+
'AA test-foo.js',
440+
).stdOut,
430441
);
431442

432443
expect(statusSummary).toEqual(
@@ -440,7 +451,7 @@ describe('status', () => {
440451
'test',
441452
'test-foo.js',
442453
],
443-
})
454+
}),
444455
);
445456
});
446457
});

0 commit comments

Comments
 (0)