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

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



답변

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의 대답에 약간의 재미를 돌려서 죄송합니다)


답변

아니요 , 간단히 힘내 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 스크립트는 도움이 될 수 있습니다. 각 파일에 대해 파일이 수정 된 가장 최근 커밋의 타임 스탬프를 적용합니다.

  • –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의 경우 4 초 미만 (커밋 24,000 개, 파일 2,500 개), Linux 커널의 경우 1 분 미만 (파일 40,000 개, 커밋 300,000 개)


답변

이것은 그가 우분투에서 나를 위해 속임수를 쓴 것입니다 (OSX의 date (1)에 “-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 및 파일 타임 스탬프와 충돌했습니다.

당신의 아이디어 중 일부를 테스트하고 내가 원하는 것을 거의 수행하는 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