git: какая команда ищет во всех удаленных ветках изменения в данном файле - PullRequest
0 голосов
/ 31 октября 2019

Я пытаюсь найти большой репо с десятками веток. В частности, я ищу ветки, которые имеют изменения в конкретном файле. Какую команду Git я бы использовал для этого?

1 Ответ

0 голосов
/ 31 октября 2019

Это не ветви , которые имеют изменения в файлах. Важным образом, это даже не коммиты - мы вернемся к этому через мгновение - но что вы должны сделать, это найти коммитов , которые имеют изменения в файлах, и git loggit rev-list) может сделать это напрямую.

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

          o--o--....  <-- branch1
         /
...--o--o
         \
          o--o--...  <-- branch2

коммиты в средней строке находятся на обеих ветвях. Если git log находит вас одним из них, он находится в обеих ветвях.

Каждый коммит на самом деле просто хранит снимок плюс некоторые метаданные. Метаданные включают идентификатор хеш-кода родителя коммита или, для коммитов слияния, все хэш-идентификаторы его родителей. git log может сделать для вас следующее:

  • начиная с last commit, как найдено по одному или нескольким именам ветвей ...
  • для каждогоcommit:
    • сравнивает снимок в (одиночном) родительском элементе со снимком в коммите;
    • сообщает о файлах, которые отличаются в этих двух снимках ( см. ниже );и
    • перейти к родителю или, для фиксации слияния, перейти к одному или нескольким или всем родителям в некотором порядке (см. ниже).

сообщает о файлах, которые отличаются шаг принимает несколько форм, и наиболее полезным для вас является тот, где Git просто вообще не сообщает о коммите , если он не не имеет изменения в файле (или в любом из нескольких файлов), который вы указываете:

git log --branches -- path1 path2

Это начинается с всех переходов подсказки ветви (внекоторый порядок), посещает коммиты, которые находятся в каждой из этих ветвей, и выполняет парное сравнение родительских и дочерних элементов сохраненных снимков. Когда parent-vs-child имеет разницу с или из двух указанных путей, git log печатает фиксацию. Когда этого не происходит, git log ничего не печатает.

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

Тоgit log сравнивает каждого родителя по одному с ребенком. Каждое из этих сравнений либо показывает, что файлы все одинаковы, либо что один или несколько из них изменены. Затем, если некоторые родители имеют все этих файлов одинаковые, Git выбирает один из них - по-видимому, случайно;Вы не получаете никакого реального контроля здесь - и игнорируете все остальные. Это по умолчанию;это то, что Git называет History Simplification; и в зависимости от того, что вы пытаетесь найти, это может стать источником страданий и отчаяния, потому что он делает именно то, что вы не хотите. Чаще (вероятно) он делает то, что вы делаете хотите, именно поэтому Git делает это, но в любом случае важно понимать, что Git делает упрощение истории для такого рода git log.

Если вы не хотите этого упрощения истории, используйте:

git log --full-history --branches -- path1 path2

, поскольку --full-history отключает упрощение истории.

Обратите внимание, чтоt --branches указывает git log начинать со всех подсказок ветви . Это игнорирует любые теги , чьи коммиты не находятся в любой ветви. Для коммитов возможно быть в ветвях ноль , особенно после коммитов. Чтобы начать со всех имен тегов, добавьте --tags. Чтобы начать со всех ссылок - включая ветви и теги, а также имена для удаленного отслеживания, refs/stash и другие внутренние ссылки Git - используйте --all. Если вы используете вещи, которые не являются именами ветвей, имейте в виду, что некоторые из коммитов, которые вы найдете таким образом, могут быть в no branch.

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

...