#!/bin/bash4 -eC
# git-filter-only-files - Rewrite history to keep only specified files
# Copyright (C) 2016-2017 Ivan Zakharyaschev <imz@altlinux.org>
set -o pipefail

usage()
{
cat <<'EOF'
git-filter-only-files
- Rewrite history to keep only the files given on stdin

Usage example:
  pushd "$(git rev-parse --show-toplevel)"
  git-ls-paths-modified-since SINCE OLD_COMMIT \
  | git-filter-only-files OLD_COMMIT NEW_BRANCH
  popd

It rewrites the history of OLD_COMMIT from the very root;
and saves the result as NEW_BRANCH.

Internally, it uses git-filter-branch and git-update-index-keeping-only.

There is a reason for git-filter-branch to refuse to work not at the
toplevel Git working dir. Similarly, the given file paths should be
relative to the toplevel dir, and this tool should be called at the
toplevel dir.
EOF
}

case "$1" in
    -h|--help|--usage)
        usage
        exit 0
        ;;
esac

readonly OLD_COMMIT="$1"; shift || { usage >&2; exit 1; }
readonly NEW_BRANCH="$1"; shift || { usage >&2; exit 1; }

# Save the list to use multiple times afterwards:
files_to_keep="$(cat)"
readonly files_to_keep
export files_to_keep

# If smth goes wrong, inspect and remove this branch (manually):
git branch "$NEW_BRANCH" "$OLD_COMMIT"

git filter-branch --prune-empty \
    --index-filter 'echo "$files_to_keep" | git-update-index-keeping-only -q' \
    "$NEW_BRANCH"

# If we were able to create the branch,
# it is fresh and new, created specially for this filter.
# No need to save a backup.
git update-ref -d refs/original/refs/heads/"$NEW_BRANCH"
