Почему это не работает: 'git log branchname: filepath'? - PullRequest
0 голосов
/ 06 октября 2018

Почему это не работает:

git log someBranch:path/to/myfile.txt       
echo $?  # shows 0/success but no output from git log

(Это работает:)

git rev-parse someBranch:path/to/myfile.txt # this works and returns the SHA

Есть ли другой способ получить журнал / коммиты, относящиеся к определенному файлу наконкретная ветка (без проверки этой ветки)?

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Причина, по которой он не работает должным образом, заключается в том, что git log составляет примерно коммитов , а someBranch:path/to/myfile.txt называет blob .Слово «blob» в переводе с Git означает «файл, хранящийся в коммите».

Чтобы полностью это понять, прочитайте описание на веб-сайте Думайте, как (а) Git.Но чтобы получить общее представление об этом, прочитайте следующее:

Git в основном о коммитах .Это не совсем о ветвях в конце концов.Это означает, что вам нужно знать, что именно коммит равен , и в чем разница между коммитом и ветвью.Это немного запутанно, потому что Git и люди, использующие Git, смешивают несколько разных значений слова «ветка».Чтобы распутать эти два значения для branch , полезно стать очень конкретным и вместо этого поговорить о каждом названии ветви .Но давайте начнем с коммитов.

Настоящее имя любого коммита - это большой некрасивый хеш-идентификатор.Вы увидите эти хеш-идентификаторы в выводе git log:

$ git log
commit c05048d43925ab8edcb36663752c2b4541911231
Author: Junio C Hamano <gitster@pobox.com>
Date:   Tue Sep 4 14:33:27 2018 -0700

    Git 2.19-rc2

    Signed-off-by: Junio C Hamano <gitster@pobox.com>

То, что c0504...1231 вещь является фактическим именем коммита, и, как вы можете видеть, коммит запоминает своего автора и метку времени,(Это еще не все, но мы остановимся здесь, чтобы сохранить эту краткость).

Есть две основные функции коммита: коммит заставляет Git сохранять - навсегда или до тех пор, пока коммит продолжает существовать,который также может быть навсегда - полный снимок всего в хранилище.Точнее, коммит сохраняет моментальный снимок всего в коммите, но это кажется немного избыточным: коммит имеет то, что имеет коммит.Тем не менее, это самый точный способ выразить это.Причина того, что он имеет полный снимок всего, заключается в том, что другие системы контроля версий часто сохраняют коммиты как изменения , но Git сохраняет их как целые снимки.

Другая основная функция фиксацииэто помнить его parent или предыдущий коммит.Вы не можете видеть выше, что родитель c05048d43925ab8edcb36663752c2b4541911231 является e9983f8965c0875cc6727e9644c84ff1dfc99372.Чтобы увидеть это напрямую, вы можете использовать git cat-file -p c05048d43925ab8edcb36663752c2b4541911231.Но git log увидит это, и вот что для нас важно:

После показа нам одного коммита, git log переходит к отображению предыдущего / родительского коммита. Он находитпредыдущий / родительский коммит с использованием истинного имени родителя - его большого некрасивого хеш-идентификатора - хранится в коммите.Всякий раз, когда у нас в руках большой уродливый идентификатор коммита, мы можем использовать его для find фактического коммита.Обычно мы говорим, что этот идентификатор указывает на коммит: он позволяет нам его найти.

Таким образом, каждый коммит указывает на своего родителя.Это делает обратную цепь.Если мы будем использовать одну заглавную букву для обозначения больших уродливых хеш-идентификаторов, мы получим что-то гораздо более удобное для человека, хотя тогда у нас закончатся буквы после 26 или около того коммитов (в зависимости от алфавита):

A  <-B  <-C  ...  <-H

С помощью этой однобуквенной системы довольно просто найти последний коммит: мы просто находим последнюю букву.Но они заменяют реальные, очевидно, случайные (вовсе не случайные, но и не предсказуемые) хэши.Так что нам нужно как-то знать, что H является последним хешем, и именно здесь приходят ветви names .

Имя ветвинапример, master хранит хэш-идентификатор последнего коммита в ветви. Git называет это tip коммитом ветви. Имя всегда указывает на коммит tip, , поэтому мы должны нарисовать его следующим образом:

A  <-B  <-C  ...  <-H   <--master

Если мы добавим new commit в ветвь,Git делает это, оставляя все существующие коммиты без изменений, не касаясь их вообще.Он создает новый большой уродливый хэш-идентификатор I и устанавливает для родительского элемента I значение H, а затем меняет имя master, так что master сохраняет I 's хэш-идентификатор вместо H s:

A  <-B  <-C  ...  <-H  <-I   <--master

Нетw, начиная с конца - используя имя master, чтобы найти I - мы можем работать с коммитом I.Commit I запоминает хэш H, поэтому мы можем использовать его, чтобы получить H.H запоминает хэш G, поэтому мы можем использовать , который , чтобы добраться до G, что возвращает нас к F и так далее, назад.В конечном итоге это приводит к B и A, и поскольку A является самым первым коммитом в истории, у него нет родителя, и мы можем остановиться.

