Skip to content

Instantly share code, notes, and snippets.

@tmelz
Last active April 12, 2023 15:09
Show Gist options
  • Save tmelz/76e655a3d8f2878fc9a4 to your computer and use it in GitHub Desktop.
Save tmelz/76e655a3d8f2878fc9a4 to your computer and use it in GitHub Desktop.
auto format java files with google-java-format
#!/bin/bash
# Auto format changed java files using google-java-format.
# To install, copy this file into $repo/.git/hooks and remove the .sh extension.
# Download the google-java-format JAR from
# https://github.com/google/google-java-format
# A more mature implementation of this would be a plugin for Yelp's pre-commit library:
# http://pre-commit.com/
echo "Running auto-formatter for any changed Java files"
echo "(formatting changes will be automatically added to your commit)"
# Grab root directory to help with creating an absolute path for changed files.
root_dir="$(git rev-parse --show-toplevel)"
[ -d "${root_dir}" ] || exit 1
# TODO add your path here.
jar_base_dir="jar/"
# To avoid any unexpected behavior, we need to "stash" any unstaged changes.
# We could use "git stash" but the situation gets complicated because we
# need to make additional changes with the formatter.
# Here's how we could do this if we didn't need to make additional changes:
# http://stackoverflow.com/a/20480591
# But since we do, we follow the same general pattern as the "pre-commit" lib:
# https://github.com/pre-commit/pre-commit/blob/master/pre_commit/staged_files_only.py#L15
# Basically we just diff the unstaged changes, store the patch, and apply it later.
# In the future, we should consider migrating to using that library.
staged_changes_diff=$(mktemp -t format_patch)
git diff --ignore-submodules --binary --exit-code --no-color > $staged_changes_diff
if [ $? -eq 1 ]; then
echo "Found unstaged changes, storing in ${staged_changes_diff}"
echo "Clearing unstaged changes for formatting, will restore after formatting."
git checkout -- ${root_dir}
stored_staged_changes=true
else
stored_staged_changes=false
fi
formatter_jar="${root_dir}/${jar_base_dir}/google-java-format-0.1-alpha.jar"
formatter_cmd="java -jar ${formatter_jar}"
# Format file in-place and use 4-space style (AOSP).
# TODO remove --aosp flag if you want 2-space style.
formatter_args="--replace --aosp"
# filter=ACMR shows only added, changed, modified, or renamed files.
# Get only java files and prepend the root directory to make the paths absolute.
changed_java_files=($(git diff --cached --name-only --diff-filter=ACMR \
| grep ".*java$" \
| sed "s:^:${root_dir}/:"))
# If we have changed java files, format them!
if [ ${#changed_java_files[@]} -gt 0 ]; then
# Do the formatting, stage the changes, and print out which files were changed.
eval ${formatter_cmd} ${formatter_args} "${changed_java_files[@]}"
git add "${changed_java_files[@]}"
echo "${changed_java_files[@]}" | xargs basename | sed "s/^/ Formatting: /"
fi
echo "Finished formatting."
if $stored_staged_changes ; then
echo "Restoring unstaged changes"
git apply "${staged_changes_diff}"
if [ $? -eq 1 ]; then
echo "Shoot! We failed to re-apply your unstaged changes."
echo "The patch for these changes is preserved at ${staged_changes_diff}"
fi
fi
@code-twister
Copy link

Nice script! I had some issues on Debian Jesse, and managed to make it work, let me know if you're interested in the fix.

@PramodForce
Copy link

@code-twister : Could you please share the fix?

@RingierAlec
Copy link

There is a problem using this script under Linux.

staged_changes_diff=$(mktemp -t format_patch)
Error mktemp: too few X's in template ‘format_patch’

Although OSX works, the above can be fixed on Linux by changing the line to read.

staged_changes_diff=$(mktemp -t format_patch.XXX)

@iiliev2
Copy link

iiliev2 commented Apr 12, 2023

Does it work if I use IntelliJ's changelist feature to commit?

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