Có cách nào để biết hoặc lấy dấu thời gian được tạo / sửa đổi ban đầu không? Cảm ơn.
Có cách nào để biết hoặc lấy dấu thời gian được tạo / sửa đổi ban đầu không? Cảm ơn.
Câu trả lời:
Tôi tin rằng dấu thời gian duy nhất được ghi lại trong cơ sở dữ liệu Git là dấu thời gian của tác giả và cam kết. Tôi không thấy tùy chọn nào để Git sửa đổi dấu thời gian của tệp để phù hợp với cam kết gần đây nhất và điều này có nghĩa là đây không phải là hành vi mặc định (vì nếu có, Makefiles sẽ không hoạt động chính xác).
Bạn có thể viết một tập lệnh để đặt ngày sửa đổi các tệp của mình thành thời điểm của lần cam kết gần đây nhất. Nó có thể trông giống như sau:
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
CÓ , siêu thị hoặc git-cache-meta có thể lưu trữ thông tin (meta-) như vậy! Git của chính nó, không có công cụ của bên thứ ba, không thể. Metastore hoặc git-cache-meta có thể lưu trữ bất kỳ siêu dữ liệu tệp nào cho một tệp.
Điều đó là do thiết kế, vì di căn hoặc git-cache-meta được thiết kế cho mục đích đó, cũng như hỗ trợ các tiện ích sao lưu và công cụ đồng bộ hóa.
(Xin lỗi chỉ là một chút vui vẻ về câu trả lời của Jakub)
find
của GNU -printf
và tôi gần như chắc chắn rằng công cụ di căn (là một dự án C) thậm chí còn nhiều công việc hơn để làm cho khả năng di động. Khá đáng tiếc. Tôi sẽ đăng lại ở đây nếu tôi phát hiện ra rằng tình hình này thay đổi.
NO , Git chỉ đơn giản là không lưu trữ như vậy (meta) thông tin , trừ khi bạn sử dụng công cụ của bên thứ ba như metastore hoặc git-cache-meta. Dấu thời gian duy nhất được lưu trữ là bản vá thời gian / thay đổi đã được tạo (thời gian của tác giả) và thời gian cam kết đã được tạo (thời gian của người thực hiện).
Đó là theo thiết kế, vì Git là hệ thống kiểm soát phiên bản, không phải là một tiện ích sao lưu hoặc công cụ đồng bộ hóa.
CẬP NHẬT : TL; DR: git bản thân nó không lưu thời gian gốc, nhưng một số giải pháp đã phá vỡ điều này bằng nhiều phương pháp khác nhau. git-restore-mtime
là một trong số họ:
https://github.com/MestreLion/git-tools/
Ubuntu / Debian: sudo apt install git-restore-mtime
Fedora / RHEL / CentOS:sudo yum install git-tools
Xem câu trả lời khác của tôi để biết thêm chi tiết
Tuyên bố từ chối trách nhiệm đầy đủ: Tôi là tác giả của git-tools
Tập lệnh python này có thể hữu ích: đối với mỗi tệp áp dụng dấu thời gian của lần cam kết gần đây nhất nơi tệp đã được sửa đổi:
Dưới đây là một phiên bản thực sự rõ ràng của kịch bản. Đối với việc sử dụng thực tế, tôi thực sự đề xuất một trong những phiên bản mạnh mẽ hơn ở trên:
#!/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
Tất cả các phiên bản phân tích cú pháp toàn bộ nhật ký được tạo bằng một git whatchanged
lệnh duy nhất , nhanh hơn hàng trăm lần so với việc ghi nhật ký cho từng tệp. Dưới 4 giây cho git (24.000 cam kết, 2.500 tệp) và dưới 1 phút cho nhân linux (40.000 tệp, 300.000 cam kết)
$ 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
Bạn có phiền có thể cho chúng tôi biết phiên bản Python nào là cần thiết không? Tôi đang sử dụng 3.3.3
str
trong Python 2 tương đương với bytestring
Python 3, trong khi str
Python 3 là unicode
Python 2. Bạn có thể vui lòng báo cáo vấn đề này tại github.com/MestreLion/git-tools/issues không?
Điều này đã làm anh ta lừa tôi trên ubuntu (thiếu cờ "-j" của OSX vào ngày (1))
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
Tôi đã giao tranh với git và dấu thời gian tệp được một thời gian rồi.
Đã thử nghiệm một số ý tưởng của bạn và tạo ra các tập lệnh cực kỳ lớn và nặng nề trước đó / ram của riêng tôi, cho đến khi tôi tìm thấy (trên một số git wiki) một tập lệnh trong perl gần như những gì tôi muốn. https://git.wiki.kernel.org/index.php/ExampleScripts
Và những gì tôi muốn là có thể duy trì sửa đổi cuối cùng của các tệp dựa trên ngày cam kết.
Vì vậy, sau một số điều chỉnh lại, tập lệnh có thể thay đổi ngày tạo và sửa đổi của 200k tệp trong khoảng 2-3 phút .
#!/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;
Giả sử rằng kho lưu trữ của bạn sẽ không có hơn 10k + tệp, điều này sẽ mất vài giây để thực thi, vì vậy bạn có thể kết nối nó với thanh toán, kéo hoặc các móc cơ bản git khác.
Đây là giải pháp của tôi có tính đến các đường dẫn có chứa khoảng trắng:
#! /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
Lưu ý rằng điều này không mất thời gian git log
báo cáo mà là thời gian được hệ thống báo cáo. Nếu bạn muốn thời gian kể từ khi các tệp được cam kết sử dụng git log
giải pháp thay vìdate -r
Gt gốc không có chức năng, nhưng nó có thể đạt được bằng các tập lệnh hook hoặc các công cụ của bên thứ ba.
Tôi đã thử metastore
. Nó rất nhanh, nhưng tôi không thích phải cài đặt và siêu dữ liệu đó không được lưu trữ ở định dạng văn bản thuần túy. git-cache-meta
là một công cụ đơn giản mà tôi đã thử, nhưng nó cực kỳ chậm đối với các kho lưu trữ lớn (đối với một kho lưu trữ có hàng chục nghìn tệp, phải mất vài phút để cập nhật tệp siêu dữ liệu) và có thể có vấn đề về tương thích đa nền tảng. setgitperms
và các cách tiếp cận khác cũng có những khuyết điểm mà tôi không thích.
Cuối cùng, tôi đã tạo một tập lệnh hook cho công việc này: git-store-meta . Nó có độ phụ thuộc rất nhẹ (* nix shell, sort
và perl
, được yêu cầu bởi git, và tùy chọn chown
, chgrp
và touch
) để không cần phải cài đặt thêm gì cho một nền tảng có thể chạy git, hiệu suất đáng mơ ước (đối với một repo có hàng chục nghìn của tệp, mất <10 giây để cập nhật tệp siêu dữ liệu; mặc dù thời gian tạo lâu hơn), lưu dữ liệu ở định dạng văn bản thuần túy và siêu dữ liệu nào được "lưu" hoặc "tải" có thể tùy chỉnh .
Nó đã làm việc tốt cho tôi. Hãy thử điều này nếu bạn không hài lòng với các phương pháp tiếp cận phổ biến, git-cache-meta và các phương pháp khác.
Tôi hy vọng bạn đánh giá cao sự đơn giản:
# 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
Đối với môi trường Windows, tôi đã viết một EXE nhỏ (nhanh và bẩn) trong Delphi 10.1 Berlin để thu thập tất cả ngày tháng của tệp trong cây nguồn vào tệp .gitfilattr và có thể áp dụng chúng trên cây nguồn đã được kiểm tra của chúng tôi một lần nữa.
Tất nhiên tôi chia sẻ mã trong GitHub:
https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr
Tôi sử dụng nó trong hệ thống xây dựng của mình dựa trên trình chạy GitLab.
Có một số mơ hồ trong cách giải thích OP của tôi (và những người khác) về việc liệu điều này có nghĩa là thời gian cam kết hay điều gì khác, nhưng giả sử nó có nghĩa là thời gian cam kết, thì một lớp lót đơn giản này sẽ hoạt động trong linux (dựa trên đoạn mã trả lời từ Dietrich Epp ):
git ls-files | xargs -I{} bash -c 'touch "{}" --date=@$(git log -n1 --pretty=format:%ct -- "{}")'
Nhưng có nhiều câu trả lời phức tạp hơn (bao gồm cả git hook) được liên kết từ một nhận xét đến câu hỏi ban đầu bởi cregox.
--date=@foo
Với các công cụ 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)
Trong CentOS 7, bạn có /usr/share/doc/rsync-*/support/git-set-file-times
và trong Debian (và các dẫn xuất) cùng một tập lệnh /usr/share/doc/rsync/scripts/git-set-file-times.gz
, bản gốc là của Eric Wong và ở đây https://yhbt.net/git-set-file-times .
Nó hoạt động nhanh hơn các ví dụ khác được đề cập ở đây và bạn có thể thấy tiện lợi hơn khi có nó trên bản phân phối Linux của mình.
Đây là của tôi.
Nhanh hơn một chút so với một số tệp khác, vì tôi không gọi 'lấy nhật ký' cho mỗi tệp được tìm thấy; thay vào đó, gọi 'git log' một lần và chuyển đầu ra đó thành các lệnh cảm ứng.
Sẽ có trường hợp có quá nhiều tệp được liệt kê trong 1 cam kết để vừa với một bộ đệm lệnh shell duy nhất; chạy "getconf ARG_MAX" để xem độ dài tối đa của một lệnh tính bằng byte - trên bản cài đặt debian của tôi, nó là 2MB, quá nhiều.
# 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 -
mô tả theo dòng:
Về tốc độ, 5 giây 1700 cam kết cho 6500 tệp trong 700 thư mục.