Skip to content

Instantly share code, notes, and snippets.

@lumenpink
Last active February 22, 2025 01:22
Show Gist options
  • Save lumenpink/9d1f2a12ba6058524a85b82162e2ea92 to your computer and use it in GitHub Desktop.
Save lumenpink/9d1f2a12ba6058524a85b82162e2ea92 to your computer and use it in GitHub Desktop.
Git Hook Scripts for Versioning and Changelog Generation

Git Hook Scripts for Versioning and Changelog Generation

This repository contains two Git hook scripts designed to automate versioning and changelog generation based on commit messages. These scripts are intended to be used as Git hooks to streamline your development workflow.

Scripts Overview

post-commit

  • If the commit message contains a version tag (ver:X.Y.Z or ver:X.Y), it uses that version, creates a Git tag with the specified version and optionally pushes the tag to the remote repository.
  • If no version tag is found, it generates a version number based on the latest tag, the number of commits since that tag, the commit timestamp, and the commit hash.
  • If no version information is available, it falls back to the version specified in a VERSION file.

Additionally, it generates a CHANGELOG.md and RELEASE_NOTES.md file based on the commit history.


Installation

To use these scripts as Git hooks, follow these steps:

  1. Clone or download the scripts:

    • Download the post-commit script from this Gist.
  2. Place the script in your Git hooks directory:

    • Navigate to your Git repository.
    • Copy the scripts into the .git/hooks/ directory:
      cp post-commit .git/hooks/
  3. Make the script executable:

    • Ensure the scripts have executable permissions:
      chmod +x .git/hooks/post-commit 
  4. Test the hook:

    • Make a commit with a version tag in the message (e.g., ver:1.2.3 or ver:1.2) to see the scripts in action.
    • Check the VERSION, CHANGELOG.md, and RELEASE_NOTES.md files for updates.

Usage

Commit Message Format

To trigger version tagging, include a version tag in your commit message using the format:

ver:X.Y.Z

Example:

Added new feature. ver:1.2.3

Automatic Versioning

If no version tag is found in the commit message, the commit-msg script will generate a version number in the format:

<latest-tag>-<commits-since-tag>-<datestamp>-<last-commit-short-hash>

Example:

v1.0.0-2-250221-abc1234

Changelog and Release Notes

The scripts automatically generate:

  • CHANGELOG.md: A list of commits since the last tag.
  • RELEASE_NOTES.md: A formatted release note with the version and changelog.

Customization

  • To prevent pushing tags to the remote repository, comment the following line in the post-commit script:
    # git push origin "$VERSION"
  • Modify the versioning logic in the post-commit script to suit your project's needs.

License

These scripts are provided under the MIT License. Feel free to use and modify them as needed.

#!/bin/sh
# Check if the hook is active to prevent infinite loops
# If the hook is active, exit the script
if [ "$HOOK_ACTIVE" = "1" ]; then
exit 0
fi
# Retrieve the last commit message
LAST_COMMIT_MESSAGE=$(git log -1 --pretty=%B)
# Define the file where the version information will be stored
VERSION_FILE="VERSION"
# Get the current date in the format YYMMDD
CURRENT_DATE=$(date "+%y%m%d")
# Get the short hash of the second-to-last commit
SECOND_TO_LAST_COMMIT_SHORT_HASH=$(git log -n 2 --format=%h | tail -n 1)
# Get the most recent tag
LATEST_TAG=$(git describe --tags --abbrev=0)
# Count the number of commits since the latest tag
COMMITS_SINCE_LATEST_TAG=$(git rev-list "$LATEST_TAG..HEAD" --count)
# Extract the version number from the commit message if it matches the pattern "ver:X.Y.Z"
EXTRACTED_VERSION=$(echo "$LAST_COMMIT_MESSAGE" | sed -En 's/.*(^| )ver:([0-9]+(\.[0-9]+){1,2})($| ).*/\2/p')
# If no version was found in the commit message, construct a version string using the tag, commit count, date, and commit hash
if [ -z "$EXTRACTED_VERSION" ]; then
EXTRACTED_VERSION="${LATEST_TAG}-${COMMITS_SINCE_LATEST_TAG}-${CURRENT_DATE}-${SECOND_TO_LAST_COMMIT_SHORT_HASH}"
else
# If a version was found in the commit message, tag the commit with that version
echo "Version found in the commit message: $EXTRACTED_VERSION"
git tag -a "$EXTRACTED_VERSION" -m "Version $EXTRACTED_VERSION"
git push origin "$EXTRACTED_VERSION"
fi
# If no version was found in the commit message or tag info, fall back to the version in the VERSION file
if [ -z "$EXTRACTED_VERSION" ]; then
EXTRACTED_VERSION=$(cat "$VERSION_FILE")
echo "No version found in the commit message or in tag info"
echo "Falling back to the version in the VERSION file ($EXTRACTED_VERSION)"
fi
# Write the determined version to the VERSION file
echo "$EXTRACTED_VERSION" > "$VERSION_FILE"
# Generate a changelog starting from the latest tag to the current HEAD
echo " HEAD $LAST_COMMIT_MESSAGE" > CHANGELOG.md
git log --pretty=format:"%h %s" "$LATEST_TAG..HEAD" >> CHANGELOG.md
# Generate release notes with the version and changelog
{
echo "## $EXTRACTED_VERSION"
echo
echo "### Changelog"
cat CHANGELOG.md
} > RELEASE_NOTES.md
# Stage the version file, changelog, and release notes for the commit
git add "$VERSION_FILE" CHANGELOG.md RELEASE_NOTES.md
# Set the HOOK_ACTIVE flag to prevent the hook from running again
export HOOK_ACTIVE=1
# Amend the last commit to include the changes without editing the commit message
git commit --amend --no-edit
# Unset the HOOK_ACTIVE flag after the commit is amended
unset HOOK_ACTIVE
# Exit the script successfully
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment