Public/Invoke-GitInit.ps1
|
<#
.SYNOPSIS Creates a new bare git repository from a name. .DESCRIPTION Initialises a new bare repo at <Destination>/<Name>.git, makes an initial empty commit on the default branch (respecting init.defaultBranch config, preferring 'master'), and sets up the same recommended git config that Invoke-GitCloneBare uses. If -RemoteUrl is provided the initial commit is pushed there and the bare repo is cloned from it, so origin is configured correctly. Create the repository on your hosting provider (GitHub, Azure DevOps, Bitbucket, etc.) first, then supply its URL here. Omit -RemoteUrl for a local-only bare repo. .EXAMPLE Invoke-GitInit myrepo # Local bare repo only — no remote configured. .EXAMPLE Invoke-GitInit myrepo -RemoteUrl https://github.com/user/myrepo -Worktrees master # Connects to an existing GitHub remote and adds a master worktree. .EXAMPLE Invoke-GitInit myrepo -RemoteUrl https://dev.azure.com/org/project/_git/myrepo # Connects to an existing Azure DevOps remote. .EXAMPLE gitt init myrepo -RemoteUrl https://github.com/user/myrepo #> function Invoke-GitInit { [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter()] [string] $Destination = (Get-Location).Path, # Remote repository URL to configure as origin. # Create the repo on your hosting provider first, then supply its URL here. # Omit this parameter for a local-only bare repo with no remote. [Parameter()] [string] $RemoteUrl, [Parameter()] [switch] $SkipSafeDirectory, [Parameter()] [switch] $SkipGitConfig, [Parameter()] [string[]] $Worktrees = @() ) $bareDir = Join-Path $Destination "$Name.git" $tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "gitt-init-$Name-$(Get-Random)" if ($PSCmdlet.ShouldProcess($bareDir, "Initialize bare repository '$Name'")) { # Determine desired default branch from global git config $defaultBranch = git config --global init.defaultBranch 2>$null if (-not $defaultBranch) { $defaultBranch = 'master' } # Bootstrap: create a temp non-bare repo with one empty commit so we have # a valid ref to clone from. Write-Verbose "Bootstrapping temporary repo at $tmpDir" git init $tmpDir if ($LASTEXITCODE -ne 0) { throw "git init failed for temporary repo at '$tmpDir'" } # Set desired initial branch via symbolic-ref (works on empty repos, unlike rev-parse) git -C $tmpDir symbolic-ref HEAD "refs/heads/$defaultBranch" git -C $tmpDir commit --allow-empty -m "Initial commit" if ($LASTEXITCODE -ne 0) { Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue throw "Initial commit failed in temporary repo" } # Optionally push to a remote and clone from it so origin is wired up $cloneSource = $tmpDir if ($RemoteUrl) { Write-Verbose "Pushing initial commit to remote: $RemoteUrl" git -C $tmpDir remote add origin $RemoteUrl git -C $tmpDir push -u origin $defaultBranch if ($LASTEXITCODE -ne 0) { Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue throw "Push to remote '$RemoteUrl' failed — ensure the repository exists and you have push access." } $cloneSource = $RemoteUrl } # Clone as bare from the remote (if provided) or the local temp repo Write-Verbose "Cloning bare repo: $cloneSource -> $bareDir" git clone --bare $cloneSource $bareDir if ($LASTEXITCODE -ne 0) { Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue throw "git clone --bare failed from '$cloneSource'" } # Remove the auto-created origin (points to tmpDir or remote) and re-add # the real remote when one was provided, setting up proper fetch refspecs. git -C $bareDir remote remove origin 2>$null if ($RemoteUrl) { git -C $bareDir remote add origin $RemoteUrl git -C $bareDir config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' git -C $bareDir fetch origin 2>$null } # Clean up temp repo Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue if (-not $SkipGitConfig) { Write-Verbose "Applying recommended git config" Set-BareRepoGitConfig -RepoPath $bareDir } if (-not $SkipSafeDirectory) { git config --global --add safe.directory $bareDir } # Create any requested worktrees Add-InitialWorktrees -RepoPath $bareDir -Worktrees $Worktrees ` -Destination $Destination -SkipSafeDirectory:$SkipSafeDirectory Write-Host "Bare repo ready: $bareDir" -ForegroundColor Cyan return $bareDir } } |