Skip to content

Instantly share code, notes, and snippets.

Last active December 13, 2022 06:11
  • Star 15 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Bash script to generate a markdown change log of GitHub pull requests between tagged releases
# Generate a Markdown change log of pull requests from commits between two tags
# Author: Russell Heimlich
# URL:
# Copy this script to a directory under Git version control
# Make the script executable i.e. chmod +x
# Run it! ./
# Check to see your results
# Repo URL to base links off of
# Get a list of all tags in reverse order
# Assumes the tags are in version format like v1.2.3
GIT_TAGS=$(git tag -l --sort=-version:refname)
# Make the tags an array
# If you want to specify your own two tags to compare, uncomment and enter them below
# LATEST_TAG=v0.23.1
# PREVIOUS_TAG=v0.22.0
# Get a log of commits that occured between two tags
# We only get the commit hash so we don't have to deal with a bunch of ugly parsing
# See Pretty format placeholders at
COMMITS=$(git log $PREVIOUS_TAG..$LATEST_TAG --pretty=format:"%H")
# Store our changelog in a variable to be saved to a file at the end
# Loop over each commit and look for merged pull requests
for COMMIT in $COMMITS; do
# Get the subject of the current commit
SUBJECT=$(git log -1 ${COMMIT} --pretty=format:"%s")
# If the subject contains "Merge pull request #xxxxx" then it is deemed a pull request
PULL_REQUEST=$( grep -Eo "Merge pull request #[[:digit:]]+" <<< "$SUBJECT" )
if [[ $PULL_REQUEST ]]; then
# Perform a substring operation so we're left with just the digits of the pull request
PULL_NUM=${PULL_REQUEST#"Merge pull request #"}
# AUTHOR_NAME=$(git log -1 ${COMMIT} --pretty=format:"%an")
# AUTHOR_EMAIL=$(git log -1 ${COMMIT} --pretty=format:"%ae")
# Get the body of the commit
BODY=$(git log -1 ${COMMIT} --pretty=format:"%b")
# Save our markdown to a file
echo -e $MARKDOWN >
Copy link

Let's take an example from a public repo like WP-CLI

Say you want to generate a change log of pull requests between two tagged releases: v0.23.0 and v0.23.1

Your commit log would look like this...

$ git log v0.23.0..v0.23.1

commit 910cbcb389e3250efdd58e7888f80eeba735d3a1
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 17:31:30 2016 -0700

    Version bump

commit 6e50278155c8241f760cd7b93b5336f08abc9a4d
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 16:59:39 2016 -0700

    Add an expected certificate file too

commit 477579385430584d6bc124905dc014ba35e0fb54
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 16:12:13 2016 -0700

    Include more dependencies the Phar build is expected to have

commit 535e7e5ea6bc0e051fc91caf9b16607d468dce4b
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 15:44:32 2016 -0700

    Make it much easier to determine which `wp` binary we're running against

commit c9748cfb5d6c500da85c2f9cb99f4a91aad7c074
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 15:41:39 2016 -0700

    Restore global `WP_CLI_BIN_DIR` env variable

    We can't set env variables in scripts. Unfortunately, this means the
    test suite hasn't been running against the Phar build for a while

commit 15d5d618a8b6d32fdaff1d25c14131a75d7aa623
Merge: 31b9c00 bd6854f
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 15:08:14 2016 -0700

    Merge pull request #2694 from wp-cli/2664-composer-1-0-0

    Use Composer ^1.0.0 (for v0.23.1)

commit bd6854fea372876a22fde5cb7375c4a712369fb4
Author: Daniel Bachhuber <>
Date:   Tue Apr 26 16:18:30 2016 -0700

    Update tests for WordPress 4.5.1

commit 27a234cd8eb319039a9068394138a772a6e20423
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 13:00:38 2016 -0700

    Also build the release branch

commit 8b78598ebb3187ffb99552877841b0be5ed94da0
Author: Daniel Bachhuber <>
Date:   Thu Mar 24 06:36:35 2016 -0700

    Use the proper method signature to prevent another fatal

commit 6bc1dfc5e56a323c4d25439a791036eddaed90ea
Author: Daniel Bachhuber <>
Date:   Thu Mar 24 04:24:29 2016 -0700

    Permit downloading Composer packages over http

    The Package Index is served over http, which we should probably change.
    For the time being, we need to unfatal the fatal.

commit d98f56e111e875c073c295ca4454272c2c9e183b
Author: Daniel Bachhuber <>
Date:   Thu Mar 24 04:21:40 2016 -0700

    Catch exceptions in a couple more places

commit 97a1d10a5f74eb056570d9990a0c57f6f141e8ef
Author: Daniel Bachhuber <>
Date:   Thu Mar 24 12:14:33 2016 -0700

    Define variable, for when `$install->run()` doesn't return a value

commit 9bea16f67644ff489f98682c025d8325944896d8
Author: Daniel Bachhuber <>
Date:   Thu Mar 24 12:16:43 2016 -0700

    Also set `secure-http=>false` for the packages composer.json

    See 8b1eff834b660e66c9047f94a7b341f7d99ec71e

commit 60c23a58cb50c93fcc94442243fc9101f6fe62a7
Author: Daniel Bachhuber <>
Date:   Thu Apr 28 12:46:49 2016 -0700

    Use Composer 1.0.0 or later

This script would generate a file called which looks like this:

Full Changelog

  • #2694: Use Composer ^1.0.0 (for v0.23.1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment