Skip to content

Instantly share code, notes, and snippets.

@cprima
Last active January 25, 2025 21:27
Show Gist options
  • Save cprima/61ab81475bf027d44ac7bd57e1eec98e to your computer and use it in GitHub Desktop.
Save cprima/61ab81475bf027d44ac7bd57e1eec98e to your computer and use it in GitHub Desktop.
Script for Creating, Archiving and Zipping Git Snapshots by Tag, Branch, or Commit

Git Repository Snapshot Archiver

A PowerShell script to create and archive snapshots of a Git repository at specified branches, tags, or commit hashes. This script generates individual folders for each snapshot, names them with user-defined labels, and compresses them into a single timestamped ZIP archive.

Table of Contents

Features

  • Takes snapshots of a Git repository at specified branches, tags, or commit hashes.
  • Saves each snapshot in a labeled folder.
  • Compresses all snapshot folders into a single timestamped ZIP archive.
  • Option to force-delete existing snapshot folders before creating new ones.

Requirements

  • PowerShell Core
  • Git
  • Archive tool (e.g., tar) installed and accessible in your PATH

Installation

  1. Place the Create-Snapshots.ps1 script in the root of your Git repository. This location is essential for the git archive commands to work correctly.
  2. Ensure that PowerShell Core, Git, and an archive tool like tar are installed on your system.

Usage

pwsh ./Create-Snapshots.ps1 [-Force] [-ZipName <string>]

Parameters

  • -Force (Optional): If specified, deletes any existing snapshot folders without prompting the user.
  • -ZipName (Optional): Specifies the base name of the resulting ZIP file. The file will be named <ZipName>_YYYYMMDD-HHMMSS.zip, where YYYYMMDD-HHMMSS is the current timestamp. If not provided, defaults to snapshots.

Examples

  1. Run with Default ZIP Name and Prompt for Deletion:

    pwsh ./Create-Snapshots.ps1
  2. Force Delete Existing Folders and Specify ZIP Name:

    pwsh ./Create-Snapshots.ps1 -Force -ZipName "ChapterEventRefactoring"

    This command forces the deletion of existing folders and creates a ZIP file named ChapterEventRefactoring_YYYYMMDD-HHMMSS.zip.

Notes

  • Script Placement: Place the script in the root directory of the Git repository for correct execution.
  • Timestamp Format: The timestamp in the ZIP file name uses the YYYYMMDD-HHMMSS format for easy tracking.
  • Folder Names: Each snapshot folder is named according to the specified label and the Git identifier (tag, branch, or commit hash).

License

Licensed under the CC-BY (Creative Commons Attribution) License.

Author

Christian Prior-Mamulyan
Contact: [email protected]

