Когда я хочу деактивировать поэтапный файл, все мои руководства по Git показывают что-то вроде:
$ git add * $ git statusOn ветке master Изменения, которые необходимо зафиксировать: (используйте "git reset HEAD ..." для отмены постановки) переименовано: README.md -> README изменено: CONTRIBUTING.md
Этот совет говорит нам использовать git reset
для отключения поэтапного файла.
Но вместо этого в моем терминале я вижу:
git statusOn ветка master Изменения, которые необходимо зафиксировать: (используйте "git restore --staged ..." для отмены постановки) переименовано: cat.js -> catcat.js переименовано: толеранто.gogo -> толендо.txt Файлы без отслеживания: (используйте "git добавить ... "для включения в то, что будет зафиксировано) readme (копировать) .md толендо (копировать) .txt zing (копировать) .html
Мой терминал сообщает мне нужно использовать git restore --staged
, но в руководствах, а также на веб-сайте Git, мне предлагается использовать git reset HEAD
.
Я понятия не имею о новой команде restore
. Я попытался найти в Google разницу между git reset
и git restore
, но ничего не подходило к моему вопросу.
Можете вы помогите мне?
Большое спасибо!
Я представил git restore
(который все еще помечен как «экспериментальный») в статье «Как сбросить все файлы из рабочего каталога, но не из промежуточной области?» с недавним Git 2.23 (август 2019 г.).
Это помогает отделить git checkout
на две команды:
- для файлов (
git restore
), которая может охватыватьgit reset
случаях. - один для ветвей (
git switch
, как показано в разделе «Смущает git checkout»), который имеет дело только с ветками, а не с файлами. .
Как указано в документации для сброса, восстановления и возврата:
Есть три команды с похожими именами:
git reset
,git restore
иgit revert
.
git-revert
о макине g новый коммит, который отменяет изменения, сделанные другими коммитами.git-restore
касается восстановления файлов в рабочем дереве либо из индекса, либо из другого коммита.
Эта команда не обновляет вашу ветку.
Эту команду также можно использовать для восстановления файлов в индексе из другого коммита.git-reset
касается обновления вашей ветки, перемещения подсказки для добавления или удаления коммитов из ветки. Эта операция изменяет историю коммитов.git reset
также можно использовать для восстановления индекса, перекрываяgit restore
.
Итак:
Чтобы восстановить файл в индексе, чтобы он соответствовал версии в HEAD (это то же самое, что использовать
git-reset
)git restore --staged hello. c
или вы можете восстановить и индекс, и рабочее дерево (это то же самое, что и при использовании
git-checkout
)git restore --source = HEAD --staged --worktree hello.c
или краткая форма, которая более практична, но менее читаема:
git restore -s @ -SW hello.c
С Git 2.25.1 (Февраль 2020 г.) « git restore --staged
» некорректно обновлял структуру дерева кэша, в результате чего впоследствии записывались фиктивные деревья, что было исправлено.
См. обсуждение.
См. фиксацию e701bab (8 января 2020 г.) Джеффа Кинга ( peff
).
(Объединено Junio C Hamano — gitster
— в фиксации 09e393d, 22 января 2020 г.)
Содержание
restore
: сделать недействительным дерево кэша при удалении записей с помощью —stagedАвтор сообщения: Torsten Krah
Подписано: Джефф КингКогда «
git restore --s taged
«удаляет путь, который находится в индексе, он отмечает запись с помощьюCE_REMOVE,
, но мы не делаем ничего, чтобы сделать дерево кэша недействительным.
В в неэтапном случае мы попадаем вcheckout_worktree ()
, который вызываетremove_marked_cache_entries ()
. Это фактически удаляет записи из индекса, а также делает недействительным дерево кэша и неотслеживаемый кеш.Но с
- staged
мы никогда не вызываемcheckout_worktree ()
, а записиCE_REMOVE
остаются. Интересно, что они отбрасываются, когда мы записываем индекс, но это означает, что результирующий индекс несовместим: его дерево кэша не будет соответствовать фактическим записям, и запуск «git commit
» сразу после того, как будет создать неправильное дерево.Мы можем решить эту проблему, вызвав
remove_marked_cache_entries ()
перед записью индекса. Обратите внимание, что мы не можем просто поднять его изcheckout_worktree ()
; этой функции необходимо перебрать записиCE_REMOVE
(чтобы удалить соответствующие файлы рабочего дерева) перед их удалением.Одно любопытство по поводу теста: без этого патча он фактически вызывает ОШИБКУ () при запуске git-restore:
ОШИБКА: cache-tree.c: 810: new1 с флагами 0x4420000 не должно быть в дереве кеша
Но в исходном отчете о проблеме, в котором использовался аналогичный рецепт,
git restore
фактически создает фиктивный индекс (и фиксация создается с неправильным деревом) . Я не уверен, почему тест здесь ведет себя иначе, чем мой тест вне набора, но то, что здесь, должно улавливать любой симптом (и исправление исправляет оба случая).
В Git 2.27 (второй квартал 2020 г.) « git restore --staged --worktree
» теперь по умолчанию принимает содержимое из «HEAD» вместо того, чтобы ошибаться.
См. коммит 088018e (5 мая 2020 г.) Эрика Саншайна ( sunshineco
).
(объединено Junio C Hamano — — gitster
— в фиксации 4c2941a, 8 мая 2020 г.)
restore
: по умолчанию — HEAD при объединении —staged и —worktreeПодписано: Эрик Саншайн
Проверено- Автор: Тейлор БлауПо умолчанию файлы восстанавливаются из индекса для
- worktree
и из HEAD для- -этапный
.Когда объединены
- рабочее дерево
и- staged
,- исходный код
необходимо указать, чтобы устранить неоднозначность источника восстановления, что затрудняет восстановление файла как в рабочем дереве, так и в индексе.(Из-за недосмотра
- source
, хотя и задокументировано, на самом деле не выполняется.)Однако HEAD также является разумным значением по умолчанию для
- worktree
в сочетании с- staged
, поэтому сделайте его по умолчанию в любое время, когда используется- staged
(в сочетании с- worktree
или нет).
Итак, теперь это работает:
git restore --staged --worktreegit restore -SW
На ваш 1-й вопрос «Что такое git-restore?»:
git-restore — это инструмент для отмены незавершенных изменений. Незавершенные изменения: а) изменения в вашей рабочей копии или б) содержимое вашего индекса (также известного как промежуточная область).
Эта команда была введена в git 2.23 (вместе с git-switch ) для разделения нескольких проблем, ранее объединенных в git-checkout.
git-restore можно использовать в трех разных режимах, в зависимости от того, хотите ли вы вернуть работу в рабочей копии, в индексе или оба.
git restore [--worktree]
заменяет в вашей рабочей копии содержимым вашего индекса (*). Другими словами, он отменяет ваши изменения в рабочей копии. Указываете ли вы - worktree
или нет, не имеет значения, потому что это подразумевается, если вы не говорите иначе.
git restore - staged
заменяет в вашем индексе текущим заголовком из локального репозитория. Другими словами, он отключает ранее подготовленный контент. Пока что он действительно эквивалентен старому git reset HEAD
.
Чтобы перезаписать как рабочую копию, так и индекс текущим HEAD используйте git restore --staged --worktree --source HEAD
. Эта версия делает и то, и другое: возвращает вашу рабочую копию в состояние HEAD и отменяет ранее поставленную работу.
На ваш второй вопрос «В чем разница между git-restore и git-reset?»:
Между этими двумя командами есть как совпадения, так и различия.
Оба могут использоваться для изменения вашей рабочей копии и/или промежуточной области. Однако только git-reset может изменить ваш репозиторий. В этом смысле git-restore кажется более безопасным вариантом, если вы хотите только восстановить локальную работу.
Есть и другие отличия, которые я не могу здесь перечислить.
(*) Файл, не добавленный
в индекс, по-прежнему считается находящимся в индексе, однако в «чистом» состоянии из текущей версии HEAD.
/git-tools
#!/usr/bin/env python3 | |
# | |
# git-restore-mtime — Изменить время файлов в зависимости от даты фиксации последнего изменения | |
# | |
# Авторские права (C) 2012 Родриго Силва (MestreLion) | |
# | |
# Эта программа является бесплатной: вы можете распространять ее и/или изменять | |
# это в соответствии с условиями Стандартной общественной лицензии GNU, опубликованной | |
# Free Software Foundation , либо версия 3 Лицензии, либо | |
# (по вашему выбору) любая более поздняя версия. | |
# | |
# Эта программа распространяется в надежде, что она будет полезной, | |
#, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии | |
# ТОВАРНОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. Подробнее см. | |
# Стандартную общественную лицензию GNU. | |
# | |
# Вы должны были получить копию Стандартной общественной лицензии GNU | |
# вместе с этой программой. См. | |
# | |
«» « | |
Измените время изменения (mtime) всех файлов в дереве работы на основе | |
даты самая последняя фиксация, которая изменила файл. | |
Полезно перед созданием архивов релизов, поэтому каждый файл заархивирован с помощью | |
дата, аналогичная дате последнего фактического изменения файла, | |
предполагая фактическую дату изменения и дата его фиксации близки. | |
По умолчанию игнорирует все игнорируемые и неотслеживаемые файлы, а также отказывается работать | |
на деревьях с незафиксированными изменениями. | |
«» « | |
# TODO: | |
# — Добавьте -z в git whatchanged/ls-files, чтобы мы не занимались декодированием имени файла/нормализацией ОС | |
# — Когда Python переведен на 3.7, используйте текст вместо universal_newlines в подпроцессе | |
# — Обновить «Статистику некоторых крупных проектов» с использованием современного оборудования и репозиториев. | |
# — Создайте README.md только для git-restore-mtime. Он заслуживает обширной документации | |
# — Переместить Статистика там | |
# FIXME: | |
# — Когда текущий каталог находится за пределами рабочего дерева, например, используя — work-tree, `git ls-files` | |
# предполагаем, что любые относительные пути относятся к корню рабочего дерева, а не к текущему реж. как например, | |
# относительные пути могут не работать. | |
# — Переименование и изменение режима не должны приводить к изменению mtime файла: | |
# — необходимо проверять статус ‘R100’ и изменения режима с одинаковыми BLOB-объектами | |
# — Должен требоваться статус для быть (A, C, M, R | |
# filelist является подмножеством lsfileslist. | |
# — Проверить файл (A, D) на наличие каталога mtime недостаточно: | |
# — Переименование также изменяет dir mtime, если только переименование не было в родительском каталоге | |
# — Если последнее изменение всех файлов в каталоге было [M] одификацией, | |
# каталог может быть вообще не затронут. | |
# — Каталоги, содержащие только подкаталоги, но не прямые файлы, также не будут | |
# не трогать. Это [grand] родительский каталог файлов, но не их dirname (). | |
# — Некоторые решения: | |
# — После того, как файлы будут готовы, выполните некоторую обработку каталогов для отсутствующих каталогов, найдя последнюю | |
# файл (A, D, R) | |
# — Простой подход: dir mtime — это самый последний дочерний (каталог или файл) mtime | |
# — Используйте виртуальную концепцию «создано не более чем в», чтобы заполнить недостающую информацию, всплыть | |
# для родителей и бабушки и дедушки | |
# — При работе с [grand] родительскими каталогами оставайтесь внутри | |
# — Лучшая обработка коммитов слияния. `-m` просто * неверно *. `-c/- cc` идеален, но | |
# очень медленный. Первый проход без коммитов слияния не точен. Может быть, добавить новый | |
# режим `—accurate` для` —cc`? | |
если __name__! = «__main__»: | |
raise ImportError («{} не следует использовать как модуль.». формат (__ name__)) | |
import subprocess, shlex | |
import sys, os.path | |
импорт журнала | |
import argparse | |
время импорта | |
# Обновляйте символические ссылки только в том случае, если ОС не поддерживает их отслеживание | |
UPDATE_SYMLINKS = bool (os.utime in getattr (os, ‘supports_follow_symlinks’, [])) | |
ШАГ = 100 | |
# Интерфейс командной строки ######## ########################################### | |
def parse_args (): | |
parser = argparse.ArgumentParser ( | |
description = «» «Восстановить исходное время модификации файлов на основе даты | |
самый последний коммит, изменивший их. Полезно при создании архивов релизов. «» «) | |
group = parser.add_mutually_exclusive_group () | |
группа. add_argument (‘- quiet’, ‘-q’, dest = ‘loglevel’, | |
action = «store_const «, const = logging.WARNING, default = logging.INFO, | |
help =» Отключить информационные сообщения и сводную статистику . «) | |
group.add_argument (‘- verbose’, ‘-v’, action =» count » , | |
help = «Печатать дополнительную информацию для каждого обработанного файла.») | |
parser.add_argument (‘ —force ‘,’ -f ‘, action = «store_true», | |
help = «Принудительное выполнение на деревьях с незафиксированными изменениями «) | |
parser.add_argument (‘- merge’, ‘-m’, action = «store _true «, | |
help =» «» Включить коммиты слияния. Приводит к более позднему времени и большему количеству файлов за | |
фиксацию, таким образом, с тем же временем mtime (которое может быть или не быть что вы хотите). Включение | |
коммитов слияния может привести к меньшему количеству оцениваемых коммитов (все файлы будут найдены раньше), | |
, который улучшает производительность, иногда значительно. Но поскольку коммиты слияния | |
обычно огромны, их обработка также может занять больше времени, иногда существенно. | |
По умолчанию журналы слияния используются только для файлов, отсутствующих в обычных журналах фиксации. «» «) | |
parser.add_argument (‘ —first-parent ‘, action = «store_true», | |
help = «» «Учитывать только первого родителя , «основная ветвь», при разборе журналов слияния | |
. Действует только тогда, когда в журнал включены коммиты слияния. , либо | |
с помощью —merge, либо для поиска недостающих файлов после первого анализа журнала. См. —skip-missing. «» «) | |
parser.add_argument (‘- skip-missing’, ‘-s’, | |
action = «store_false», default = True, dest = «missing», | |
help = «» » D o не пытаться найти недостающие файлы. Если некоторые файлы не были найдены в обычных | |
журналах фиксации, по умолчанию он пытается повторно использовать журналы фиксации слияния для этих файлы (если | |
—merge еще не использовался). Эта опция отключает такое поведение, которое может немного | |
улучшить производительность, но файлы, найденные только в коммитах слияния, не будут обновлены . «» «) | |
parser.add_argument (‘- без каталогов’, ‘-D’, | |
action = «store_false», по умолчанию = True, dest = ‘dirs’, | |
help = «» «Не обновляйте каталог mtime для файлов, созданных, переименованных или удаленных в нем. | |
Примечание: простое изменение файла приведет к не обновлять свой каталог mtime. «» «) | |
parser.add_argument (‘- test’, ‘-t’, action = «store_true», default = False, | |
help = «Тестовый запуск: фактически не обновлять какой-либо файл») | |
parser.add_argument (‘- время фиксации’, ‘-c’ , | |
actio n = ‘store_true’, default = False, dest = ‘commit_time’, | |
help = «Вместо этого используйте время фиксации времени автора «) | |
парсер. add_argument (‘- самый старый’, ‘-o’, | |
action = ‘store_true’, default = False, dest = ‘reverse_order’, | |
help = «» «Установить mtime на время первой фиксации упомянуть данный файл | |
вместо самого последнего. Это работает путем изменения порядка, в котором git | |
журнал обрабатывается (т. е. от самого старого до последнего коммита в текущей ветке, | |
вместо от самого последнего к самому старому). Это может привести к неправильному поведению | |
, если есть несколько файлов, которые были переименованы с тем же именем в | |
история текущей ветки. «» «) | |
parser.add_argument (‘pathspec’, nargs = ‘*’, metavar = ‘PATH’, | |
help = «» «Изменять только пути, соответствующие PATH, каталогам или файлы относительно текущего | |
каталога. По умолчанию все файлы, обрабатываемые git, изменяются без учета неотслеживаемых файлов | |
и подмодулей. «» «) | |
parser.add_argument (‘- work-tree’, dest = ‘workdir’, | |
help = «Путь в дерево работ, если это не текущий каталог или один из его родителей. «) | |
parser.add_argument (‘- git-dir’, dest = ‘gitdir’, | |
help = «Путь к репозиторию git, если не по умолчанию /.git») | |
parser.add_argument (‘ —skip-old-than ‘, metavar =’ SECONDS ‘, type = int, | |
help = «» «Не изменяйте файлы старше% (metavar) s. | |
Это может значительно улучшить производительность, если меньше файлов обрабатываются. | |
Полезно на сборках CI, которые могут в конечном итоге переключить рабочее пространство на другую ветку, | |
, но в основном выполняет сборки на одном и том же (например, мастер). | |
«» «) | |
return parser.parse_args () | |
# Вспомогательные функции ##################### ################################### | |
def setup_logging (args): | |
TRACE = logging.DEBUG//2 | |
logging.Logger. trace = lambda _, m, * a, ** k: _.log (TRACE, m, * a, ** k) | |
level = (args.verbose и max (TRACE, logging.DEBUG//args.verbose)) или args.loglevel | |
logging.basicConfig (level = level, format = ‘% (message) s’) | |
return logging.getLogger () | |
def normalize (путь): | |
«» «Нормализовать пути из git, обрабатывая символы, отличные от ASCII. | |
Git для Windows, начиная с версии v1.7.10 , сохраняет пути как форму нормализации UTF-8 C. Если путь | |
содержит не-ASCII или непечатаемые символы, он выводит UTF-8 в восьмеричном формате | |
, заключая весь путь в двойные кавычки. Двойные кавычки и обратная косая черта также экранированы. | |
https://git-scm.com/docs/git-config#Documentation/git-config.txt- corequotePath | |
https://github.com/msysgit/msysgit/wiki/Git-for-Windows-Unicode- Поддержка | |
https://github.com/git/git/blob/master/Documentation/i18n.txt | |
Пример вывода git, эта функция отменяет это: | |
r’back slash_double «quote_açaí ‘-> r ‘»назад \ slash_double » quote_a 303 247a 303 255 «‘ | |
» «» | |
if path и path [0] == ‘»‘: | |
# Python 2: path = path [1: -1] .decode («строка-escape») | |
# Python 3: https://stackoverflow.com/a/46650050/624066 | |
path = (path [1: -1] # Удалить заключительные двойные кавычки | |
.encode (‘лати n1 ‘) # Преобразовать в байты, требуется’ unicode-escape ‘ | |
.decode (‘ unicode-escape ‘) # Выполните фактическое декодирование с восьмеричным экранированием | |
.encode (‘latin1’) # 1: 1 сопоставление с байтами, формирование кодировки UTF-8 | |
.decode (‘utf8’)) # Декодирование из UTF-8 | |
# Убедитесь, что косая черта соответствует ОС; для Windows нам нужна обратная косая черта | |
return os.path. normpath (путь) | |
если UPDATE_SYMLINKS: | |
def touch (path, mtime, test = False): | |
«» «Фактическое обновление mtime» «» | |
if test: return | |
os.utime (path, (mtime, mtime), follow_symlinks = False) | |
else: | |
def touch (path, mtime , test = False): | |
«» «Фактическое обновление mtime» «» | |
if test: return | |
os.utime (путь, (mtime, mtime)) | |
isodate по умолчанию (сек): | |
return time.strftime (‘% Y-% m-% d% H:% M:% S’ , time.localtime (секунды)) | |
# Класс Git и parselog (), сердце скрипта ########################## | |
класс Git () : | |
def __init __ (self, workdir = None, gitdir = None): | |
self.gitcmd = [‘git’] | |
if workdir: self.gitcmd.extend ((‘- work-tree’, workdir)) | |
если gitdir: self.gitcmd.extend ((‘- git-dir’, gitdir)) | |
self.workdir, self.gitdir = self._repodirs () | |
def ls_files (self, pathlist = None): | |
return (normalize (_) для _ в self._run (‘ls-files —full-name’, pathlist)) | |
def is_dirty (self): | |
return bool (self._run (‘diff —no-ext-diff —quiet’, output = False)) | |
def log (self, merge = False, first_parent = False, commit_time = False, reverse_order = False , | |
pathlist = None): | |
cmd = ‘whatchanged —pretty = {}’. format (‘% ct’ if commit_time else ‘% at’) | |
при слиянии: cmd + = ‘-m’ | |
если first_parent: cmd + = ‘—first-parent’ | |
if reverse_order: cmd + = ‘—reverse ‘ | |
return self._run (cmd, pathlist) | |
def _repodirs (self): | |
return (os.path. normpath (_) для _ в | |
self._run (‘rev-parse —show-toplevel —absolute -git-dir ‘, check = True)) | |
def _run (self, cmdstr, pathlist = None, output = True, check = False): | |
cmdlist = self.gitcmd + shlex.split (cmdstr) | |
если список путей: | |
cmdlist.append (‘-‘) | |
cmdlist.extend (список путей) | |
log.trace («Выполнение:% s», » .join (cmdlist)) | |
, если не выводится: | |
return subprocess.call (cmdlist) | |
если проверьте: | |
попробуйте: | |
stdout = subprocess.check_output (cmdlist, universal_newlines = True) | |
return stdout.splitlines () | |
кроме subprocess.CalledProcessError как e: | |
поднять self.Error (e.returncode, e.cmd, e.output, e.stderr) | |
self.proc = subprocess. Popen (cmdlist, stdout = subprocess.PIPE, universal_newlines = True) | |
return (_.strip () for _ в self.proc.stdout) | |
Ошибка класса (subprocess.CalledProcessError): пройти | |
def parselog (filelist, dirlist, stats, git, merge = False, filterlist = None): | |
mtime = 0 | |
для строки в git.log (merge, args.first_parent, args.commit_time, args.reverse_order, | |
filterlist): | |
статистика [‘loglines’] + = 1 | |
# Пустая строка между датой и списком файлов | |
если не строка: продолжить | |
# Строка файла | |
if line [0] == ‘:’ : # Быстрее, чем line.startswith (‘:’) | |
# Если строка описывает переименование, в linetok есть три токена , иначе две | |
linetok = line. split (‘ t’) | |
status = linetok [0] | |
file = linetok [-1] | |
# Обрабатывает символы, отличные от ASCII, и разделитель путей ОС | |
file = normalize (файл) | |
если файл в списке файлов: | |
stats [‘files’] — = 1 | |
log.debug («% d t% d t% d t% s t% s «, | |
stats [‘loglines’ ], статистика [‘совершает’], статистика [‘файлы’], | |
isodate (mtime), file) | |
filelist.remove (файл) | |
попробуйте: | |
touch (os.path.join (git.workdir , файл), mtime, args.test) | |
stats [‘touches’] + = 1 | |
кроме Exception as e: | |
log.error («ОШИБКА:% s», e) | |
stats [‘errors’] + = 1 | |
если args.dirs: | |
dirname = os.path.dirname (file) | |
если статус [-1] в ( ‘A’, ‘D’) и имя каталога в списке каталогов: | |
log.debug («% d t% d t- t% s t% s «, | |
stats [‘loglines’], stats [ ‘совершает’], | |
isodate (mtime), «{}/». формат (имя каталога или ‘.’ )) | |
dirlist.remove (имя каталога) | |
попробуйте: | |
touch (os.path.join (git .workdir, dirname), mtime, args.test) | |
stats [‘dirtyouches’] + = 1 | |
кроме Exception as e: | |
log.error («ОШИБКА:% s», e) | |
stats [‘direrrors’] + = 1 | |
# Строка дат | |
else: | |
stats [‘commits’] + = 1 | |
mtime = int (строка) | |
# Все файлы готовы? | |
if not stats [‘files’]: | |
git.proc.terminate () # хакерский, но делает работу. В любом случае не требуется | |
return | |
# Основная логика ################################# ############################# | |
def main (): | |
start = time.time () # да, время стены. Процессорное время нереально для пользователей. | |
stats = {_: 0 for _ in (‘loglines’, ‘ совершает ‘,’ касается ‘,’ ошибок ‘,’ грязные пятна ‘,’ direrrors ‘)} | |
# Перво-наперво: где и кто мы? | |
попробуйте: | |
git = Git (args.workdir, args .gitdir) | |
кроме Git.Error как e: | |
# Не в репозитории git, а git уже проинформировал пользователя о stderr. Итак, мы просто … | |
возвращаем e.returncode | |
# Не работать с грязными репозиториями, кроме —force | |
, если не args.force и git.is_dirty (): | |
log.critical ( | |
«ОШИБКА: в рабочем каталоге произошли локальные изменения. N» | |
«Это может привести к нежелательным результатам для измененные файлы. n « | |
» Пожалуйста, подтвердите свои изменения (или используйте —force) и повторите попытку. n « | |
» Прерывание «) | |
return 1 | |
# Получить файлы, управляемые git, и построить файл и список каталогов для обработки | |
filelist = set () | |
dirlist = set () | |
d> | , если UPDATE_SYMLINKS, а не args.skip_older_than: |
filelist = set (git.ls_files ( args.pathspec)) | |
dirlist = set (os.path.dirname (_) для _ в списке файлов) | |
else: | |
для пути в git.ls_files (args.pathspec): | |
fullpath = os.path. присоединиться (git.workdir, путь) | |
# Символьная ссылка (в файл, в каталог или сломана — git обрабатывает аналогично) | |
если не UPDATE_SYMLINKS и os.path.islink (fullpath): | |
log. предупреждение («ВНИМАНИЕ: пропуск символической ссылки, ОС не поддерживает обновление:% s», путь) | |
continue | |
# пропустить файлы старше заданного порога | |
if args.skip_older_than и start — os.path.getmtime (полный путь)> args.skip_older_than: | |
continue | |
# Всегда добавляйте их относительно корня рабочего дерева | |
filelist.add (путь) | |
dirlist.add (os.path.dirname (path)) | |
stats [‘totalfiles’] = stats [‘files’] = len (список файлов) | |
log.info («{0 :,} файлов для обработки в рабочем каталоге» .format (stats [‘totalfiles’])) | |
если не список файлов: | |
# Ничего не делать. Выйти тихо и без ошибок, как это делает git | |
return | |
# Обрабатываем журнал, пока все файлы не будут ‘прикоснулся’ | |
log.debug («Строка # tLog # tF.Left tМодификация времени tИмя файла «) | |
parselog (список файлов, список каталогов, статистика, git, args.merge, args.pathspec) | |
# Отсутствующие файлы | |
if filelist: | |
# Попытайтесь найти их в журналах слияния, если это еще не сделано | |
# (обычно ОГРОМНЫЙ, поэтому НАМНОГО медленнее!) | |
, если args.missing, а не args.merge: | |
filterlist = list (список файлов) | |
для i в диапазоне (0, len (filterlist), STEPMISSING): | |
parselog (f ilelist, dirlist, stats, git, | |
merge = True, filterlist = filterlist [i: i + STEPMISSING]) | |
# По-прежнему не хватает некоторых? | |
для файла в списке файлов: | |
log.warning («ПРЕДУПРЕЖДЕНИЕ: не найдено в журнале:% s», файл) | |
# Итоговая статистика | |
# Предложение: используйте git-log —before = mtime, чтобы похвастаться пропущенными записями журнала | |
log.info ( | |
«Статистика: n « | |
» {: 13,. 2f} секунды n « | |
» {: 13,} обработано строк журнала n « | |
«{: 13,} оценивается коммитов» | |
«» .format (time.time () — начало, статистика [‘loglines’], статистика [‘совершает’])) | |
если args.dirs: | |
if stats [‘direrrors’]: log.info («{: 13,} ошибки обновления каталога» .format (stats [‘ direrrors ‘])) | |
log.info («{: 13,} каталоги обновлены» .format (stats [ ‘грязные пятна’])) | |
if stats [‘touches’]! = stats [‘totalfiles’]: log.info («{: 13,} files» .format (stats [‘totalfiles’])) | |
if stats [‘files’]: log.info («{: 13,} файлов отсутствуют» .format ( stats [‘files’])) | |
if stats [‘errors’]: log.info («{: 13,} ошибки обновления файлов «.format (stats [‘errors’])) | |
log.info («{: 13,} файлы обновлены» .format (статистика [‘касания’])) | |
if args.test: | |
log.info (» ТЕСТОВЫЙ ЗАПУСК — файлы не изменены! «) | |
args = parse_args () | |
log = setup_logging (args) | |
log.trace («Аргументы:% s», args) | |
# Интерфейс готов, время показа! | |
попробуйте: | |
sys.exit (main ()) | |
кроме KeyboardInterrupt: | |
log.info («Прерывание») | |
sys.exit (-1) |