গিটের জন্য ব্যবহার-প্রতিশ্রুতি বারের সমতুল্য কী?


97

সিঙ্কে থাকতে আমার আমার স্থানীয় এবং সার্ভারে ফাইলের টাইমস্ট্যাম্পগুলি দরকার। কনফিগারেশনে ব্যবহার-কমিট-টাইমস = সত্য সেট করে এটি সাবভার্সনের মাধ্যমে সম্পন্ন হয় যাতে প্রতিটি ফাইলের সর্বশেষ সংশোধিত প্রতিশ্রুতি হয়।

প্রতিবার আমার সংগ্রহস্থলটির ক্লোন করার সময় আমি চাই যে ফাইলগুলির টাইমস্ট্যাম্পগুলি রিমোট রিপোজিটরিতে সর্বশেষ পরিবর্তন করা হয়েছিল, যখন আমি রেপো ক্লোন করেছিলাম তা নয় reflect

গিট দিয়ে এটি করার কোনও উপায় আছে?


আমার স্থাপনার প্রক্রিয়াটির অংশ হিসাবে, আমি একটি সিডিএনতে সম্পদ (চিত্র, জাভাস্ক্রিপ্ট ফাইল এবং সিএসএস ফাইল) আপলোড করি। প্রতিটি ফাইলের নাম সর্বশেষ পরিবর্তিত টাইমস্ট্যাম্পের সাথে যুক্ত করা হয়। এটি গুরুত্বপূর্ণ যে প্রতিবার আমি নিযুক্ত করি তখন আমার সমস্ত সম্পদ শেষ হয় না। (ব্যবহার-প্রতিশ্রুতি বারের আরেকটি পার্শ্ব প্রতিক্রিয়া হ'ল আমি এই প্রক্রিয়াটি আমার স্থানীয়টিতে করতে পারি এবং আমার সার্ভারটি একই ফাইলগুলিকে উল্লেখ করবে তা জানি তবে এটি ততটা গুরুত্বপূর্ণ নয়)) যদি গিট ক্লোন না করে, আমি একটি করতাম গিট ফেচ এর পরে গিট রিসেট করা হবে - আমার রিমোট রেপো থেকে শুরু করে, এটি একটি একক সার্ভারের জন্য কাজ করবে তবে একাধিক সার্ভারের জন্য নয় যেহেতু প্রত্যেকটির টাইমস্ট্যাম্পগুলি পৃথক হবে।
বেন ডব্লু

@ বেনডাব্লু: git annexইমেজগুলি ট্র্যাক রাখতে দরকারী হতে পারে
জেএফএস

আইডি চেক করে আপনি কী পরিবর্তন করেছেন তা যাচাই করতে পারেন। আপনি ফাইল সিস্টেমে টাইমস্ট্যাম্পগুলি ভিসিএস টাইমস্ট্যাম্পগুলির একই জিনিস বোঝানোর চেষ্টা করছেন। তারা একই জিনিস বোঝায় না।
জেথিল

উত্তর:


25

আমি নিশ্চিত না যে এটি ডিভিসিএসের জন্য উপযুক্ত হবে ("বিতরণ করা" ভিসিএসের মতো)

ইতিমধ্যে 2007 সালে বিশাল আলোচনা হয়েছিল (এই থ্রেডটি দেখুন)

এবং লিনাসের কিছু উত্তর ধারণা সম্পর্কে খুব আগ্রহী ছিল না। এখানে একটি নমুনা দেওয়া হল:

আমি দুঃখিত. যদি আপনি না দেখেন যে এমন কীভাবে কোনও ডেটস্ট্যাম্প সেট করা কীভাবে ভুল যা আপনার উত্স গাছটিকে একটি "মেক" বানান যা সহজেই তৈরি করে দেয়, আপনি কী "ভুল" এর চূড়ান্ত কথা বলছেন তা আমি জানি না।
এটা ভুল.
এটা মূঢ়.
এবং এটি বাস্তবায়ন সম্পূর্ণরূপে অসফল F


(দ্রষ্টব্য: ছোট উন্নতি: একটি চেকআউটের পরে, আপ টু ডেট ফাইলগুলির টাইমস্ট্যাম্পগুলি আর সংশোধিত হবে না (গিট ২.২.২+, জানুয়ারী ২০১৫): "গিট চেকআউট - শাখাগুলি স্যুইচ করার সময় আমি কীভাবে টাইমস্ট্যাম্পগুলি বজায় রাখতে পারি?" )


দীর্ঘ উত্তর ছিল:

আমি মনে করি পরিবর্তে একাধিক সংগ্রহস্থল ব্যবহার করে আপনি অনেক বেশি ভাল, যদি এটি সাধারণ কিছু হয়।

টাইমস্ট্যাম্পগুলির সাথে জবাবদিহি করা সাধারণভাবে চলবে না। এটি আপনাকে কেবল গ্যারান্টি দিয়ে চলেছে যে "মেক" সত্যই খারাপ উপায়ে বিভ্রান্ত হয়ে পড়েছে এবং খুব বেশি পরিমাণে পুনরায় সংশ্লেষের পরিবর্তে পর্যাপ্ত পরিমাণে পুনরায় কম্পাইল করে না ।

গিট আপনার "অন্যান্য শাখাটি পরীক্ষা করে দেখুন" জিনিসটি খুব সহজেই, বিভিন্ন উপায়ে করা সম্ভব করে তোলে।

আপনি কিছু তুচ্ছ স্ক্রিপ্ট তৈরি করতে পারেন যা নিম্নলিখিত যে কোনও একটি (তুচ্ছ থেকে আরও বহিরাগত পর্যন্ত):

  • শুধু একটি নতুন রেপো তৈরি করুন:
    git clone old new
    cd new
    git checkout origin/<branch>

এবং আপনি সেখানে আছেন। পুরানো টাইমস্ট্যাম্পগুলি আপনার পুরানো রেপোতে ঠিক আছে, এবং আপনি পুরানোটিকে একেবারে ক্ষতিগ্রস্থ না করে নতুনটিতে কাজ করতে (এবং সংকলন) করতে পারেন।

মূলত এই তাত্ক্ষণিক করে তুলতে "গিট ক্লোন" থেকে "-n -l -s" পতাকা ব্যবহার করুন। প্রচুর ফাইলের জন্য (যেমন কার্নেলের মতো বড় রেপো), এটি কেবল শাখাগুলি স্যুইচ করার মতো দ্রুত হবে না, তবে কার্যক্ষম গাছের দ্বিতীয় কপিটি শক্তিশালী হতে পারে।

  • আপনি যদি চান তবে তার পরিবর্তে কেবল একটি টার-বল দিয়েই করুন
    git archive --format=tar --prefix=new-tree/ <branchname> |
            (cd .. ; tar xvf -)

যা সত্যিই বেশ দ্রুত, যদি আপনি কেবল একটি স্ন্যাপশট চান।

  • " git show" অভ্যাস করুন এবং স্বতন্ত্র ফাইলগুলি দেখুন।
    এটি আসলে সময়ে সত্যিই দরকারী। তুমি শুধু কর
    git show otherbranch:filename

একটি এক্সটার্ম উইন্ডোতে, এবং অন্য উইন্ডোতে আপনার বর্তমান শাখায় একই ফাইলটি দেখুন। বিশেষত, স্ক্রিপ্টযোগ্য সম্পাদকদের (অর্থাত্ জিএনইউ ইম্যাকস) সাথে এটি করা তুচ্ছ হওয়া উচিত, যেখানে এটি ব্যবহার করে সম্পাদকের অভ্যন্তরে অন্য শাখাগুলির জন্য পুরো "ডায়ার্ড মোড" থাকা সম্ভব। আমি জানি সবার জন্য, ইমাস গিট মোড ইতিমধ্যে এর মতো কিছু সরবরাহ করে (আমি কোনও ইম্যাক ব্যবহারকারী নই)

  • এবং সেই "ভার্চুয়াল ডিরেক্টরি" জিনিসটির চূড়ান্ত উদাহরণে, ফুস জন্য একটি গিট প্লাগইনে অন্ততপক্ষে কেউ কাজ করছিল, অর্থাৎ আপনি আক্ষরিকভাবে আপনার সমস্ত শাখা দেখিয়ে ভার্চুয়াল ডিরেক্টরি থাকতে পারেন ।

এবং আমি নিশ্চিত যে উপরের যে কোনওটি ফাইল টাইমস্ট্যাম্পগুলির সাথে গেম খেলার চেয়ে ভাল বিকল্প।

লিনাস


5
রাজি। আপনার কোনও ডিভিসিএস বিতরণ সিস্টেমের সাথে বিভ্রান্ত করা উচিত নয়। gitসোর্স কোড ম্যানিপুলেট করার জন্য এটি একটি ডিভিসিএস, যা আপনার চূড়ান্ত পণ্যটিতে অন্তর্নির্মিত হবে । আপনি যদি কোনও বিতরণ ব্যবস্থা চান তবে আপনি কোথায় পাবেন তা জানেন rsync
র্যান্ডাল শোয়ার্জ

14
হুঁ, আমি তার যুক্তি বিশ্বাস করতে পারি যে এটি অনিবার্য। তা ভুল হোক বা বোকা হোক তা অন্য বিষয়। আমি টাইমস্ট্যাম্প ব্যবহার করে আমার ফাইলগুলিকে সংস্করণ করি এবং সেগুলি একটি সিডিএন-এ আপলোড করি, যার কারণে ফাইলটি বাস্তবে পরিবর্তিত হওয়ার সময় টাইমস্ট্যাম্পগুলি প্রতিফলিত করা গুরুত্বপূর্ণ, যখন এটি রেপো থেকে শেষ বার টেনে নামানো হয়নি।
বেন ডব্লিউ

4
@ বেন ডাব্লু: "লিনাসের উত্তর" এখানে আপনার বিশেষ পরিস্থিতিতে এটি ভুল তা বলার জন্য নয় । এটি কেবলমাত্র একটি অনুস্মারক হিসাবে রয়েছে যে কোনও ডিভিসিএস সেই ধরণের বৈশিষ্ট্যের জন্য উপযুক্ত নয় (টাইমস্ট্যাম্প সংরক্ষণ)।
ভোনসি

15
@ ভনসি: যেহেতু অন্যান্য আধুনিক ডিভিসিএস যেমন বাজার এবং মার্কুরিয়াল হ্যান্ডেল টাইমস্ট্যাম্পগুলি ঠিক আছে, তাই আমি বরং বলব যে " গিটটি এই ধরণের বৈশিষ্ট্যের জন্য উপযুক্ত নয়"। যদি "একটি" DVCS উচিত যা ফিচার বিতর্ক সাপেক্ষ আছে (এবং আমি দৃঢ়ভাবে মনে করি তারা না)।
MestreLion

10
এটি প্রশ্নের উত্তর নয়, সংস্করণ নিয়ন্ত্রণ ব্যবস্থায় এটি করার যোগ্যতা সম্পর্কে দার্শনিক আলোচনা। যদি ব্যক্তিটি এটি পছন্দ করতে পারে তবে তারা জিজ্ঞাসা করত, "গিট ফাইলগুলির পরিবর্তিত সময়ের জন্য কমিট সময়টি ব্যবহার না করার কারণ কী?"
থোমাসফুচস 12 '24

85

যদি আপনি যাচাই করে নেওয়ার সময় সত্যই টাইমস্ট্যাম্পগুলির জন্য কমিট সময় ব্যবহার করতে চান তবে এই স্ক্রিপ্টটি ব্যবহার করে চেষ্টা করুন এবং এটি (এক্সিকিউটেবল হিসাবে) $ GIT_DIR / .git / hooks / পোস্ট-চেকআউট ফাইলটিতে রাখুন:

#!/bin/sh -e

OS=${OS:-`uname`}
old_rev="$1"
new_rev="$2"

get_file_rev() {
    git rev-list -n 1 "$new_rev" "$1"
}

if   [ "$OS" = 'Linux' ]
then
    update_file_timestamp() {
        file_time=`git show --pretty=format:%ai --abbrev-commit "$(get_file_rev "$1")" | head -n 1`
        touch -d "$file_time" "$1"
    }
elif [ "$OS" = 'FreeBSD' ]
then
    update_file_timestamp() {
        file_time=`date -r "$(git show --pretty=format:%at --abbrev-commit "$(get_file_rev "$1")" | head -n 1)" '+%Y%m%d%H%M.%S'`
        touch -h -t "$file_time" "$1"
    }
else
    echo "timestamp changing not implemented" >&2
    exit 1
fi

IFS=`printf '\t\n\t'`

git ls-files | while read -r file
do
    update_file_timestamp "$file"
done

তবে নোট করুন যে এই স্ক্রিপ্টটি বড় সংগ্রহস্থলগুলি পরীক্ষা করার জন্য যথেষ্ট পরিমাণে বিলম্ব ঘটাবে (যেখানে বৃহত্তর অর্থ ফাইলের বড় পরিমাণ, বড় ফাইলের আকার নয়)।


55
প্রকৃত উত্তর, বদলে শুধু বলার অপেক্ষা রাখে +1 "করতে করবে না যে,"
DanC

4
| head -n 1যেমন একটি নতুন প্রক্রিয়া spawns, এড়িয়ে চলা উচিত -n 1জন্য git rev-listএবং git logপরিবর্তে ব্যবহার করা যাবে।
ইরিগন

4
এটা দিয়ে লাইন পড়তে না ভালো `...`এবং for; আপনি কেন "জন্য" দিয়ে লাইন পড়েন না তা দেখুন । আমি যেতে হবে git ls-files -zএবং while IFS= read -r -d ''
মুশিফিল

4
উইন্ডোজ সংস্করণ কি সম্ভব?
এহরিক

4
git show --pretty=format:%ai --abbrev-commit "$(get_file_rev "$1")" | head -n 1আপনি না করার পরিবর্তে git show --pretty=format:%ai -s "$(get_file_rev "$1")"এটি showকমান্ড দ্বারা প্রচুর পরিমাণে কম ডেটা উত্পন্ন করে এবং ওভারহেড হ্রাস করা উচিত।
স্কট চেম্বারলাইন

81

আপডেট : আমার সমাধানটি এখন ডেবিয়ান / উবুন্টু / মিন্ট, ফেডোরা, জেন্টু এবং সম্ভবত অন্যান্য ডিস্ট্রোজে প্যাক করা হয়েছে:

https://github.com/MestreLion/git-tools#install

sudo apt install git-restore-mtime  # Debian/Ubuntu/Mint
yum install git-tools               # Fedora/ RHEL / CentOS
emerge dev-vcs/git-tools            # Gentoo

আইএমএইচও, টাইমস্ট্যাম্পগুলি সংরক্ষণ না করে (এবং অন্যান্য মেটাডেটা যেমন অনুমতি এবং মালিকানার মতো) একটি বড় সীমাবদ্ধতা git

লিনাসের টাইমস্ট্যাম্পগুলির যুক্তিটি কেবল "বিভ্রান্ত make" হওয়ার কারণে ক্ষতিকারক লম্পট :

  • make clean যে কোনও সমস্যা সমাধানের জন্য যথেষ্ট।

  • কেবলমাত্র সেই প্রকল্পগুলিতে প্রয়োগ হয় make বেশিরভাগ সি / সি ++ ব্যবহার করে। পাইথন, পার্ল বা সাধারণভাবে ডকুমেন্টেশনের মতো স্ক্রিপ্টগুলির জন্য এটি সম্পূর্ণরূপে মোড।

  • আপনি টাইমস্ট্যাম্পগুলি প্রয়োগ করলে কেবল ক্ষতি হয় । কোন ক্ষতি নেই হবে সংরক্ষণকারী তাদের রেপো হবে। তাদের প্রয়োগ করা হচ্ছে একটি সহজ হতে পারে --with-timestampsজন্য বিকল্প git checkoutএবং বন্ধুদের ( clone, pullইত্যাদি), এ ব্যবহারকারীর বিবেচনার ভিত্তিতে।

উভয় বাজার এবং মার্কুরিয়াল স্টোরের মেটাডেটা। ব্যবহারকারীরা এগুলি প্রয়োগ করতে পারেন বা যখন চেক আউট করার সময় নয়। কিন্তু Git মধ্যে, যেহেতু মূল টাইমস্ট্যাম্প এমনকি নয় প্রাপ্তিসাধ্য রেপো, সেখানে এই ধরনের কোনো বিকল্প নেই।

সুতরাং, খুব অল্প লাভের জন্য (সমস্ত কিছুর পুনরায় সংকলন না করার জন্য) যা প্রকল্পের একটি উপসেটের সাথে সুনির্দিষ্ট, gitযেমন একটি সাধারণ ডিভিসিএস পঙ্গু হয়েছিল , ফাইলগুলি সম্পর্কে কিছু তথ্য হারিয়ে গেছে , এবং লিনাস যেমন বলেছে, এটি করা অসম্ভব এখন.দু: খিত

বলেছিল, আমি কি 2 পন্থা প্রস্তাব করতে পারি?

1 - http://repo.or.cz/w/metastore.git , ডেভিড হার্ডম্যানের দ্বারা। git প্রথমে যা করা উচিত ছিল তা করার চেষ্টা করে : কমিট করার সময় (প্রাক কমিট হুকের মাধ্যমে) রেপোতে মেটাডেটা (কেবলমাত্র টাইমস্ট্যাম্পগুলি নয়) সঞ্চয় করে এবং টান দেওয়ার সময় সেগুলি পুনরায় প্রয়োগ করে (হুকের মাধ্যমেও)।

2 - মুক্তির টারবলগুলি তৈরি করার জন্য আমি আগে ব্যবহৃত স্ক্রিপ্টের আমার নম্র সংস্করণ। হিসাবে অন্যান্য উত্তর উল্লেখ করা হয়েছে, পন্থা একটু ভিন্ন : প্রতিটি ফাইল জন্য আবেদন করতে টাইমস্ট্যাম্প এর সাম্প্রতিকতম কমিট যেখানে ফাইল সংশোধন করা হয়।

নীচে পাইথন ২.7-তে ধারণার প্রুফ অফ কনসেপ্ট হিসাবে স্ক্রিপ্টটির সত্যিই খালি-হাড়ের সংস্করণ দেওয়া আছে। প্রকৃত ব্যবহারের জন্য আমি উপরের পুরো সংস্করণটির দৃ strongly়তার সাথে সুপারিশ করছি:

#!/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

পারফরমেন্স এমনকি দৈত্য প্রকল্পগুলির জন্য, বেশ চিত্তাকর্ষক wine, gitবা এমনকি Linux kernel:

bash
# 0.27 seconds
# 5,750 log lines processed
# 62 commits evaluated
# 1,155 updated files

git
# 3.71 seconds
# 96,702 log lines processed
# 24,217 commits evaluated
# 2,495 updated files

wine
# 13.53 seconds
# 443,979 log lines processed
# 91,703 commits evaluated
# 6,005 updated files

linux kernel
# 59.11 seconds
# 1,484,567 log lines processed
# 313,164 commits evaluated
# 40,902 updated files

4
কিন্তু git না দোকান টাইমস্ট্যাম্প, ইত্যাদি এটা ঠিক ডিফল্টরূপে টাইমস্ট্যাম্প সেট করেনি। কেবল আউটপুটটি দেখুনgit ls-files --debug
রস স্মিথ II

9
@ রোসস্মিথআইআই: git ls-filesওয়ার্কিং ডিরেক্টরি এবং সূচক পরিচালনা করে, সুতরাং এর অর্থ এই নয় যে এটি আসলে তথ্যটি রেপোতে সঞ্চয় করে। যদি এটি সঞ্চয় করে থাকে তবে এমটাইম পুনরুদ্ধার (এবং প্রয়োগ) খুব তুচ্ছ হবে।
MestreLion

14
"লিনাসের টাইমস্ট্যাম্পগুলির যুক্তিটি ক্ষতিকারক কারণ এটি" বিভ্রান্ত করে তোলে "খোঁড়া" - এটি 100% সম্মত, কোনও ডিসিভিএসকে এতে থাকা কোড সম্পর্কে জানা বা যত্ন নেওয়া উচিত নয়! আবার এটি সাধারণ ব্যবহারের ক্ষেত্রে নির্দিষ্ট ব্যবহারের ক্ষেত্রে রচিত সরঞ্জামগুলি পুনর্বিবেচনার চেষ্টা করার ক্ষতিগুলি দেখায়। মার্চুরিয়াল হ'ল এবং সর্বদা একটি সেরা পছন্দ হবে কারণ এটি ডিজাইন করা হয়েছিল, বিবর্তিত হয়নি।
ইয়ান কেম্প

6
@ ডেভেক আপনি স্বাগত, খুশি এটি কার্যকর ছিল। Github.com/MestreLion/git-tools এর সম্পূর্ণ সংস্করণ ইতিমধ্যে উইন্ডোজ, পাইথন 3, নন-এএসসিআইআই পথের নামগুলি ইত্যাদি পরিচালনা করে The উপরের স্ক্রিপ্টটি ধারণার একটি কার্যকরী প্রমাণ, উত্পাদন ব্যবহারের জন্য এড়িয়ে চলুন।
MestreLion

4
আপনার যুক্তি বৈধ। আমি আশা করি যে কোনও ক্লাউটযুক্ত কেউ আপনার প্রস্তাবিত - সময়-স্ট্যাম্পস বিকল্পের জন্য গিটের জন্য বর্ধনের অনুরোধ করবে।
weberjn

12

আমি গিলের উত্তর নিয়েছি এবং পোস্ট-কমিট হুক স্ক্রিপ্ট ব্যবহার না করে এটি আমার কাস্টম ডিপ্লোয়মেন্ট স্ক্রিপ্টে ব্যবহার করেছি।

আপডেট : আমি | head -n@ ইরেগনের পরামর্শ অনুসরণ করে একটি অপসারণ করেছি এবং সেগুলিতে ফাঁকা ফাঁকা ফাইলগুলির জন্য সমর্থন যোগ করেছি:

# Adapted to use HEAD rather than the new commit ref
get_file_rev() {
    git rev-list -n 1 HEAD "$1"
}

# Same as Giel's answer above
update_file_timestamp() {
    file_time=`git show --pretty=format:%ai --abbrev-commit "$(get_file_rev "$1")" | head -n 1`
    sudo touch -d "$file_time" "$1"
}

# Loop through and fix timestamps on all files in our CDN directory
old_ifs=$IFS
IFS=$'\n' # Support files with spaces in them
for file in $(git ls-files | grep "$cdn_dir")
do
    update_file_timestamp "${file}"
done
IFS=$old_ifs

ধন্যবাদ ড্যানিয়েল, এটি জানার জন্য সহায়ক
অ্যালেক্স ডিন

--abbrev-commitমধ্যে প্রযোজন নেই git showকমান্ড কারণে --pretty=format:%ai(কমিট হ্যাশ আউটপুট অংশ নয়) ব্যবহার করা হচ্ছে এবং | head -n 1ব্যবহার দিয়ে প্রতিস্থাপিত করা যেতে পারে -sপতাকাgit show
প্রাণবন্ততা Ruusamäe

4
@ ড্যানিয়েলএস। স্টার্লিং: %aiলেখকের তারিখ, আইএসও 8601 ফর্ম্যাটের মতো , কঠোর আইসো 8601 ব্যবহারের জন্য %aI: git-scm.com/docs/git-show
এলান রুসামে

4

আমরা আরও একটি সমাধান উদ্ভাবন করতে বাধ্য হয়েছিলাম, কারণ আমাদের বিশেষভাবে পরিবর্তনের সময় প্রয়োজন ছিল এবং সময়গুলি প্রতিশ্রুতিবদ্ধ না, এবং সমাধানটিও বহনযোগ্য হতে পারে (যেমন উইন্ডোজগুলির গিট ইনস্টলশনে অজগর পাওয়া সত্যিই একটি সহজ কাজ নয়) এবং দ্রুত। এটি ডেভিড হার্ডম্যানের সমাধানের সাথে সাদৃশ্যপূর্ণ, যা আমি নথির অভাবের কারণে ব্যবহার না করার সিদ্ধান্ত নিয়েছিলাম (সংগ্রহশালা থেকে আমি তার কোডটি ঠিক কী করে তা ধারণা পেতে সক্ষম হইনি)।

এই সমাধানটি একটি ফাইলের মধ্যে মাইটাইমগুলি সঞ্চয় করে it গিট সংগ্রহস্থলের সময়গুলিতে, সেগুলি অনুযায়ী কমিটগুলিতে আপডেট করে (নির্বাচিতভাবে স্টেজযুক্ত ফাইলগুলির মাইটাইমস) এবং তাদের চেকআউটে প্রয়োগ করে। এটি গিগের সাইগউইন / মিংডউ সংস্করণগুলির সাথেও কাজ করে (তবে আপনাকে স্ট্যান্ডার্ড সাইগউইন থেকে গিটের ফোল্ডারে কিছু ফাইল অনুলিপি করতে হবে)

সমাধানটিতে 3 টি ফাইল থাকে:

  1. এমটাইমস্টোর - মূল স্ক্রিপ্ট 3 টি বিকল্প সরবরাহ করে - একটি (সমস্ত সংরক্ষণ করুন - ইতিমধ্যে বিদ্যমান রেপোতে শুরু করার জন্য (গিট-বুদ্ধিযুক্ত ফাইলগুলির সাথে কাজ করে)), -এস (পর্যায়যুক্ত পরিবর্তনগুলি সংরক্ষণ করতে), এবং -r সেগুলি পুনরুদ্ধার করতে। এটি আসলে ২ টি সংস্করণে আসে - একটি ব্যাশ ওয়ান (পোর্টেবল, দুর্দান্ত, সহজেই পড়তে / পরিবর্তন করতে পারে), এবং সি সংস্করণ (নোংরা একটি তবে দ্রুত, কারণ মিংডাব্যাশ ব্যাশ মারাত্মকভাবে ধীর হয় যা বড় প্রকল্পগুলিতে ব্যাশ সমাধানটি ব্যবহার করা অসম্ভব করে তোলে)
  2. প্রাক কমিট হুক
  3. পোস্ট-চেকআউট হুক

পূর্ব-প্রতিশ্রুতিবদ্ধ:

#!/bin/bash
mtimestore -s
git add .mtimes

পোস্ট-চেকআউট

#!/bin/bash
mtimestore -r

এমটাইমস্টোর - ব্যাশ:

#!/bin/bash

function usage 
{
  echo "Usage: mtimestore (-a|-s|-r)"
  echo "Option  Meaning"
  echo " -a save-all - saves state of all files in a git repository"
  echo " -s save - saves mtime of all staged files of git repository"
  echo " -r restore - touches all files saved in .mtimes file"
  exit 1
}

function echodate 
{
  echo "$(stat -c %Y "$1")|$1" >> .mtimes
}

IFS=$'\n'

while getopts ":sar" optname
do
  case "$optname" in
    "s")
      echo "saving changes of staged files to file .mtimes"
      if [ -f .mtimes ]
      then
        mv .mtimes .mtimes_tmp
        pattern=".mtimes"
        for str in $(git diff --name-only --staged)
        do
          pattern="$pattern\|$str"
        done
        cat .mtimes_tmp | grep -vh "|\($pattern\)\b" >> .mtimes
      else
        echo "warning: file .mtimes does not exist - creating new"
      fi

      for str in $(git diff --name-only --staged)
      do
        echodate "$str" 
      done
      rm .mtimes_tmp 2> /dev/null
      ;;
    "a")
      echo "saving mtimes of all files to file .mtimes"
      rm .mtimes 2> /dev/null
      for str in $(git ls-files)
      do
        echodate "$str"
      done
      ;;
    "r")
      echo "restorim dates from .mtimes"
      if [ -f .mtimes ]
      then
        cat .mtimes | while read line
        do
          timestamp=$(date -d "1970-01-01 ${line%|*} sec GMT" +%Y%m%d%H%M.%S)
          touch -t $timestamp "${line##*|}"
        done
      else
        echo "warning: .mtimes not found"
      fi
      ;;
    ":")
      usage
      ;;
    *)
      usage
      ;;
