Programing

원래 생성 / 수정 된 타임 스탬프가있는 오래된 파일 체크 아웃

lottogame 2020. 11. 1. 17:13
반응형

원래 생성 / 수정 된 타임 스탬프가있는 오래된 파일 체크 아웃


원래 생성 / 수정 된 타임 스탬프를 알거나 얻을 수있는 방법이 있습니까? 감사.


Git 데이터베이스에 기록 된 유일한 타임 스탬프는 작성자와 커밋 타임 스탬프라고 생각합니다. 가장 최근 커밋과 일치하도록 파일의 타임 스탬프를 수정하는 Git 옵션이 표시되지 않으며 이것이 기본 동작이 아니라는 것이 합리적입니다 (그렇다면 Makefile이 올바르게 작동하지 않기 때문입니다).

파일의 수정 날짜를 가장 최근 커밋 시간으로 설정하는 스크립트를 작성할 수 있습니다. 다음과 같이 보일 수 있습니다.

IFS="
"
for FILE in $(git ls-files)
do
    TIME=$(git log --pretty=format:%cd -n 1 --date=iso -- "$FILE")
    TIME=$(date -j -f '%Y-%m-%d %H:%M:%S %z' "$TIME" +%Y%m%d%H%M.%S)
    touch -m -t "$TIME" "$FILE"
done

, metastore 또는 git-cache-meta 는 이러한 (meta-) 정보를 저장할 수 있습니다! 타사 도구없이 Git 자체로는 불가능합니다. Metastore 또는 git-cache-meta 는 파일에 대한 모든 파일 메타 데이터를 저장할 수 있습니다.

메타 스토어 또는 git-cache-meta는 백업 유틸리티 및 동기화 도구를 지원할뿐만 아니라 바로 그 목적을 위해 고안된 것입니다.

(Jakub의 대답에 약간의 재미를 돌려서 죄송합니다)


아니요 , Git metastore 또는 git-cache-meta 와 같은 타사 도구를 사용하지 않는 한 이러한 (meta-) 정보를 저장하지 않습니다 . 저장되는 유일한 타임 스탬프는 패치 / 변경이 생성 된 시간 (작성자 시간)과 커밋이 생성 된 시간 (커미터 시간)입니다.

Git은 백업 유틸리티 나 동기화 도구가 아닌 버전 제어 시스템이므로 의도적으로 설계된 것입니다.


이 Python 스크립트는 도움이 될 수 있습니다. 각 파일에 대해 파일이 수정 된 가장 최근 커밋의 타임 스탬프를 적용합니다.

  • --help, 디버그 메시지와 함께 핵심 기능 . 작업 트리 내 어디에서나 실행 가능
  • 다양한 옵션을 갖춘 본격적인 짐승 . 모든 저장소 레이아웃을 지원합니다.

아래는 스크립트 진짜 베어 본 버전입니다. 실제 사용을 위해 위의보다 강력한 버전 중 하나를 강력히 제안합니다.

#!/usr/bin/env python
# Bare-bones version. Current dir must be top-level of work tree.
# Usage: git-restore-mtime-bare [pathspecs...]
# By default update all files
# Example: to only update only the README and files in ./doc:
# git-restore-mtime-bare README doc

import subprocess, shlex
import sys, os.path

filelist = set()
for path in (sys.argv[1:] or [os.path.curdir]):
    if os.path.isfile(path) or os.path.islink(path):
        filelist.add(os.path.relpath(path))
    elif os.path.isdir(path):
        for root, subdirs, files in os.walk(path):
            if '.git' in subdirs:
                subdirs.remove('.git')
            for file in files:
                filelist.add(os.path.relpath(os.path.join(root, file)))

mtime = 0
gitobj = subprocess.Popen(shlex.split('git whatchanged --pretty=%at'),
                          stdout=subprocess.PIPE)
for line in gitobj.stdout:
    line = line.strip()
    if not line: continue

    if line.startswith(':'):
        file = line.split('\t')[-1]
        if file in filelist:
            filelist.remove(file)
            #print mtime, file
            os.utime(file, (mtime, mtime))
    else:
        mtime = long(line)

    # All files done?
    if not filelist:
        break

모든 버전은 단일 git whatchanged명령으로 생성 된 전체 로그를 구문 분석 합니다. 이는 각 파일에 대해 삭제하는 것보다 수백 배 더 빠릅니다. git (24,000 개 커밋, 2,500 개 파일)의 경우 4 초 미만, Linux 커널의 경우 1 분 미만 (파일 40,000 개, 커밋 300,000 개)


이것은 그가 우분투에서 나를 위해 속임수를 쓴 것입니다 (날짜 (1)에 OSX의 "-j"플래그가 없습니다)

for FILE in $(git ls-files)
do
    TIME=$(git log --pretty=format:%cd -n 1 --date=iso $FILE)
    TIME2=`echo $TIME | sed 's/-//g;s/ //;s/://;s/:/\./;s/ .*//'`
    touch -m -t $TIME2 $FILE
done 

나는 이미 얼마 동안 git 및 파일 타임 스탬프와 충돌했습니다.

당신의 아이디어 중 일부를 테스트하고 내가 원하는 것을 거의 수행하는 펄에서 스크립트를 찾을 때까지 (일부 git wiki에서) 엄청나게 크고 전임자 / 램 무거운 스크립트를 만들었습니다. https://git.wiki.kernel.org/index.php/ExampleScripts

그리고 내가 원했던 것은 커밋 날짜를 기반으로 파일의 마지막 수정 사항을 보존 할 수있는 것입니다.