<#
.SYNOPSIS
Creates snapshots of a Git repository at specified tags, branches, or commits.
.DESCRIPTION
This script generates snapshots of a Git repository based on user-defined labels, branches, tags, or specific commits.
The snapshots are saved as separate folders and then compressed into a timestamped ZIP file. The script can
optionally force delete existing snapshot folders without user confirmation.
NOTE: This script must be placed and run from the root of the Git repository for the `git archive` commands to work correctly.
.PARAMETER Force
If specified, forces deletion of existing snapshot folders without prompting the user.
.PARAMETER ZipName
Specifies the base name of the resulting ZIP file. The file will be named as
'ZipName_YYYYMMDD-HHMMSS.zip', where 'YYYYMMDD-HHMMSS' is the current timestamp.
.EXAMPLE
pwsh ./Create-Snapshots.ps1 -Force -ZipName "ChapterEventRefactoring"
Forces deletion of existing snapshot folders and creates a ZIP file named 'ChapterEventRefactoring_YYYYMMDD-HHMMSS.zip'.
.EXAMPLE
pwsh ./Create-Snapshots.ps1
Runs the script without force deletion, prompting the user if any existing folders are present, and uses the default ZIP file name 'snapshots_YYYYMMDD-HHMMSS.zip'.
.NOTES
Ensure that Git and an archive tool (tar) are installed and accessible in your system's PATH for the script to work.
The script should be placed in the root of the repository to work correctly.
.AUTHOR
Christian Prior-Mamulyan, [email protected]
.LICENSE
Licensed under CC-BY (Creative Commons Attribution License).
#>
param (
[switch]$Force, # Argument to force deletion without prompt
[string]$ZipName = "snapshots" # Argument to specify the ZIP file name prefix
)
# Define snapshots with labels, identifiers (branches, tags, commits), and types
$snapshots = @(
@{ label = "01_foo"; identifier = "v0.1.0"; type = "tag" },
@{ label = "10_bar"; identifier = "legacy/REFramework2016"; type = "branch" },
@{ label = "20_baz"; identifier = "be87405fa7c8f1bbbda1dc95703750182adaccdd"; type = "commit" }
)
# Define directories: repository and snapshots directory paths
$repoDir = (Get-Location).Path
$snapshotsDir = Join-Path -Path $repoDir -ChildPath "../snapshots"
# Check if any existing snapshot folders are present in the snapshots directory
$existingFolders = Get-ChildItem -Path $snapshotsDir -Directory -ErrorAction SilentlyContinue
if ($existingFolders) {
# If -Force parameter is specified, delete all existing folders without prompting
if ($Force) {
$existingFolders | ForEach-Object { Remove-Item -Recurse -Force -Path $_.FullName }
Write-Output "Existing snapshot folders deleted (force mode)."
} else {
# Prompt the user if -Force is not specified and existing folders are found
Write-Output "Snapshot folders already exist in $snapshotsDir."
$response = Read-Host "Do you want to delete all existing snapshot folders and continue? (y/n)"
if ($response -eq 'y') {
# Delete existing folders if the user confirms
$existingFolders | ForEach-Object { Remove-Item -Recurse -Force -Path $_.FullName }
Write-Output "Existing snapshot folders deleted."
} else {
# Exit if the user chooses not to delete existing folders
Write-Output "Exiting without making any changes."
exit
}
}
} else {
Write-Output "No existing snapshot folders found. Proceeding with snapshot creation."
}
# Ensure snapshots directory exists
if (!(Test-Path -Path $snapshotsDir)) {
New-Item -ItemType Directory -Path $snapshotsDir | Out-Null
}
# Function to create individual snapshots
function Create-Snapshot {
<#
.SYNOPSIS
Creates a snapshot of the Git repository at the specified identifier.
.DESCRIPTION
This function uses Git to create a snapshot of the repository at a specified branch, tag, or commit.
The snapshot is saved in a uniquely labeled folder within the snapshots directory.
.PARAMETER Label
The label used as a prefix in the snapshot folder name.
.PARAMETER Identifier
The Git identifier for the snapshot (e.g., branch name, tag name, or commit hash).
.PARAMETER Type
The type of the identifier (e.g., "branch", "tag", or "commit").
#>
param (
[string]$Label,
[string]$Identifier,
[string]$Type
)
# Construct folder name by combining label and identifier, replacing '/' with '-'
$folderName = "$Label-$($Identifier -replace '/', '-')"
$snapshotPath = Join-Path -Path $snapshotsDir -ChildPath $folderName
Write-Output "Creating snapshot for '$Identifier' with label '$Label'..."
New-Item -ItemType Directory -Path $snapshotPath | Out-Null
# Use git archive to export the snapshot; assumes script is in the repo root
& git archive --format=tar --prefix="$Identifier/" $Identifier | tar -xf - -C $snapshotPath
# Check for successful snapshot creation
if ($LASTEXITCODE -eq 0) {
Write-Output "Snapshot created: $snapshotPath"
} else {
Write-Output "Error creating snapshot for $Identifier"
}
}
# Iterate through each defined snapshot and create it
foreach ($snapshot in $snapshots) {
Create-Snapshot -Label $snapshot.label -Identifier $snapshot.identifier -Type $snapshot.type
}
# Generate a timestamp in the format YYYYMMDD-HHMMSS for the ZIP file name
$timestamp = (Get-Date -Format "yyyyMMdd-HHmmss")
$zipPath = Join-Path -Path $snapshotsDir -ChildPath "$ZipName`_$timestamp.zip"
# Delete any existing ZIP file with the same name
if (Test-Path -Path $zipPath) { Remove-Item -Path $zipPath }
Write-Output "Zipping all snapshots into $zipPath..."
# Compress all folders in the snapshots directory into a single ZIP archive
Compress-Archive -Path (Get-ChildItem -Path $snapshotsDir -Directory).FullName -DestinationPath $zipPath
# Verify that the ZIP file was created successfully
if (Test-Path -Path $zipPath) {
Write-Output "All snapshots have been zipped into $zipPath"
} else {
Write-Output "Error creating ZIP archive"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment