@ -13,6 +13,7 @@ import ( 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						"code.gitea.io/gitea/modules/git"   
					 
					 
					 
						"code.gitea.io/gitea/modules/git"   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						"code.gitea.io/gitea/modules/log"   
					 
					 
					 
						"code.gitea.io/gitea/modules/log"   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						"code.gitea.io/gitea/modules/structs"   
					 
					 
					 
						"code.gitea.io/gitea/modules/structs"   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						"code.gitea.io/gitea/modules/util"   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					)  
					 
					 
					 
					)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// ForkRepository forks a repository
  
					 
					 
					 
					// ForkRepository forks a repository
  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					 
					@ -45,38 +46,60 @@ func ForkRepository(doer, owner *models.User, opts models.ForkRepoOptions) (_ *m 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						oldRepoPath  :=  opts . BaseRepo . RepoPath ( )   
					 
					 
					 
						oldRepoPath  :=  opts . BaseRepo . RepoPath ( )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						err  =  models . WithTx ( func ( ctx  models . DBContext )  error  {   
					 
					 
					 
						needsRollback  :=  false   
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
							if  err  =  models . CreateRepository ( ctx ,  doer ,  owner ,  repo ,  false ) ;  err  !=  nil  {   
					 
					 
					 
						rollbackFn  :=  func ( )  {   
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
								return  err   
					 
					 
					 
							if  ! needsRollback  {   
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
								return   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							repoPath  :=  models . RepoPath ( owner . Name ,  repo . Name )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							if  exists ,  _  :=  util . IsExist ( repoPath ) ;  ! exists  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
								return   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							rollbackRemoveFn  :=  func ( )  {   
					 
					 
					 
							// As the transaction will be failed and hence database changes will be destroyed we only need
   
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
								if  repo . ID  ==  0  {   
					 
					 
					 
							// to delete the related repository on the filesystem
   
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							if  errDelete  :=  util . RemoveAll ( repoPath ) ;  errDelete  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
								log . Error ( "Failed to remove fork repo" )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						needsRollbackInPanic  :=  true   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						defer  func ( )  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							panicErr  :=  recover ( )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							if  panicErr  ==  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								return   
					 
					 
					 
								return   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								if  errDelete  :=  models . DeleteRepository ( doer ,  owner . ID ,  repo . ID ) ;  errDelete  !=  nil  {   
					 
					 
					 
					
 
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
									log . Error ( "Rollback deleteRepository: %v" ,  errDelete )   
					 
					 
					 
							if  needsRollbackInPanic  {   
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
								rollbackFn ( )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							panic ( panicErr )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						} ( )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						err  =  models . WithTx ( func ( ctx  models . DBContext )  error  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							if  err  =  models . CreateRepository ( ctx ,  doer ,  owner ,  repo ,  false ) ;  err  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
								return  err   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							if  err  =  models . IncrementRepoForkNum ( ctx ,  opts . BaseRepo . ID ) ;  err  !=  nil  {   
					 
					 
					 
							if  err  =  models . IncrementRepoForkNum ( ctx ,  opts . BaseRepo . ID ) ;  err  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								rollbackRemoveFn ( )   
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								return  err   
					 
					 
					 
								return  err   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							// copy lfs files failure should not be ignored
   
					 
					 
					 
							// copy lfs files failure should not be ignored
   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							if  err  :=  models . CopyLFS ( ctx ,  repo ,  opts . BaseRepo ) ;  err  !=  nil  {   
					 
					 
					 
							if  err  =  models . CopyLFS ( ctx ,  repo ,  opts . BaseRepo ) ;  err  !=  nil  {   
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
								rollbackRemoveFn ( )   
					 
					 
					 
					 
				
			 
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
								return  err   
					 
					 
					 
								return  err   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							needsRollback  =  true   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							repoPath  :=  models . RepoPath ( owner . Name ,  repo . Name )   
					 
					 
					 
							repoPath  :=  models . RepoPath ( owner . Name ,  repo . Name )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							if  stdout ,  err  :=  git . NewCommand (   
					 
					 
					 
							if  stdout ,  err  :=  git . NewCommand (   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								"clone" ,  "--bare" ,  oldRepoPath ,  repoPath ) .   
					 
					 
					 
								"clone" ,  "--bare" ,  oldRepoPath ,  repoPath ) .   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								SetDescription ( fmt . Sprintf ( "ForkRepository(git clone): %s to %s" ,  opts . BaseRepo . FullName ( ) ,  repo . FullName ( ) ) ) .   
					 
					 
					 
								SetDescription ( fmt . Sprintf ( "ForkRepository(git clone): %s to %s" ,  opts . BaseRepo . FullName ( ) ,  repo . FullName ( ) ) ) .   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								RunInDirTimeout ( 10 * time . Minute ,  "" ) ;  err  !=  nil  {   
					 
					 
					 
								RunInDirTimeout ( 10 * time . Minute ,  "" ) ;  err  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								log . Error ( "Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v" ,  repo ,  opts . BaseRepo ,  stdout ,  err )   
					 
					 
					 
								log . Error ( "Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v" ,  repo ,  opts . BaseRepo ,  stdout ,  err )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								rollbackRemoveFn ( )   
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								return  fmt . Errorf ( "git clone: %v" ,  err )   
					 
					 
					 
								return  fmt . Errorf ( "git clone: %v" ,  err )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -84,23 +107,23 @@ func ForkRepository(doer, owner *models.User, opts models.ForkRepoOptions) (_ *m 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								SetDescription ( fmt . Sprintf ( "ForkRepository(git update-server-info): %s" ,  repo . FullName ( ) ) ) .   
					 
					 
					 
								SetDescription ( fmt . Sprintf ( "ForkRepository(git update-server-info): %s" ,  repo . FullName ( ) ) ) .   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								RunInDir ( repoPath ) ;  err  !=  nil  {   
					 
					 
					 
								RunInDir ( repoPath ) ;  err  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								log . Error ( "Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v" ,  repo ,  stdout ,  err )   
					 
					 
					 
								log . Error ( "Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v" ,  repo ,  stdout ,  err )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								rollbackRemoveFn ( )   
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								return  fmt . Errorf ( "git update-server-info: %v" ,  err )   
					 
					 
					 
								return  fmt . Errorf ( "git update-server-info: %v" ,  err )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							if  err  =  createDelegateHooks ( repoPath ) ;  err  !=  nil  {   
					 
					 
					 
							if  err  =  createDelegateHooks ( repoPath ) ;  err  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								rollbackRemoveFn ( )   
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
								return  fmt . Errorf ( "createDelegateHooks: %v" ,  err )   
					 
					 
					 
								return  fmt . Errorf ( "createDelegateHooks: %v" ,  err )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							}   
					 
					 
					 
							}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							return  nil   
					 
					 
					 
							return  nil   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						} )   
					 
					 
					 
						} )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
						needsRollbackInPanic  =  false   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						if  err  !=  nil  {   
					 
					 
					 
						if  err  !=  nil  {   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
							rollbackFn ( )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
							return  nil ,  err   
					 
					 
					 
							return  nil ,  err   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						}   
					 
					 
					 
						}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						// even if below operations failed, it could be ignored. And they will be retried
   
					 
					 
					 
						// even if below operations failed, it could be ignored. And they will be retried
   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						ctx  :=  models . DefaultDBContext ( )   
					 
					 
					 
						ctx  :=  models . DefaultDBContext ( )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						if  err  =  repo . UpdateSize ( ctx ) ;  err  !=  nil  {   
					 
					 
					 
						if  err  : =  repo . UpdateSize ( ctx ) ;  err  !=  nil  {   
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
							log . Error ( "Failed to update size for repository: %v" ,  err )   
					 
					 
					 
							log . Error ( "Failed to update size for repository: %v" ,  err )   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						}   
					 
					 
					 
						}   
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
						if  err  :=  models . CopyLanguageStat ( opts . BaseRepo ,  repo ) ;  err  !=  nil  {   
					 
					 
					 
						if  err  :=  models . CopyLanguageStat ( opts . BaseRepo ,  repo ) ;  err  !=  nil  {