diff --git a/Commands.md b/Commands.md index 72e45227b..a644e45be 100644 --- a/Commands.md +++ b/Commands.md @@ -1520,12 +1520,14 @@ $ git browse-ci upstream ## git utimes -Change files modification time to their last commit date. +Change files modification time to their last commit date. Does not touch files that are in the working tree or index. + +The `--newer` flag preserves the original modification time of files that were committed from the local repo, by only touching files that are newer than their last commit date. ```bash git-extras$ ls -l bin | head total 308 --rwxr-xr-x 1 vt vt 489 Nov 8 13:56 git-alias +-rwxr-xr-x 1 vt vt 489 Jul 28 2015 git-alias -rwxr-xr-x 1 vt vt 1043 Nov 8 13:56 git-archive-file -rwxr-xr-x 1 vt vt 970 Nov 8 13:56 git-authors -rwxr-xr-x 1 vt vt 267 Nov 8 13:56 git-back @@ -1534,8 +1536,8 @@ total 308 -rwxr-xr-x 1 vt vt 6282 Nov 8 13:56 git-bulk -rwxr-xr-x 1 vt vt 18561 Nov 8 13:56 git-changelog -rwxr-xr-x 1 vt vt 215 Nov 8 13:56 git-clear -git-extras$ git utimes -+ touch -d 2015-08-09T19:27:49+08:00 bin/git-alias + +git-extras$ git utimes --newer + touch -d 2020-05-22T10:40:29+08:00 bin/git-archive-file + touch -d 2017-05-05T16:02:09+08:00 bin/git-authors + touch -d 2020-02-23T11:41:54+08:00 bin/git-back @@ -1545,9 +1547,10 @@ git-extras$ git utimes + touch -d 2019-09-05T12:41:38+08:00 bin/git-changelog + touch -d 2016-11-19T16:41:19+00:00 bin/git-clear [...] + git-extras$ ls -l bin | head total 308 --rwxr-xr-x 1 vt vt 489 Aug 9 2015 git-alias +-rwxr-xr-x 1 vt vt 489 Jul 28 2015 git-alias -rwxr-xr-x 1 vt vt 1043 May 22 05:40 git-archive-file -rwxr-xr-x 1 vt vt 970 May 5 2017 git-authors -rwxr-xr-x 1 vt vt 267 Feb 23 2020 git-back @@ -1558,6 +1561,8 @@ total 308 -rwxr-xr-x 1 vt vt 215 Nov 19 2016 git-clear ``` +Note above, that because of the `--newer` flag, the file `git-alias` was not touched since its modified date is earlier than the commit date. + ## git abort Abort current rebase, merge or cherry-pick, without the need to find exact command in history. diff --git a/bin/git-utimes b/bin/git-utimes index 9e45c0513..80d9d337e 100755 --- a/bin/git-utimes +++ b/bin/git-utimes @@ -2,20 +2,28 @@ # # Change files modification time to their last commit date # -if [ "$1" = --touch ]; then +if [ "$1" = "--touch" ]; then # Internal use option only just to parallelize things. - shift + newer_flag="" + [ "$2" = "--newer" ] && newer_flag="true" + shift 2 + bsd=$(date -j > /dev/null 2>&1 && echo 'true') + if [ -n "$bsd" ]; then + stat_flags="-f %m" + date_flags="-r" + else + stat_flags="-c %Y" + date_flags="-d@" + fi for f; do - iso_t=$(git --no-pager log --no-renames --pretty=format:%cI -1 @ -- "$f" 2>/dev/null) - if [ -n "$iso_t" ]; then - bsd=$(date -j > /dev/null 2>&1 && echo 'true') - if [ "$bsd" == "true" ]; then - t=$(date -j -f %Y-%m-%dT%H:%M:%S "$iso_t" +%Y%m%d%H%M.%S) - else - t=$(date -d"$iso_t" +%Y%m%d%H%M.%S) + git_s=$(git --no-pager log --no-renames --pretty=format:%ct -1 @ -- "$f" 2>/dev/null) + mod_s=$(stat $stat_flags "$f" 2>/dev/null) + if [ -n "$git_s" ] && [ -n "$mod_s" ] && [ "$mod_s" -ne "$git_s" ]; then + if [ "$mod_s" -gt "$git_s" ] || [ ! -n "$newer_flag" ]; then + t=$(date $date_flags$git_s '+%Y%m%d%H%M.%S') + echo "+ touch -h -t $t $f" >&2 + touch -h -t "$t" "$f" fi - echo "+ touch -t $t $f" >&2 - touch -t "$t" "$f" fi done else @@ -25,6 +33,12 @@ else # because all args will go into single worker. NPROC=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null) # shellcheck disable=SC2086 - git ls-tree -z -r -t --name-only @ \ - | xargs -0 -P${NPROC:-1} -n${NPROC:-1} $opt_r git utimes --touch + # don't touch files that have been modified in the worktree or index + # bsd doesn't have `-z` option for `comm` and `cut`, so use `tr` as work around + prefix="$(git rev-parse --show-prefix) " + comm -23 <(git ls-tree -z -r --name-only --full-name @ | tr '\0' '\n' | sort) \ + <(git status -z --porcelain | tr '\0' '\n' | cut -c 4- | sort) \ + | cut -c ${#prefix}- \ + | tr '\n' '\0' \ + | xargs -0 -P${NPROC:-1} -n 24 $opt_r git utimes --touch "$1" fi diff --git a/check_dependencies.sh b/check_dependencies.sh index 639951036..05c2f735b 100755 --- a/check_dependencies.sh +++ b/check_dependencies.sh @@ -6,5 +6,5 @@ err() { } if ! command -v column >/dev/null 2>&1; then - err "Need to install dependency 'column' before installation" + err "Need to install dependency 'column' before installation (can be found in bsdmainutils)" fi diff --git a/man/git-utimes.md b/man/git-utimes.md index 5ad693a3e..9e9cf363c 100644 --- a/man/git-utimes.md +++ b/man/git-utimes.md @@ -3,23 +3,31 @@ git-utimes(1) -- Change files modification time to their last commit date ## SYNOPSIS -`git-utimes` +`git-utimes` [--newer] ## DESCRIPTION - Change files modification time to their last commit date. + Change files modification time to their last commit date. Does not touch files that are in the working tree or index. ## OPTIONS - No options needed. + --newer + + Preserves the original modification time of files that were committed from the local repo, by only touching files that are newer than their last commit date. ## EXAMPLES - git utimes + * Update all files' modification time to their last commit date, except those in working tree or index: + + $ git utimes + + * As above, but preserve original modification time of files that were committed from local repo: + + $ git utimes --newer ## AUTHOR -Written by Vitaly Chikunov <>, inspired by Stackexchange comments. +Written by Vitaly Chikunov <>, inspired by Stackexchange comments. Updated by Bill Wood <> to add `--newer` flag and ignore files in the working tree or index. ## REPORTING BUGS