원래 생성 / 수정 된 타임 스탬프를 알거나 얻을 수있는 방법이 있습니까?
원래 생성 / 수정 된 타임 스탬프를 알거나 얻을 수있는 방법이 있습니까?
답변:
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의 대답에 약간의 재미를 돌려서 죄송합니다)
find의 -printf확장 에 의존 하며, 저는 메타 스토어 (C 프로젝트)가 이식성을 높이기 위해 훨씬 더 많은 작업을 수행한다고 확신합니다. 매우 유감입니다. 이 상황이 바뀌면 여기에 다시 게시하겠습니다.
아니요 , 간단히 힘내은 metastore 또는 git-cache-meta와 같은 타사 도구를 사용하지 않는 한 이러한 (meta-) 정보를 저장하지 않습니다 . 저장되는 유일한 타임 스탬프는 패치 / 변경이 생성 된 시간 (작성자 시간)과 커밋이 생성 된 시간 (커미터 시간)입니다.
Git은 백업 유틸리티 나 동기화 도구가 아닌 버전 제어 시스템이므로 의도적으로 설계된 것입니다.
UPDATE : TL; DR : git 자체는 원래 시간을 저장하지 않지만 일부 솔루션은 다양한 방법으로이를 우회합니다. git-restore-mtime다음 중 하나입니다.
https://github.com/MestreLion/git-tools/
Ubuntu / Debian : sudo apt install git-restore-mtime
Fedora / RHEL / CentOS :sudo yum install git-tools
자세한 내용은 다른 답변 을 참조하십시오.
전체 고지 사항 : 저는 다음의 저자입니다. git-tools
이 Python 스크립트는 도움이 될 수 있습니다. 각 파일에 대해 파일이 수정 된 가장 최근 커밋의 타임 스탬프를 적용합니다.
아래는 스크립트 의 진짜 베어 본 버전입니다. 실제 사용을 위해 위의보다 강력한 버전 중 하나를 강력히 제안합니다.
#!/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의 경우 4 초 미만 (커밋 24,000 개, 파일 2,500 개), Linux 커널의 경우 1 분 미만 (파일 40,000 개, 커밋 300,000 개)
$ python ./git-restore-mtime Traceback (most recent call last): File "./git-restore-mtime", line 122, in <module> 'git rev-parse --show-toplevel --git-dir')).split('\n')[:2] TypeError: Type str doesn't support the buffer API어떤 버전의 Python이 필요한지 알려주시겠습니까? 3.3.3을 사용하고 있습니다
str파이썬 2의 것과 동일 bytestring하지만, 파이썬 3에서 str파이썬 3에 unicode당신이에서이 문제를보고하십시오 수 파이썬 2에 github.com/MestreLion/git-tools/issues ?
나는 이미 얼마 동안 git 및 파일 타임 스탬프와 충돌했습니다.
당신의 아이디어 중 일부를 테스트하고 내가 원하는 것을 거의 수행하는 perl에서 스크립트를 찾을 때까지 (일부 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 기본 후크에 연결할 수 있습니다.
다음은 공백이 포함 된 경로를 고려하는 내 솔루션입니다.
#! /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
이있는 시간이 걸릴하지 않습니다 git log보고서는, 시스템에 의해보고 된 시간이다. 파일이 커밋 된 이후의 시간을 원한다면 git log대신 솔루션을 사용하십시오.date -r
네이티브 git에는 기능이 없지만 후크 스크립트 또는 타사 도구를 통해 얻을 수 있습니다.
나는 시도했다 metastore. 매우 빠르지 만 설치가 필요하지 않으며 메타 데이터가 일반 텍스트 형식으로 저장되지 않습니다. git-cache-meta내가 시도한 간단한 도구이지만 대규모 저장소의 경우 매우 느리고 (수만 개의 파일이있는 저장소의 경우 메타 데이터 파일을 업데이트하는 데 몇 분이 소요됨) 플랫폼 간 호환성 문제가 발생할 수 있습니다. setgitperms그리고 다른 접근 방식에도 내가 싫어하는 단점이 있습니다.
마침내이 작업을위한 후크 스크립트를 만들었습니다 : git-store-meta . 그것은이 매우 가벼운 의존성 (* nix에서 스크립트 쉘을, sort그리고 perl자식에 의해 요구하고 선택적으로 된, chown, chgrp과 touch) 자식, 실행할 수있는 플랫폼 설치해야합니다 추가하는 것도 있도록 바람직한 성능을 수만와의 repo에 대해 ( 파일의 경우 메타 데이터 파일을 업데이트하는 데 10 초 미만이 걸리며 생성하는 데 더 오래 걸리지 만 일반 텍스트 형식으로 데이터를 저장하며 "저장"또는 "로드"할 메타 데이터를 사용자 정의 할 수 있습니다 .
그것은 나를 위해 잘 작동했습니다. 메타 스토어, git-cache-meta 및 기타 접근 방식에 만족하지 않는 경우 이것을 시도하십시오.
단순함에 감사드립니다.
# 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 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
Windows 환경의 경우 Delphi 10.1 Berlin에서 소스 트리의 모든 파일 날짜를 .gitfilattr 파일로 수집하고 확인 된 소스 트리에 다시 적용 할 수있는 작은 (빠르고 더러운) EXE를 작성했습니다.
물론 GitHub에서 코드를 공유합니다.
https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr
GitLab 러너를 기반으로 한 빌드 시스템에서 사용합니다.
이것이 커밋 시간을 의미하는지 아니면 다른 것을 의미하는지에 대한 내 (및 다른 사람들의) 해석에 약간 모호성이 있지만 커밋 시간을 의미한다고 가정하면이 간단한 한 줄이 Linux에서 작동합니다 (Dietrich Epp의 답변 스 니펫을 기반으로 함). ) :
git ls-files | xargs -I{} bash -c 'touch "{}" --date=@$(git log -n1 --pretty=format:%ct -- "{}")'
그러나 cregox의 댓글에서 원래 질문에 연결된 더 정교한 답변 (git hooks 포함)이 있습니다.
--date=@foo
GNU 도구로.
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)
CentOS 7에는 /usr/share/doc/rsync-*/support/git-set-file-times에서 동일한 스크립트 가 있고 Debian (및 파생물) /usr/share/doc/rsync/scripts/git-set-file-times.gz에서는 원본이 Eric Wong의 스크립트 이며 여기에 https://yhbt.net/git-set-file-times 있습니다.
여기에 언급 된 다른 예제보다 빠르게 작동하며 Linux 배포판에 이미있는 것이 더 편리 할 수 있습니다.
여기 내 꺼야.
발견 된 각 파일에 대해 '로그 가져 오기'를 호출하지 않기 때문에 다른 파일보다 조금 더 빠릅니다. 대신 'git log'를 한 번 호출하고 해당 출력을 터치 명령으로 변환합니다.
단일 셸 명령 버퍼에 맞추기에는 하나의 커밋에 나열된 파일이 너무 많은 경우가 있습니다. "getconf ARG_MAX"를 실행하여 명령의 최대 길이 (바이트)를 확인하십시오. 데비안 설치에서는 2MB로 충분합니다.
# set file last modification time to last commit of file
git log --reverse --date=iso --name-only | \
grep -vE "^(commit |Merge:|Author:| |^$)" | \
grep -B 1 "^[^D][^a][^t][^e][^:][^ ]" | \
grep -v "^\-\-" | \
sed "s|^\(.*\)$|\"\1\"|;s|^\"Date: *\(.*\)\"$|~touch -c -m -d'\1'|" | \
tr '~\n' '\n ' | \
sh -
줄별 설명 :
속도면에서 700 개 디렉토리의 6500 개 파일에 대해 5 초 1700이 커밋됩니다.