따라서 약간의 재조정 후 스크립트는 약 2 ~ 3 분 안에 200k 파일 의 생성 및 수정 날짜를 변경할 수 있습니다 .

#!/usr/bin/perl
my %attributions;
my $remaining = 0;

open IN, "git ls-tree -r --full-name HEAD |" or die;
while (<IN>) {
    if (/^\S+\s+blob \S+\s+(\S+)$/) {
        $attributions{$1} = -1;
    }
}
close IN;

$remaining = (keys %attributions) + 1;
print "Number of files: $remaining\n";
open IN, "git log -r --root --raw --no-abbrev --date=raw --pretty=format:%h~%cd~ |" or die;
while (<IN>) {
    if (/^([^:~]+)~([^~]+)~$/) {
        ($commit, $date) = ($1, $2);
    } elsif (/^:\S+\s+1\S+\s+\S+\s+\S+\s+\S\s+(.*)$/) {
        if ($attributions{$1} == -1) {
            $attributions{$1} = "$date";
            $remaining--;

            utime $date, $date, $1;
            if ($remaining % 1000 == 0) {               
                print "$remaining\n";
            }
            if ($remaining <= 0) {
                break;
            }
        }
    }
}
close IN;

리포지토리에 10,000 개 이상의 파일이 없다고 가정하면 실행하는 데 몇 초가 걸리므로 체크 아웃, 풀 또는 기타 git 기본 후크에 연결할 수 있습니다.


Native git doesn't have the functionality, but it can be achieved by hook scripts or third party tools.

I've tried metastore. It's very fast, but I don't like the need to install and that metadata are not stored in plain text format. git-cache-meta is a simple tool I've tried, but it's extremely slow for large repos (for a repo with tens of thousands of files, it takes minutes to update the metadata file) and could have cross-platform compatibility issues. setgitperms and other approaches also have their shortcomings that I don't like.

At last I made a hook script for this job: git-store-meta. It has very light dependency (*nix shell, sort, and perl, which is required by git, and optionally chown, chgrp and touch) so that nothing additional have to be installed for a platform that can run git, desirable performance (for a repo with tens of thousands of files, it takes < 10 seconds to update the metadata file; although longer to create), saves data in plain text format, and which metadata to be "saved" or "loaded" is customizable.

It has worked fine for me. Try this if you are not satisfied with metastore, git-cache-meta, and other approaches.


Here is my solution that takes into consideration paths that contain spaces:

#! /bin/bash

IFS=$'\n'
list_of_files=($(git ls-files | sort))
unset IFS

for file in "${list_of_files[@]}"; do
  file_name=$(echo $file)

  ## When you collect the timestamps:
  TIME=$(date -r "$file_name" -Ins)

  ## When you want to recover back the timestamps:
  touch -m -d $TIME "$file_name"
done

Note that this does not take the time which git log reports, it's the time reported by the system. If you want the time since the files were commited use git log solution instead of date -r


For Windows environment I wrote a small (quick and dirty) EXE in Delphi 10.1 Berlin that collects all file dates in the source tree into the file .gitfilattr and can apply them on the checked our source tree again.

Of course I share the code in GitHub:

https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr

I use it in my build system based on GitLab runners.


There's some ambiguity in my (and others') interpretation of the OP about whether this means the commit time or something else, but assuming it means commit time, then this simple one-liner will work in linux (based on answer snippet from Dietrich Epp):

git ls-files | xargs -I{} bash -c 'touch "{}" --date=@$(git log -n1 --pretty=format:%ct -- "{}")'

But there's more sophisticated answers (including git hooks) linked from a comment to the original question by cregox.


I hope you appreciate the simplicity:

# getcheckin - Retrieve the last committed checkin date and time for
#              each of the files in the git project.  After a "pull"
#              of the project, you can update the timestamp on the
#              pulled files to match that date/time.  There are many
#              that don't believe that this is not a good idea, but
#              I found it useful to get the right source file dates
#
#              NOTE: This script produces commands suitable for
#                    piping into BASH or other shell
# License: Creative Commons Attribution 3.0 United States
# (CC by 3.0 US)

##########
# walk back to the project parent or the relative pathnames don't make
# sense
##########
while [ ! -d ./.git ]
do
    cd ..
done
echo "cd $(pwd)"
##########
# Note that the date format is ISO so that touch will work
##########
git ls-tree -r --full-tree HEAD |\
    sed -e "s/.*\t//" | while read filename; do
    echo "touch --date=\"$(git log -1 --date=iso --format="%ad" -- "$filename")\" -m $filename" 
done

With GNU tools.

s=$(git ls-files  | wc -l); 
git ls-files -z  |
 xargs -0 -I{} -n1 bash -c \
"git log --date=format:%Y%m%d%H%M.%S '--pretty=format:touch -m -t %cd \"{}\"%n' -n1 -- {}"|
 pv -l -s$s |
 parallel -n1 -j8

 967  0:00:05 [ 171 /s] [=====================================>  ] 16% 

.

$ git --version ; xargs --version | sed 1q ; ls --version | sed 1q;
  parallel --version  | sed 1q;  pv --version | sed 1q; sh --version | sed 1q 
git version 2.13.0
xargs (GNU findutils) 4.6.0
ls (GNU coreutils) 8.25
GNU parallel 20150522
pv 1.6.0 - Copyright 2015 Andrew Wood <andrew.wood@ivarch.com>
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

참고URL : https://stackoverflow.com/questions/2179722/checking-out-old-file-with-original-create-modified-timestamps

반응형