From f1e098d3d5cd9f5ac03616b830a2525066b8ee6c Mon Sep 17 00:00:00 2001 From: Ed Gomoliako Date: Fri, 15 Apr 2022 16:31:24 +0200 Subject: [PATCH 1/3] Add FILTER_BRANCH_SQUELCH_WARNING=1 envvar export to disable git filter-branch warning that affects script performance --- git-redate | 2 ++ 1 file changed, 2 insertions(+) diff --git a/git-redate b/git-redate index 066fd95..0b1b58f 100755 --- a/git-redate +++ b/git-redate @@ -174,6 +174,8 @@ END done < $tmpfile +export FILTER_BRANCH_SQUELCH_WARNING=1 + ITERATOR=0 for each in "${COLLECTION[@]}" do From 9dcf9068e2341e105c07037bb87d02ea4b21210f Mon Sep 17 00:00:00 2001 From: Ed Gomoliako Date: Fri, 15 Apr 2022 18:54:41 +0200 Subject: [PATCH 2/3] Make redate using `git rebase` for date changes with a couple more features - `git rebase` uses `commit --amend --date={date} --no-edit -n` command to change commit metadata - the unknown arguments provided to redate are provided to `commit --ammend` command - the --limit argument has been ditched because it seems it does not make sense without filter-branch - hash-bang instruction is changed to `/usr/bin/env bash` to be as generic as possible - editor choice dialog does not require hitting enter for making choice - a single key input is expected - added support for --user parameter to filter the date changing commits only made by the current git user (email is used for identification) - debug option shows all the output of the `git rebase` command --- git-redate | 181 +++++++++++++++-------------------------------------- 1 file changed, 51 insertions(+), 130 deletions(-) diff --git a/git-redate b/git-redate index 0b1b58f..6bef685 100755 --- a/git-redate +++ b/git-redate @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash is_git_repo() { git rev-parse --show-toplevel > /dev/null 2>&1 @@ -19,7 +19,7 @@ make_editor_choice() { echo "3. Your own\n" echo "You Choose: "; - read CHOOSE_EDITOR + read -d'' -s -n1 CHOOSE_EDITOR } get_editor_executable() { @@ -56,36 +56,36 @@ is_has_editor ALL=0 DEBUG=0 -LIMITCHUNKS=20 - -while [[ $# -ge 1 ]] -do -key="$1" - -case $key in - -c| --commits) - COMMITS="$2" - if [ -z "${COMMITS}" ]; then COMMITS="5"; fi; - shift - ;; - -l| --limit) - LIMITCHUNKS="$2" - if [ -z "${LIMITCHUNKS}" ]; then LIMITCHUNKS="20"; fi; - shift - ;; - -d| --debug) - DEBUG=1 - shift - ;; - -a| --all) - ALL=1 +LOG_FILTER="" +REBASE_REF="--root" +COMMIT_ARGS="" +LOG_OUT_PATTERN="error" + +while [[ $# -ge 1 ]]; do + key="$1" + + case $key in + -c| --commits) + COMMITS="${2:-5}" + shift + ;; + -u| --user) + LOG_FILTER="${LOG_FILTER} --author=$(git config --get user.email)" + shift + ;; + -d| --debug) + DEBUG=1 + LOG_OUT_PATTERN="" + ;; + -a| --all) + ALL=1 + ;; + *) + COMMIT_ARGS="${COMMIT_ARGS} ${key}" + # unknown option + ;; + esac shift - ;; - *) - # unknown option - ;; -esac -shift done die () { @@ -93,119 +93,40 @@ die () { exit 1 } -tmpfile=$(mktemp gitblah-XXXX) -[ -f "$tmpfile" ] || die "could not get tmpfile=[$tmpfile]" -trap "rm -f $tmpfile" EXIT +COMMITS_FILE=$(mktemp /tmp/gitblah-XXXX) +[ -f "$COMMITS_FILE" ] || die "could not get COMMITS_FILE=[$COMMITS_FILE]" +LOG_FILE=$(mktemp ${COMMITS_FILE}.log) +[ -f "$LOG_FILE" ] || die "could not get LOG_FILE=[$LOG_FILE]" -datefmt=%cI -if [ "`git log -n1 --pretty=format:"$datefmt"`" == "$datefmt" ]; -then - datefmt=%ci +if [ "${DEBUG}" -eq 0 ]; then + trap "rm -f $COMMITS_FILE; rm -f $LOG_FILE" EXIT fi -if [ "${ALL}" -eq 1 ]; -then - git log --pretty=format:"$datefmt | %H | %s" > $tmpfile; -else - if [ -n "${COMMITS+set}" ]; - then git log -n ${COMMITS} --pretty=format:"$datefmt | %H | %s" > $tmpfile; - else git log -n 5 --pretty=format:"$datefmt | %H | %s" > $tmpfile; - fi -fi - -${VISUAL:-${EDITOR:-${OUR_EDITOR}}} $tmpfile - - -ITER=0 -COLITER=0 -declare -a COLLECTION - -COUNTCOMMITS=$(awk 'END {print NR}' $tmpfile) - -while read commit || [ -n "$commit" ]; do - - IFS="|" read date hash message <<< "$commit" - shopt -s nocasematch - if [[ "$date" == 'now' ]]; then - date=$(date +%Y-%m-%dT%H:%M:%S%z); - fi - shopt -u nocasematch - if [ "$datefmt" == "%cI" ] - then - DATE_NO_SPACE="$(echo "${date}" | tr -d '[[:space:]]')" - else - DATE_NO_SPACE="$(echo "${date}")" - fi - - - COMMIT_ENV=$(cat <<-END -if [ \$GIT_COMMIT = $hash ]; -then - export GIT_AUTHOR_DATE="$DATE_NO_SPACE" - export GIT_COMMITTER_DATE="$DATE_NO_SPACE"; -fi; -END -) - ((ITER++)) - - if [ "${DEBUG}" -eq 1 ] && [ $((ITER % LIMITCHUNKS)) == $((LIMITCHUNKS - 1)) ]; - then - echo "Chunk $COLITER Finished" - fi - - if [ $((ITER % LIMITCHUNKS)) == 0 ] - then - ((COLITER++)) +if [ "${ALL}" -eq 0 ]; then + LOG_FILTER="${LOG_FILTER} -n ${COMMITS:-5}" + REBASE_REF="HEAD~${COMMITS:-5}" +fi - if [ "${DEBUG}" -eq 1 ]; - then - echo "Chunk $COLITER Started" - fi +git log $LOG_FILTER --date=iso-strict-local --pretty=format:"%cd | %H | %s" > $COMMITS_FILE; - fi - - COLLECTION[$COLITER]=${COLLECTION[COLITER]}"$COMMIT_ENV" - if [ "${DEBUG}" -eq 1 ] - then - echo "Commit $ITER/$COUNTCOMMITS Collected" - fi +${VISUAL:-${EDITOR:-${OUR_EDITOR}}} $COMMITS_FILE -done < $tmpfile -export FILTER_BRANCH_SQUELCH_WARNING=1 +REDATE_EXEC="export GIT_COMMITTER_DATE=\$(grep -F \"\$(git rev-parse --verify HEAD)\" $COMMITS_FILE | awk '{ print \$1 }'); \ + test -n \"\$GIT_COMMITTER_DATE\" && git commit --date=\${GIT_COMMITTER_DATE} --amend --no-edit -n ${COMMIT_ARGS}" -ITERATOR=0 -for each in "${COLLECTION[@]}" -do +git rebase --exec "${REDATE_EXEC}" ${REBASE_REF} >${LOG_FILE} 2>&1 - ((ITERATOR++)) +RESULT=$? - if [ "${ALL}" -eq 1 ]; - then - if [ "${DEBUG}" -eq 1 ]; - then - echo "Chunk $ITERATOR/"${#COLLECTION[@]}" Started" - git filter-branch -f --env-filter "$each" -- --all - echo "Chunk $ITERATOR/"${#COLLECTION[@]}" Finished" - else - git filter-branch -f --env-filter "$each" -- --all >/dev/null - fi - else - if [ "${DEBUG}" -eq 1 ]; - then - echo "Chunk $ITERATOR/"${#COLLECTION[@]}" Started" - git filter-branch -f --env-filter "$each" HEAD~${COMMITS}..HEAD - echo "Chunk $ITERATOR/"${#COLLECTION[@]}" Finished" - else - git filter-branch -f --env-filter "$each" HEAD~${COMMITS}..HEAD >/dev/null - fi - fi -done +cat ${LOG_FILE} | grep -F "${LOG_OUT_PATTERN}" -if [ $? = 0 ] ; then +if [ $RESULT -eq 0 ] ; then echo "Git commit dates updated. Run 'git push -f BRANCH_NAME' to push your changes." else echo "Git redate failed. Please make sure you run this on a clean working directory." fi + +exit $RESULT From 4c10bb29c5aba0cbabd9ce3668c7cd38d2d7176c Mon Sep 17 00:00:00 2001 From: Ed Gomoliako Date: Wed, 27 Apr 2022 10:37:34 +0200 Subject: [PATCH 3/3] Fix problem when redating a commit generates a new commit hash --- git-redate | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-redate b/git-redate index 6bef685..651cd2e 100755 --- a/git-redate +++ b/git-redate @@ -114,10 +114,15 @@ git log $LOG_FILTER --date=iso-strict-local --pretty=format:"%cd | %H | %s" > $C ${VISUAL:-${EDITOR:-${OUR_EDITOR}}} $COMMITS_FILE -REDATE_EXEC="export GIT_COMMITTER_DATE=\$(grep -F \"\$(git rev-parse --verify HEAD)\" $COMMITS_FILE | awk '{ print \$1 }'); \ - test -n \"\$GIT_COMMITTER_DATE\" && git commit --date=\${GIT_COMMITTER_DATE} --amend --no-edit -n ${COMMIT_ARGS}" +REDATE_EXEC="export GIT_COMMITTER_DATE=\$(tail -1 $COMMITS_FILE | awk '{ print \$1 }'); \ + echo \"Handling \$(cat .git/rebase-merge/msgnum)/\$(cat .git/rebase-merge/end) with date: \$GIT_COMMITTER_DATE\" >>$LOG_FILE; \ + grep -vF \"\$GIT_COMMITTER_DATE\" $COMMITS_FILE >$COMMITS_FILE.tmp; \ + mv $COMMITS_FILE.tmp $COMMITS_FILE; \ + test -n \"\$GIT_COMMITTER_DATE\" && git commit --date=\${GIT_COMMITTER_DATE} --amend --no-edit -n ${COMMIT_ARGS}" -git rebase --exec "${REDATE_EXEC}" ${REBASE_REF} >${LOG_FILE} 2>&1 + +echo "Rebase ref: ${REBASE_REF}" >>$LOG_FILE +git rebase --exec "${REDATE_EXEC}" ${REBASE_REF} >>${LOG_FILE} 2>&1 RESULT=$?