@@ -197,6 +197,7 @@ describe('pushSkills', () => {
197197 mockGit . commit . mockResolvedValue ( undefined ) ;
198198 mockGit . push . mockResolvedValue ( undefined ) ;
199199 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
200+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
200201
201202 const result = await pushSkills ( tempDir , 'test commit' ) ;
202203
@@ -240,8 +241,10 @@ describe('pushSkills', () => {
240241 mockGit . add . mockResolvedValue ( undefined ) ;
241242 mockGit . commit . mockResolvedValue ( undefined ) ;
242243 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
243- // rev-list fails because origin/main doesn't exist yet
244- mockGit . raw . mockRejectedValue ( new Error ( 'unknown revision origin/main' ) ) ;
244+ // rev-list origin/main..HEAD fails, then rev-list HEAD --count returns commit count
245+ mockGit . raw
246+ . mockRejectedValueOnce ( new Error ( 'unknown revision origin/main' ) )
247+ . mockResolvedValueOnce ( '1\n' ) ;
245248 mockGit . push . mockResolvedValue ( undefined ) ;
246249
247250 const result = await pushSkills ( tempDir , 'initial' ) ;
@@ -251,12 +254,34 @@ describe('pushSkills', () => {
251254 expect ( result ) . toEqual ( { committed : true , pushed : true } ) ;
252255 } ) ;
253256
257+ it ( 'pushes existing commits when tree is clean but remote branch never existed' , async ( ) => {
258+ // User scenario: first push committed but failed to push (no gh cli/remote repo),
259+ // then user installs gh cli + creates remote, runs push again — tree is clean but
260+ // local has commits that were never pushed
261+ mockGit . add . mockResolvedValue ( undefined ) ;
262+ mockGit . status . mockResolvedValue ( { isClean : ( ) => true } ) ;
263+ mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
264+ // rev-list origin/main..HEAD fails (no remote branch), rev-list HEAD --count shows commits exist
265+ mockGit . raw
266+ . mockRejectedValueOnce ( new Error ( 'unknown revision origin/main' ) )
267+ . mockResolvedValueOnce ( '3\n' ) ;
268+ mockGit . push . mockResolvedValue ( undefined ) ;
269+
270+ const result = await pushSkills ( tempDir ) ;
271+
272+ expect ( mockGit . commit ) . not . toHaveBeenCalled ( ) ;
273+ expect ( mockGit . push ) . toHaveBeenCalledWith ( 'origin' , 'main' , { '--set-upstream' : null } ) ;
274+ expect ( result . committed ) . toBe ( false ) ;
275+ expect ( result . pushed ) . toBe ( true ) ;
276+ } ) ;
277+
254278 it ( 'uses token with temporary remote URL and restores clean URL' , async ( ) => {
255279 mockGit . status . mockResolvedValue ( { isClean : ( ) => false } ) ;
256280 mockGit . add . mockResolvedValue ( undefined ) ;
257281 mockGit . commit . mockResolvedValue ( undefined ) ;
258282 mockGit . push . mockResolvedValue ( undefined ) ;
259283 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
284+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
260285 mockGit . getRemotes . mockResolvedValue ( [
261286 { name : 'origin' , refs : { fetch : 'https://github.com/user/repo.git' , push : 'https://github.com/user/repo.git' } } ,
262287 ] ) ;
@@ -274,6 +299,7 @@ describe('pushSkills', () => {
274299 mockGit . add . mockResolvedValue ( undefined ) ;
275300 mockGit . commit . mockResolvedValue ( undefined ) ;
276301 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
302+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
277303 mockGit . getRemotes . mockResolvedValue ( [
278304 { name : 'origin' , refs : { fetch : '' , push : '' } } ,
279305 ] ) ;
@@ -289,6 +315,7 @@ describe('pushSkills', () => {
289315 mockGit . commit . mockResolvedValue ( undefined ) ;
290316 mockGit . push . mockResolvedValue ( undefined ) ;
291317 mockGit . branchLocal . mockResolvedValue ( { current : 'master' } ) ;
318+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
292319
293320 await pushSkills ( tempDir , 'test' , null ) ;
294321
@@ -302,6 +329,7 @@ describe('pushSkills', () => {
302329 mockGit . commit . mockResolvedValue ( undefined ) ;
303330 mockGit . push . mockResolvedValue ( undefined ) ;
304331 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
332+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
305333
306334 await pushSkills ( tempDir ) ;
307335
@@ -314,6 +342,7 @@ describe('pushSkills', () => {
314342 mockGit . add . mockResolvedValue ( undefined ) ;
315343 mockGit . commit . mockResolvedValue ( undefined ) ;
316344 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
345+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
317346 mockGit . push . mockRejectedValue ( new Error ( 'error: failed to push some refs... non-fast-forward' ) ) ;
318347
319348 await expect ( pushSkills ( tempDir , 'test' ) ) . rejects . toThrow ( 'Push rejected' ) ;
@@ -325,6 +354,7 @@ describe('pushSkills', () => {
325354 mockGit . add . mockResolvedValue ( undefined ) ;
326355 mockGit . commit . mockResolvedValue ( undefined ) ;
327356 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
357+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
328358 mockGit . getRemotes . mockResolvedValue ( [
329359 { name : 'origin' , refs : { fetch : 'https://github.com/user/repo.git' , push : 'https://github.com/user/repo.git' } } ,
330360 ] ) ;
@@ -339,6 +369,7 @@ describe('pushSkills', () => {
339369 mockGit . add . mockResolvedValue ( undefined ) ;
340370 mockGit . commit . mockResolvedValue ( undefined ) ;
341371 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
372+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
342373 mockGit . getRemotes . mockResolvedValue ( [
343374 { name : 'origin' , refs : { fetch : 'https://github.com/user/repo.git' , push : 'https://github.com/user/repo.git' } } ,
344375 ] ) ;
@@ -357,6 +388,7 @@ describe('pushSkills', () => {
357388 mockGit . add . mockResolvedValue ( undefined ) ;
358389 mockGit . commit . mockResolvedValue ( undefined ) ;
359390 mockGit . branchLocal . mockResolvedValue ( { current : 'main' } ) ;
391+ mockGit . raw . mockResolvedValue ( '1\n' ) ;
360392 mockGit . push . mockRejectedValue ( new Error ( 'network timeout' ) ) ;
361393
362394 await expect ( pushSkills ( tempDir , 'test' ) ) . rejects . toThrow ( 'network timeout' ) ;
0 commit comments