Со всемиэто, мы, наконец, получаем, как git log выполняет свою работу

Основная задача для git log состоит в том, чтобы показать некоторый набор коммитов, начиная с некоторой начальной точки (или, может быть, мыдолжен называть это конечная точка , поскольку Git всегда работает в обратном направлении).Мы можем начать с любого коммита, если у нас есть его хэш-идентификатор.Но у нас есть хеш-идентификаторы, которые хранятся в именах ветвей .

На рисунках выше показано, как выглядит диаграмма, когда есть только одно имя ветви.Если есть больше имен ветвей, каждое из этих имен хранит хеш-идентификатор некоторого tip (крайний справа, в наших чертежах) коммит.Каждый коммит указывает на своего родителя как обычно.Если мы начнем рисовать внутренние стрелки в виде просто соединительных линий, чтобы сделать это проще, это даст нам, например:

...--F--G--H--I   <-- master
         \
          J--K   <-- develop

Имя master говорит начинается с I и работает в обратном направлении .Имя develop означает начинаться с K и работать в обратном направлении .

(Обратите внимание, что, работая в обратном направлении, мы в конечном итоге достигаем коммита G, независимо от того, начинаем ли мы с I или K. Этот вопрос для вашего дальнейшего исследования: В каких ветвях содержится коммит G? Мы не будем сейчас здесь это обсуждать.)

Ограничение вывода git log

В любом случае git log начинает с конца и идет по цепочке коммитов в обратном направлении, показывая каждый коммит, по одному за раз.В большом проекте это может быть много коммитов.

Каждый коммит имеет полный снимок всех файлов.Если у вас в хранилище было path/to/myfile.txt в течение длительного времени, есть много копий path/to/myfile.txt.Многие из них, вероятно, абсолютно одинаковы, и если это так, Git получает share их, чтобы использовать только одну копию для всех коммитов, которые имеют эту конкретную версию.Git может сделать это, потому что зафиксированные версии заморожены: ничто не может изменить их когда-либо.

Но если они те же , что и каждый предыдущий коммит, это делает каждый из этих коммитов довольно скучным,с вашей точки зрения!Зачем начинать с коммита Z, а затем показывать Y и X и W и т. Д., Если во всех этих коммитах имеют одинаковые path/to/myfile.txt?Так что именно здесь git log имеет возможность не показывать коммиты.

Вы можете попросить git log показать вам коммиты, начиная с некоторой начальной (конечной?) Точки и работая в обратном направлении., но пропустить, показывая большинство из них .Вы можете сказать это: Показывать мне каждый коммит тогда и только тогда, когда после сравнения коммита и его родителя файл path/to/myfile.txt отличается от в этих двух коммитах.

То есть git log начнется в конце - commit Z - и найдет родителя Z Y.Если path/to/myfile.txt равно , то же в Z и Y, git log не покажет Z.Если это не так, git log покажет покажет Z.Затем, в любом случае, Git вернется к Y.Теперь, когда он работает на Y, Git будет искать родителя Y X.Если path/to/myfile.txt равно , то в Y и X, git log просто перейдут к X.Это продолжается до тех пор, пока вы не устанете от вывода git log или git log до самого первого коммита.

Чтобы это сработало, вы должны дать git log правильный начальный (конечный?) Коммит или коммит. Вот тут и наступает git log <em>branchname</em>. По умолчанию git log начинается с вашего текущегоcommit , но вы хотите начать с какого-то другого конкретного коммита: кончика имени некоторой ветви. Затем вы также должны указать git log ограничивающий файл (ы). Вот где появляется -- <em>path</em>. Имена путей идут после --, чтобы отделить их от имен ветвей.Если у вас есть файл с именем master, git log master покажет вам коммиты, начиная с master, но git log -- master покажет вам коммиты, начиная с вашего текущего коммита, ограниченные теми, которые изменили файл master.

Обратите внимание, что не имеет значения, существует ли имя файла после --: git log просто проверяет, есть ли разница в таком файле между коммитами, когда он идет назад по истории.Если файл не входит в оба эти коммита, он сравнивается в одно и то же время, что означает «без изменений в файле».Если файл находится в точном одном из двух подтверждений, это означает, что файл изменил (был добавлен или удален).Если файл находится в обоих моментальных снимках, файл изменился тогда и только тогда, когда, конечно, файл изменился.

Почему сбой git log someBranch:path/to/myfile.txt должен быть теперь понятен

Использование someBranch:path/to/myfile.txtимеет git log поиск необработанного хеш-идентификатора BLOB-объекта.Это не коммит, поэтому git log не может показать это и не показывает.Тогда git log не имеет commit для начала, поэтому он также не может работать в обратном направлении.Не имея никаких показов, он просто ничего не делает и уходит.Для git log может иметь смысл хотя бы предупредить вас, что ваша начальная точка (конечная точка?) Вообще не была коммитом, но это не так.

0 голосов
/ 06 октября 2018

git log --branches=<regex> -- <filename>: регистрирует все коммиты, которые изменили filename в ветвях, имя которых соответствует regex.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...