Git - зачем использовать двойные тире при запуске команды для удаленного файла?
Рассмотрим git-репозиторий, где файл был когда-то удален.
git rm path/to/file
git commit -a -m"testing"
Хорошо, теперь я хочу увидеть git log
для файла, но я получаю классическое сообщение об ошибке:
git log path/to/file
fatal: ambiguous argument 'path/to/file': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
Решение простое - добавить --
:
git log -- path/to/file
Но почему? Зачем это нужно? В чем здесь обоснование? Не может ли Гит сделать обоснованное предположение, что это мог быть файл? Я понимаю проблему "неоднозначности" - но тега с таким именем никогда не было. Если файл был когда-то удален, а тег отсутствует, тогда выбор "интерпретация файла" всегда является хорошим выбором.
С другой стороны, можно иметь тег с именем, совпадающим с файлом, который git log
справляется довольно хорошо:
fatal: ambiguous argument 'path/to/file': both revision and filename
Use '--' to separate filenames from revisions
Такое поведение кажется противоречивым. Кто-нибудь может объяснить, что имели в виду разработчики git?
3 ответа
git log
можно использовать как для файлов, так и для веток, тегов и т. д.
Предположим, у вас есть папка с именем a/b/c
вы получите коммиты для этой папки используя
git log a/b/c
Все в порядке.
Вы также можете иметь ветку под названием d/e/f
, Вы получите коммиты для этой ветки, используя
git log d/e/f
Это тоже хорошо.
Вещи начинают усложняться, если предмет, где git log
следует работать, не может быть четко определена. Если ты тупой и позвони в свою ветку a/b/c
Кроме того, Git не имеет ни малейшего понятия, чей журнал должен быть напечатан: что из ветви a/b/c
или журнал вашего каталога a/b/c
? Поэтому вам нужно рассказать немного больше об информации, которую вы хотите получить:
- покажи логи ветки
a/b/c
:git log a/b/c --
- показать журнал папки
a/b/c
в текущей ветке:git log -- a/b/c
- показать журнал папки
a/b/c
вa/b/c
ветка:git log a/b/c -- a/b/c
С удаленным файлом возникает похожая проблема: ни один файл не называется path/to/file
присутствует в рабочей копии, а также нет ветки под названием path/to/file
, Это причина, почему вы должны указать, что вы хотите.
Конечно, git мог знать, что там был файл с именем path/to/file
20000 ревизий назад, но для этого потребуется (в худшем случае) поиск по всей истории вашего проекта, независимо от того, существует такой файл или нет.
Путем явного указания пути к файлу после --
Скажи мерзавцу:
искать этот файл сложнее, даже если это занимает часы
Вывод (отвечая на ваш вопрос):
в вашем случае --
нужен потому что иначе git log
будет работать медленнее в целом.
Почему разница, когда файл существует, а когда нет? Давайте посмотрим на случаи:
- Редакция и имя файла существуют. Очевидно, неоднозначно.
- Ревизия существует, а имя файла нет. Очевидно, не двусмысленно.
- Ревизия не существует, а имя файла существует. Очевидно, не двусмысленно.
- Ревизия не существует и имя файла тоже не существует. Неоднозначность?
Это действительно так.
Знать, существовал ли когда-либо файл по какому-либо пути, означает просмотреть историю, открыть каждый коммит, открыть каждое дерево и пройтись по дереву, чтобы увидеть, существовал ли тогда этот путь. В большом репозитории с большим количеством коммитов и глубоким путем... это может дорого обойтись, особенно на медленном диске.
Но! Ты говоришь. Разве это не то, что git log filename
в любом случае? И ответ - да, это так. Разница в том, что когда я бегу git log filename
и файл, как известно, существует, то git-log
знает, что я хочу потратить время, чтобы получить эту историю.
Если вместо этого я бегу git log foo
и foo не является ревизией или файлом, который существует в настоящее время, тогда ему нужно потратить время, чтобы пройти весь график, просто чтобы сказать мне, что foo
был неоднозначным.
Уч.
Так что вы можете сказать git log -- filename
сказать git, что вы действительно хотите, чтобы он шел по графику. В противном случае оно будет снижаться.
Примечание: просто мерзавец stat(2)
s аргумент, который вы даете в командной строке, чтобы определить, существует ли файл. Он не смотрит в индекс и не открывает ваше дерево HEAD. Конечно, он может делать те вещи, которые позволят вам использовать git log filename
где filename
было удаление, не поставленное для фиксации. Это кажется очень разумным изменением.
никогда не было тега с таким именем.
Почему ты это сказал? git tag path/to/file
работает просто отлично.
Это действительно так просто, как кажется: git rm
принимает только имена путей; git log
сначала берет имена ссылок и пути, имена ссылок и все, что может быть именем пути, также может быть именем ссылки - это не столько правило для того, что может быть именем ссылки, сколько определение.
В небольших проектах git log может легко решить, что если он вообще действителен, то в какой-то момент это должен быть путь к исходному файлу, но в этот момент вы должны сделать суждение, уравновешивающее вероятность и стоимость. из всех возможных провалов здесь. Возможно ли, что вы запрашиваете журналы для файла, который больше не существует, или что вы нашли имя существующего пути или существующую ссылку? git log remote/ref
очень распространено Я думаю, что git просто предполагает, что имя, которое не соответствует текущему, скорее всего, будет опечаткой.