esac

এমটাইমস্টোর - সি ++

#include <time.h>
#include <utime.h>
#include <sys/stat.h>
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <ctime>
#include <map>


void changedate(int time, const char* filename)
{
  try
  {
    struct utimbuf new_times;
    struct stat foo;
    stat(filename, &foo);

    new_times.actime = foo.st_atime;
    new_times.modtime = time;
    utime(filename, &new_times);
  }
  catch(...)
  {}
}

bool parsenum(int& num, char*& ptr)
{
  num = 0;
  if(!isdigit(*ptr))
    return false;
  while(isdigit(*ptr))
  {
    num = num*10 + (int)(*ptr) - 48;
    ptr++;
  }
  return true;
}

//splits line into numeral and text part - return numeral into time and set ptr to the position where filename starts
bool parseline(const char* line, int& time, char*& ptr)
{
  if(*line == '\n' || *line == '\r')
    return false;
  time = 0;
  ptr = (char*)line;
  if( parsenum(time, ptr))
  { 
    ptr++;
    return true;
  }
  else
    return false;
}

//replace \r and \n (otherwise is interpretted as part of filename)
void trim(char* string)
{
  char* ptr = string;
  while(*ptr != '\0')
  {
    if(*ptr == '\n' || *ptr == '\r')
      *ptr = '\0';
    ptr++;
  }
}


