Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save maxkagamine/32652c1a5173e827b63d55826088b8ef to your computer and use it in GitHub Desktop.
Save maxkagamine/32652c1a5173e827b63d55826088b8ef to your computer and use it in GitHub Desktop.
Retroactively add license header, chmod, sign commits (git filter-branch example)

Save the following script to ~/tree-filter.sh and chmod +x it:

#!/bin/bash
set -eo pipefail

fd '\.cs$' -H -E .git -E Migrations -tf -x perl -pi -e '
  if ($. == 1) {
    print <<'\''EOF'\'';
// Copyright (c) Your Name
// Licensed under the Apache License, Version 2.0

EOF
    s/^\xEF\xBB\xBF// # Remove BOM
  }
'

fd -H -E .git -tf -X chmod 644

Then run:

FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --tree-filter ~/tree-filter.sh HEAD

This example will prepend the header to all .cs files (removing the BOM if present), skipping EF migrations, and remove the executable bit from all files. Using fd as it excludes .gitignore'd files by default and runs -x in parallel. Passing -H -E .git will include any git-tracked hidden files ("include hidden except for .git").

filter-branch will leave the commits unsigned, however. To resign them:

FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --commit-filter 'git commit-tree -S "$@";' HEAD

Both commands will leave the committer date as-is (unlike rebasing).


This SO answer suggests using sed to prepend a license header:

https://stackoverflow.com/questions/8866416/add-a-licenses-to-file-headers-in-tree-retroactively

However, this won't work if the file is a single line. The r command only queues the file to be written to the output once sed moves to the next line; it doesn't output the file immediately (moving the pattern buffer to the hold space and back with h/g is therefore unnecessary, although it's entirely possible the behavior is different on some versions of sed). With auto printing on, the current line will be printed first. The trick with N is that, by manually reading the next line and appending it to the current line (still held in the pattern buffer), it causes sed to write the queued file before the first line (now the first two lines) is printed. Unfortunately, if there are no further lines to be read, N causes sed to quit, resulting in the current line being auto-printed first, followed by the file contents.

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