55 getCommitParents ,
66 getLocalOnlyBranches ,
77 getStaleBranches ,
8+ getRemotes ,
89 type CommitInfo ,
910 type CommitFile ,
1011 type SelectedDiffInfo ,
@@ -79,11 +80,12 @@ interface ContextMenuProps {
7980 x : number ; y : number ;
8081 commit : CommitInfo ;
8182 repoPath : string ;
83+ localOnlyBranches : Set < string > ;
8284 onClose : ( ) => void ;
8385 onRefresh : ( ) => void ;
8486}
8587
86- function ContextMenu ( { x, y, commit, repoPath, onClose, onRefresh } : ContextMenuProps ) {
88+ function ContextMenu ( { x, y, commit, repoPath, localOnlyBranches , onClose, onRefresh } : ContextMenuProps ) {
8789 const ref = useRef < HTMLDivElement > ( null ) ;
8890
8991 useEffect ( ( ) => {
@@ -98,6 +100,10 @@ function ContextMenu({ x, y, commit, repoPath, onClose, onRefresh }: ContextMenu
98100 catch ( e ) { alert ( String ( e ) ) ; }
99101 } ;
100102
103+ const localOnlyRefsOnCommit = parseRefNames ( commit . ref_names )
104+ . filter ( r => ( r . kind === "branch" || r . kind === "head" ) && localOnlyBranches . has ( r . label ) )
105+ . map ( r => r . label ) ;
106+
101107 const items : { label : string ; action : ( ) => void ; danger ?: boolean } [ ] = [
102108 { label : "Checkout" , action : ( ) => run ( [ "checkout" , commit . hash ] ) } ,
103109 {
@@ -131,6 +137,34 @@ function ContextMenu({ x, y, commit, repoPath, onClose, onRefresh }: ContextMenu
131137 { label : "──" , action : ( ) => { } } ,
132138 { label : "Copy Commit ID" , action : ( ) => { onClose ( ) ; navigator . clipboard . writeText ( commit . hash ) . catch ( ( ) => { } ) ; } } ,
133139 { label : "Copy Short ID" , action : ( ) => { onClose ( ) ; navigator . clipboard . writeText ( commit . short_hash ) . catch ( ( ) => { } ) ; } } ,
140+ ...( localOnlyRefsOnCommit . length > 0 ? [
141+ { label : "──" , action : ( ) => { } } ,
142+ ...localOnlyRefsOnCommit . map ( branch => ( {
143+ label : `Push "${ branch } " to remote…` ,
144+ action : async ( ) => {
145+ onClose ( ) ;
146+ let remotes : { name : string } [ ] ;
147+ try { remotes = await getRemotes ( repoPath ) ; }
148+ catch { alert ( "Failed to get remotes." ) ; return ; }
149+ if ( remotes . length === 0 ) { alert ( "No remotes configured." ) ; return ; }
150+
151+ let remote : string ;
152+ if ( remotes . length === 1 ) {
153+ remote = remotes [ 0 ] . name ;
154+ } else {
155+ const names = remotes . map ( r => r . name ) . join ( ", " ) ;
156+ const input = prompt ( `Push to which remote? (${ names } )` , remotes [ 0 ] . name ) ;
157+ if ( ! input ?. trim ( ) ) return ;
158+ remote = input . trim ( ) ;
159+ }
160+
161+ try {
162+ await invoke ( "run_git_simple" , { args : [ "push" , "-u" , remote , branch ] , cwd : repoPath } ) ;
163+ onRefresh ( ) ;
164+ } catch ( e ) { alert ( String ( e ) ) ; }
165+ } ,
166+ } ) ) ,
167+ ] : [ ] ) ,
134168 ] ;
135169
136170 return (
@@ -495,7 +529,8 @@ export function HistoryTab({ repoPath, filePath, refreshKey, onRefresh, onFileSe
495529 ) }
496530 { contextMenu && (
497531 < ContextMenu x = { contextMenu . x } y = { contextMenu . y } commit = { contextMenu . commit }
498- repoPath = { repoPath } onClose = { ( ) => setContextMenu ( null ) }
532+ repoPath = { repoPath } localOnlyBranches = { localOnlyBranches }
533+ onClose = { ( ) => setContextMenu ( null ) }
499534 onRefresh = { ( ) => { setContextMenu ( null ) ; onRefresh ( ) ; } } />
500535 ) }
501536 </ div >
0 commit comments