void help()
{
  std::cout << "version: 1.4" << std::endl;
  std::cout << "usage: mtimestore <switch>" << std::endl;
  std::cout << "options:" << std::endl;
  std::cout << "  -a  saves mtimes of all git-versed files into .mtimes file (meant to be done on intialization of mtime fixes)" << std::endl;
  std::cout << "  -s  saves mtimes of modified staged files into .mtimes file(meant to be put into pre-commit hook)" << std::endl;
  std::cout << "  -r  restores mtimes from .mtimes file (that is meant to be stored in repository server-side and to be called in post-checkout hook)" << std::endl;
  std::cout << "  -h  show this help" << std::endl;
}

void load_file(const char* file, std::map<std::string,int>& mapa)
{

  std::string line;
  std::ifstream myfile (file, std::ifstream::in);

  if(myfile.is_open())
  {
      while ( myfile.good() )
      {
        getline (myfile,line);
        int time;
        char* ptr;
        if( parseline(line.c_str(), time, ptr))
        {
          if(std::string(ptr) != std::string(".mtimes"))
            mapa[std::string(ptr)] = time;
        }
      }
    myfile.close();
  }

}

void update(std::map<std::string, int>& mapa, bool all)
{
  char path[2048];
  FILE *fp;
  if(all)
    fp = popen("git ls-files", "r");
  else
    fp = popen("git diff --name-only --staged", "r");

  while(fgets(path, 2048, fp) != NULL)
  {
    trim(path);
    struct stat foo;
    int err = stat(path, &foo);
    if(std::string(path) != std::string(".mtimes"))
      mapa[std::string(path)]=foo.st_mtime;
  }
}

