Git tricks

Reset all commit times to the original commit date

Added on 14 February 2024

The command originally published, git filter-repo, will still work but is no longer recommended. Git recommends using the git-filter-repo tool, which can achieve the same results with the following command:

$ git filter-repo --commit-callback 'commit.committer_date = commit.author_date' --force

Credit goes to Simon Willison for this solution.

$ git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; export GIT_COMMITTER_DATE'

When rebasing commits, the date information is updated to the current date and time. There are two times stored in a commit however; commit date and author date.

The author date is the original date of the commit, so running a filter-branch across the repository will reset the date of every commit to the original author commit.

Reset all commit author information for a specific name/email

$ git filter-branch --env-filter '
  OLD_EMAIL="old@email.com"
  NEW_NAME="New Name"
  NEW_EMAIL="new@email.com"

  if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
  then
      export GIT_COMMITTER_NAME="$NEW_NAME"
      export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
  fi

  if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
  then
      export GIT_AUTHOR_NAME="$NEW_NAME"
      export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
  fi
  ' --tag-name-filter cat -- --branches --tags

If searching by name instead of email, swap $GIT_COMMITTER_EMAIL and $GIT_AUTHOR_EMAIL with $GIT_COMMITTER_NAME and $GIT_AUTHOR_NAME name respectively.

Format the output of logs

Aliases for Git can be set up to display customised outputs from git log, typically using the --pretty=format:'...' flag.

See my own Git configuration file for examples of log formatting.

The Pro Git book lists:

Split one existing commit into many commits

Run an interactive rebase at the specific commit:

$ git rebase -i <id>^

Mark the commit to split as edit in the interactive rebase's todo:

edit <id>

Once editing the commit, reset the HEAD to unstage all files from the commit being edited:

$ git reset HEAD~

With all files unstaged, select the files to commit with git add, commit them and repeat this process until the commit is split as desired. Then let the rebase continue:

$ git rebase --continue

Export a stash to a file

$ git stash show -p > stash.patch

To apply the patch:

$ git apply stash.patch

Remove untracked files in Git

First, double check which untracked files Git will remove using -n, the dry run flag:

$ git clean -n -d

Once happy with the output of the dry run, delete the untracked files via:

$ git clean -d -f

The -d flag tells Git to recursively delete files in directories. -f is required to force the removal of files if the Git configuration variable clean.requireForce is set to true.

You can use the -i flag to interactively delete files and directories. This is useful if only certain untracked files should be removed.

Find and replace text in commit messages

$ git-filter-repo --replace-message <expressions_file> --refs <refs+>

An example of an expression that will change all instances of find to replace is:

find===>replace