|
| 1 | +#!/bin/bash |
| 2 | +# Description: |
| 3 | +# |
| 4 | +# This script allows you to generate a baseline commit history maintains the |
| 5 | +# original author / committor information before making upstream contribution. |
| 6 | +# Inspired by https://stosb.com/blog/retaining-history-when-moving-files-across-repositories-in-git/ |
| 7 | +# |
| 8 | +# See usage for more detailed description. |
| 9 | + |
| 10 | +function usage() { |
| 11 | +cat <<DOCEND |
| 12 | +Description: |
| 13 | +
|
| 14 | + This script takes a list of file as input. Find out all the commits containing the input |
| 15 | + file list, then rewrites the history from START_COMMIT to END_COMMIT, removing all commits |
| 16 | + does not contain file within input file list. For the remaining commits, trim out all the |
| 17 | + changes not applied to input file list. The end result is a commit history after START_COMMIT, |
| 18 | + all commits are specific for input file list. |
| 19 | +
|
| 20 | + Note: after you get a rewrite history, you might want to review it and use 'git rebase' to get |
| 21 | + an even cleaner history. |
| 22 | +
|
| 23 | +Environment variables: |
| 24 | +
|
| 25 | + START_COMMIT default is the commit right before message "Apply IBM specific changes". |
| 26 | + This commit won't be changed. |
| 27 | + END_COMMIT default is "head" which is the last commit to be rewrite. |
| 28 | +
|
| 29 | +Parameters: |
| 30 | +
|
| 31 | + List of files to collect commits from |
| 32 | +
|
| 33 | +Example: |
| 34 | +
|
| 35 | + env START_COMMIT=a3a8b85 END_COMMIT=head ./prepare-upstream-contribution.sh detect_secrets/plugins/softlayer.py tests/plugins/softlayer_test.py |
| 36 | +DOCEND |
| 37 | + exit 1 |
| 38 | +} |
| 39 | + |
| 40 | +if [[ "$1" == "-h" || "$1" == "--help" ]]; then |
| 41 | + usage |
| 42 | +fi |
| 43 | + |
| 44 | +echo "File to filter is ${FILES:=$@}" |
| 45 | +if [ -z "$FILES" ]; then |
| 46 | + echo "Incoming file list is empty" |
| 47 | + exit 1 |
| 48 | +fi |
| 49 | + |
| 50 | +echo "START_COMMIT is ${START_COMMIT:=$(git log --grep='Apply IBM specific changes' --pretty=format:'%h')~1}" |
| 51 | +echo "END_COMMIT is ${END_COMMIT:=head}" |
| 52 | +echo "Temp branch is ${TEMP_BRANCH:=rewrite-$(head /dev/urandom | base64 | tr -dc a-z0-9 | head -c8)}" |
| 53 | + |
| 54 | +TEMP_GIT_DIR=${TEMP_BRANCH}-newroot |
| 55 | +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) |
| 56 | +git checkout -b ${TEMP_BRANCH} |
| 57 | + |
| 58 | +# Use filter to copy file to a temporarity location |
| 59 | +git filter-branch --force --prune-empty --tree-filter "mkdir -p ${TEMP_GIT_DIR}; for f in $FILES; do mv \$f ${TEMP_GIT_DIR}/ 2>/dev/null; done; true;" ${START_COMMIT}..${END_COMMIT} |
| 60 | +# Set the temp location as root |
| 61 | +git filter-branch --prune-empty -f --subdirectory-filter ${TEMP_BRANCH}-newroot |
| 62 | +# Add filtered off commits to the top of starting commit |
| 63 | +git rebase ${START_COMMIT} |
| 64 | + |
| 65 | +# move files back to their original location and make a new commit |
| 66 | +for f in $FILES; do |
| 67 | + mv $(basename $f) $f 2>/dev/null |
| 68 | + git add $f |
| 69 | + git add $(basename $f) |
| 70 | +done |
| 71 | +git commit -m 'Move files back' |
| 72 | +git checkout ${CURRENT_BRANCH} |
| 73 | + |
| 74 | +echo "The prepared branch is ${TEMP_BRANCH}. Use command below to view the history" |
| 75 | +echo "" |
| 76 | +echo " git log --oneline -n10 ${TEMP_BRANCH}" |
| 77 | +echo "" |
0 commit comments