void write(const char * file, std::map<std::string, int>& mapa)
{
  std::ofstream outputfile;
  outputfile.open(".mtimes", std::ios::out);
  for(std::map<std::string, int>::iterator itr = mapa.begin(); itr != mapa.end(); ++itr)
  {
    if(*(itr->first.c_str()) != '\0')
    {
      outputfile << itr->second << "|" << itr->first << std::endl;   
    }
  }
  outputfile.close();
}

int main(int argc, char *argv[])
{
  if(argc >= 2 && argv[1][0] == '-')
  {
    switch(argv[1][1])
    {
      case 'r':
        {
          std::cout << "restoring modification dates" << std::endl;
          std::string line;
          std::ifstream myfile (".mtimes");
          if (myfile.is_open())
          {
            while ( myfile.good() )
            {
              getline (myfile,line);
              int time, time2;
              char* ptr;
              parseline(line.c_str(), time, ptr);
              changedate(time, ptr);
            }
            myfile.close();
          }
        }
        break;
      case 'a':
      case 's':
        {
          std::cout << "saving modification times" << std::endl;

          std::map<std::string, int> mapa;
          load_file(".mtimes", mapa);
          update(mapa, argv[1][1] == 'a');
          write(".mtimes", mapa);
        }
        break;
      default:
        help();
        return 0;
    }
  } else
  {
    help();
    return 0;
  }

  return 0;
}
  • নোট করুন যে হুকগুলি তাদের স্থান নির্ধারণের জন্য স্বয়ংক্রিয় করতে টেমপ্লেট-ডিরেক্টরিতে স্থাপন করা যেতে পারে

আরও তথ্য এখানে পাওয়া যাবে https://github.com/kareltucek/git-mtime- এক্সটেনশন কিছু পুরানো তথ্য http://www.ktweb.cz/blog/index.php?page=page&id=116 এ রয়েছে

// সম্পাদনা - সি ++ সংস্করণ আপডেট হয়েছে:

  • এখন সি ++ সংস্করণ বর্ণানুক্রমিক ক্রম -> কম সংহত বিবাদগুলি বজায় রাখে।
  • কুৎসিত সিস্টেম () কলগুলি থেকে মুক্তি পেয়েছে।
  • পোস্ট-চেকআউট হুক থেকে $ গিট আপডেট-ইনডেক্স - রিফ্রেশ le মুছে ফেলা হয়েছে। কচ্ছপের গিটের অধীনে ফিরে যাওয়ার কিছু সমস্যা সৃষ্টি করে এবং যাইহোক এটি খুব গুরুত্বপূর্ণ বলে মনে হয় না।
  • আমাদের উইন্ডোজ প্যাকেজটি http://ktweb.cz/blog/download/git-mtimestore-1.4.rr এ ডাউনলোড করা যাবে

// সম্পাদনা আপ টু ডেট সংস্করণ জন্য গিথুব দেখুন


4
লক্ষ্য করুন, একটি চেকআউট পর আপ-টু-ডেট ফাইল আর পরিবর্তিত হয় এর (গীত 2.2.2+ জানুয়ারি 2015) টাইমস্ট্যাম্প যে: stackoverflow.com/a/28256177/6309
VonC

3

নিম্নলিখিত লিপিটি -n 1এবং HEADপরামর্শগুলি অন্তর্ভুক্ত করে , বেশিরভাগ নন-লিনাক্স পরিবেশে (সাইগউইনের মতো) কাজ করে এবং সত্যতার পরে একটি চেকআউট চালানো যেতে পারে:

#!/bin/bash -e

OS=${OS:-`uname`}

get_file_rev() {
    git rev-list -n 1 HEAD "$1"
}    

if [ "$OS" = 'FreeBSD' ]
then
    update_file_timestamp() {
        file_time=`date -r "$(git show --pretty=format:%at --abbrev-commit "$(get_file_rev "$1")" | head -n 1)" '+%Y%m%d%H%M.%S'`
        touch -h -t "$file_time" "$1"
    }    
else    
    update_file_timestamp() {
        file_time=`git show --pretty=format:%ai --abbrev-commit "$(get_file_rev "$1")" | head -n 1`
        touch -d "$file_time" "$1"
    }    
fi    

OLD_IFS=$IFS
IFS=$'\n'

for file in `git ls-files`
do
    update_file_timestamp "$file"
done

IFS=$OLD_IFS

git update-index --refresh

ধরে নিলাম আপনি উপরের স্ক্রিপ্টটির নাম দিয়েছেন /path/to/templates/hooks/post-checkoutএবং / অথবা /path/to/templates/hooks/post-update, আপনি এটির মাধ্যমে একটি বিদ্যমান সংগ্রহস্থলে চালনা করতে পারেন:

git clone git://path/to/repository.git
cd repository
/path/to/templates/hooks/post-checkout

এটির জন্য আরও একটি শেষ লাইনের দরকার: গিট আপডেট-ইনডেক্স - রিফ্রেশ // জিইউআই সরঞ্জামগুলি সূচকের উপর নির্ভর করতে পারে এবং এই জাতীয় ক্রিয়াকলাপের পরে সমস্ত ফাইলে "নোংরা" অবস্থা প্রদর্শন করে show যথা উইন্ডোজ কোড. google.com/p/tortoisegit/issues/detail?id=861
'দ্য

4
এবং স্ক্রিপ্ট জন্য ধন্যবাদ। আমি চাই যে এই ধরনের স্ক্রিপ্টটি গিট স্ট্যান্ডার্ড ইনস্টলারের অংশ ছিল। আমার ব্যক্তিগতভাবে এটি প্রয়োজন তা নয়, তবে দলের সদস্যরা ভিসিএস গ্রহণের সময় "স্টপ" ব্যানার হিসাবে টাইমস্ট্যাম্প রিফ্রেশ মনে করছেন।
আরিচ 'দ্য

3

এই সমাধানটি বেশ দ্রুত চালানো উচিত। এটি লেখক সময়গুলিতে প্রতিশ্রুতিবদ্ধ সময় এবং সময়কে সেট করে। এটি কোনও মডিউল ব্যবহার করে না তাই যুক্তিযুক্ত পোর্টেবল হতে হবে be

#!/usr/bin/perl

# git-utimes: update file times to last commit on them
# Tom Christiansen <tchrist@perl.com>

use v5.10;      # for pipe open on a list
use strict;
use warnings;
use constant DEBUG => !!$ENV{DEBUG};

my @gitlog = ( 
    qw[git log --name-only], 
    qq[--format=format:"%s" %ct %at], 
    @ARGV,
);

open(GITLOG, "-|", @gitlog)             || die "$0: Cannot open pipe from `@gitlog`: $!\n";

our $Oops = 0;
our %Seen;
$/ = ""; 

while (<GITLOG>) {
    next if /^"Merge branch/;

    s/^"(.*)" //                        || die;
    my $msg = $1; 

    s/^(\d+) (\d+)\n//gm                || die;
    my @times = ($1, $2);               # last one, others are merges

    for my $file (split /\R/) {         # I'll kill you if you put vertical whitespace in our paths
        next if $Seen{$file}++;             
        next if !-f $file;              # no longer here

        printf "atime=%s mtime=%s %s -- %s\n", 
                (map { scalar localtime $_ } @times), 
                $file, $msg,
                                        if DEBUG;

        unless (utime @times, $file) {
            print STDERR "$0: Couldn't reset utimes on $file: $!\n";
            $Oops++;
        }   
    }   

}
exit $Oops;

2

এখানে ছোটখাট ফিক্স সহ উপরের শেল সমাধানগুলির একটি অনুকূলিত সংস্করণ:

#!/bin/sh

if [ "$(uname)" = 'Darwin' ] ||
   [ "$(uname)" = 'FreeBSD' ]; then
   gittouch() {
      touch -ch -t "$(date -r "$(git log -1 --format=%ct "$1")" '+%Y%m%d%H%M.%S')" "$1"
   }
else
   gittouch() {
      touch -ch -d "$(git log -1 --format=%ci "$1")" "$1"
   }
fi

git ls-files |
   while IFS= read -r file; do
      gittouch "$file"
   done

1

এখানে পিএইচপি সহ একটি পদ্ধতি রয়েছে:

<?php
$r = popen('git ls-files', 'r');
$n_file = 0;

while (true) {
   $s_gets = fgets($r);
   if (feof($r)) {
      break;
   }
   $s_trim = rtrim($s_gets);
   $m_file[$s_trim] = false;
   $n_file++;
}

$r = popen('git log -m -z --name-only --relative --format=%ct .', 'r');

while ($n_file > 0) {
   $s_get = fgets($r);
   $s_trim = rtrim($s_get);
   $a_name = explode("\x0", $s_trim);
   $s_unix = array_pop($a_name);
   foreach ($a_name as $s_name) {
      if (! array_key_exists($s_name, $m_file)) {
         continue;
      }
      if ($m_file[$s_name]) {
         continue;
      }
      touch($s_name, $n_unix);
      $m_file[$s_name] = true;
      $n_file--;
   }
   $n_unix = (int)($s_unix);
}

এটি এখানে উত্তরের অনুরূপ:

গিটের জন্য ব্যবহার-প্রতিশ্রুতি বারের সমতুল্য কী?

এটি সেই উত্তরের মতো একটি ফাইল তালিকা তৈরি করে তবে এটি git ls-files কেবল ওয়ার্কিং ডিরেক্টরিটি অনুসন্ধান করার পরিবর্তে তৈরি করে । এটি বাদ দেওয়ার সমস্যাটি সমাধান করে .gitএবং এটি তালাবিহীন ফাইলগুলির সমস্যাও সমাধান করে। এছাড়াও, এই উত্তরটি ব্যর্থ হয় যদি কোনও ফাইলের শেষ প্রতিশ্রুতিটি একটি মার্জ কমিট ছিল, যা আমি সমাধান করেছি git log -m। অন্যান্য উত্তরের মতো, একবার সমস্ত ফাইল পাওয়া গেলে বন্ধ হয়ে যাবে, সুতরাং এটি সমস্ত কমিটগুলি পড়তে হবে না। উদাহরণস্বরূপ:

https://github.com/git/git

এই পোস্টিং হিসাবে এটি কেবল 292 টি কমিট পড়তে হয়েছিল। এছাড়াও এটি প্রয়োজন অনুসারে ইতিহাস থেকে পুরানো ফাইলগুলি উপেক্ষা করে এবং এটি এমন কোনও ফাইলের স্পর্শ করবে না যা ইতিমধ্যে স্পর্শ করা হয়েছে। শেষ পর্যন্ত এটি অন্যান্য সমাধানের চেয়ে কিছুটা দ্রুত বলে মনে হচ্ছে। git/gitরেপো সহ ফলাফল :

PS C:\git> Measure-Command { git-touch.php }
TotalSeconds      : 3.4215134

0

আমি একটি উইন্ডোজ সংস্করণের জন্য কিছু অনুরোধ দেখেছি, তাই এটি এখানে। নিম্নলিখিত দুটি ফাইল তৈরি করুন:

সি: \ প্রোগ্রাম ফাইলগুলি \ গিট \ মিংডব্লিউ \৪ \ ভাগ \ গিটার-কোর \ টেম্পলেটগুলি \ হুক \ পোস্ট-চেকআউট

#!C:/Program\ Files/Git/usr/bin/sh.exe
exec powershell.exe -NoProfile -ExecutionPolicy Bypass -File "./$0.ps1"

সি: \ প্রোগ্রাম ফাইলগুলি it গিট \ মিংডব্লিউ \৪ \ ভাগ \ গিট-কোর \ টেম্পলেটগুলি \ হুকস \ পোস্ট-চেকআউট.পিএস 1

[string[]]$changes = &git whatchanged --pretty=%at
$mtime = [DateTime]::Now;
[string]$change = $null;
foreach($change in $changes)
{
    if($change.Length -eq 0) { continue; }
    if($change[0] -eq ":")
    {
        $parts = $change.Split("`t");
        $file = $parts[$parts.Length - 1];
        if([System.IO.File]::Exists($file))
        {
            [System.IO.File]::SetLastWriteTimeUtc($file, $mtime);
        }
    }
    else
    {
        #get timestamp
        $mtime = [DateTimeOffset]::FromUnixTimeSeconds([Int64]::Parse($change)).DateTime;
    }
}

এটি গিটটি কী বদলেছে তা ব্যবহার করে , সুতরাং এটি প্রতিটি ফাইলের জন্য গিট কল করার পরিবর্তে একটি পাসের সমস্ত ফাইলের মধ্য দিয়ে চলে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.