Учитывая ветку, я хотел бы увидеть список коммитов, которые существуют только в этой ветке. В этом вопросе мы обсуждаем способы увидеть, какие коммиты находятся в одной ветке, но не в одной или нескольких указанных других ветвях.
Это немного другое. Я хотел бы узнать , какие коммиты находятся на одной ветви , а не на каких - либо других отраслях.
Вариант использования - стратегия ветвления, при которой некоторые ветки следует только объединять, а не фиксировать напрямую. Это будет использоваться, чтобы проверить, были ли сделаны какие-либо коммиты непосредственно в ветке, предназначенной только для слияния.
РЕДАКТИРОВАТЬ: Ниже приведены шаги по настройке фиктивного репозитория git для тестирования:
git init
echo foo1 >> foo.txt
git add foo.txt
git commit -am "initial valid commit"
git checkout -b merge-only
echo bar >> bar.txt
git add bar.txt
git commit -am "bad commit directly on merge-only"
git checkout master
echo foo2 >> foo.txt
git commit -am "2nd valid commit on master"
git checkout merge-only
git merge master
Должна появиться только фиксация с сообщением «плохая фиксация непосредственно при только слиянии», которая была сделана непосредственно в ветке только слияния.
git log ^branch1 ^branch2 merge-only-branch
синтаксис?git log ^branch1 ^branch2 merge-only-branch
Требует перечислений каждой отдельной ветви. Этого можно избежать с помощью умного использования bash / grep (см. Мой ответ ниже), но я надеюсь, что в git есть встроенная поддержка для этого. Вы правы, предполагая, что все ветки слияния являются удаленными (только локальные так же хороши, как и несуществующие для других разработчиков). Использование--no-merges
исключает любые коммиты, которые были объединены, а затем была удалена их исходная ветвь слияния из, поэтому предполагается, что ветки слияния из ветки сохраняются до тех пор, пока они не будут объединены в ветвь без слияния (т.е.Ответы:
Мы только что нашли это элегантное решение
В вашем примере, конечно, все еще отображается первоначальная фиксация.
этот ответ не совсем отвечает на вопрос, потому что первоначальная фиксация все еще отображается. С другой стороны, многие люди, приходящие сюда, похоже, находят ответ, который ищут.
источник
initial valid commit
, что часть обоихmerge-only
иmaster
ветвей. Однако, если кто-то приложит усилия, чтобы поместить в конец имя текущей ветки, за которым следуют имена ветвей с префиксом ^, которые, как известно, исходят из текущей ветки, это решит половину проблем (за исключением вещей, которые были объединены). Пример:git log --first-parent --no-merges merge-only ^master
git log --first-parent --no-merges | grep <branch_name>
Предоставлено моим дорогим другом Редмумба :
... где
origin/merge-only
находится имя вашей удаленной ветки только для слияния. При работе на локальном-только мерзавца репо, заменительrefs/remotes/origin
сrefs/heads
, и заменить имя удаленного филиалаorigin/merge-only
с именем локального филиалаmerge-only
, а именно:источник
git for-each-ref
для перечисления каждого имени ссылки в источнике иgrep -v
для исключения ветки только слияния.git log
принимает--not
параметр, которому мы передаем наш список всех ссылок (кроме ветки только слияния). Если у вас есть более элегантный ответ на проблему, давайте его послушаем./*
вgit for-each-refs
командах не опирается на соответствие некоторых существующий файла и не имеющийfailglob
илиnullglob
множество ( Баш вариантов, другие оболочки изменяются). Вы должны либо заключить в кавычки / избежать звездочек, либо просто оставить завершение/*
(git for-each-ref
шаблоны могут соответствовать «от начала до косой черты»). Возможно, используйтеgrep -Fv refs/remotes/origin/foo
(refs/heads/foo
), чтобы более строго определить, какие ссылки удаляются.git log --no-merges B1 --not B2
где B1 - это ветка, которая вас интересует, а B2 - ветка, с которой вы хотите сравнить B1. И B1, и B2 могут быть локальными или удаленными ветвями, поэтому вы можете указатьgit log --no-merges master --not origin/master
или даже указать две удаленные ветки.Это покажет вам все коммиты, сделанные в вашей ветке.
источник
origin/branchName
будет указывать на заголовок удаленной ветки ИHEAD
указывать на commitid последней локальной фиксации в этой ветке. Так что это не сработает, если вы использовали git push.@Prakash ответ работает. Просто для ясности ...
перечисляет коммиты в функциональной ветке, но не в восходящей ветке (обычно это ваш главный).
источник
Может быть, это может помочь:
источник
Попробуй это:
В основном
git rev-list --all ^branch
получает все ревизии не в ветке, а затем вы все ревизии в репо и вычитаете предыдущий список, который является ревизиями только в ветке.После комментариев @Brian:
Из документации git rev-list:
List commits that are reachable by following the parent links from the given commit(s)
Таким образом, такая команда, как
git rev-list A
где A - это фиксация, будет перечислять коммиты, доступные из A, включая A.Имея это в виду, что-то вроде
git rev-list --all ^A
перечислит коммиты, недоступные из A
Таким образом,
git rev-list --all ^branch
будут перечислены все коммиты, недоступные из конца ветки. Что удалит все коммиты в ветке, или, другими словами, коммиты, которые есть только в других ветках.Теперь перейдем к
git rev-list --all --not $(git rev-list --all ^branch)
Это будет похоже
git rev-list --all --not {commits only in other branches}
Итак, мы хотим перечислить,
all
что недоступно изall commits only in other branches
Это набор коммитов, которые есть только в ветке. Возьмем простой пример:
Здесь цель - получить D и E, коммитов нет ни в какой другой ветке.
git rev-list --all ^branch
дать только BТеперь
git rev-list --all --not B
это то , к чему мы подошли. Что такжеgit rev-list -all ^B
- мы хотим, чтобы все коммиты были недоступны из B. В нашем случае это D и E. Это то, что мы хотим.Надеюсь, это объясняет, как команда работает правильно.
Изменить после комментария:
После вышеуказанных шагов, если вы сделаете a,
git rev-list --all --not $(git rev-list --all ^merge-only)
вы получите коммит, который искали -"bad commit directly on merge-only"
тот.Но как только вы сделаете последний шаг в своих шагах,
git merge master
команда не даст ожидаемого результата. Потому что на данный момент нет фиксации, которой не было бы в режиме только слияния, поскольку одна дополнительная фиксация в мастере также была объединена в режим только слияния. Такgit rev-list --all ^branch
дает пустой результат и, следовательноgit rev-list -all --not $(git rev-list --all ^branch)
, все коммиты будут доступны только для слияния.источник
xargs -L 1 -t git branch -a --contains
отображения множества ложных срабатываний (коммитов, которые фактически находятся в других ветвях). Пробовал с и без--no-merges
. Спасибо за ответ!git rev-list --all ^branch
предоставит вам все коммиты, которых нетbranch
. Затем вы вычитаете это из списка, который находится вbranch
; но по определению все коммиты, которых нет, неbranch
входятbranch
, поэтому вы ничего не вычитаете. Джиммёрр ищет коммиты, которые находятся,branch
но не находятся вmaster
любой другой ветке. Вы не хотите вычитать коммиты, которых нетbranch
; вы хотите вычесть коммиты из любых других веток.branch
, но так же работаетgit rev-list branch
. Вы просто пишетеgit rev-list branch
более сложным (и медленным) способом. Не получается ответить на вопрос, как найти все коммитыbranch
, которых нет ни в одной другой ветке .Другой вариант принятых ответов для использования с
master
git log origin/master --not $(git branch -a | grep -Fv master)
Отфильтруйте все коммиты, которые происходят в любой ветке, кроме master.
источник
Это не совсем правильный ответ, но мне нужен доступ к форматированию и много места. Я постараюсь описать теорию, лежащую в основе того, что я считаю двумя лучшими ответами: принятый и (по крайней мере, на данный момент) получивший наибольшее количество баллов . Но на самом деле они отвечают на разные вопросы .
Коммиты в Git очень часто выполняются более чем в одной ветке за раз. В самом деле, это большая часть того, о чем идет речь. Дано:
где прописные буквы обозначают фактические идентификаторы хэша Git, мы часто ищем только фиксацию
H
или только фиксацииI-J
в нашемgit log
выводе. Сквозные коммитыG
находятся в обеих ветвях, поэтому мы хотели бы их исключить.(Обратите внимание, что на графиках, нарисованных таким образом, более новые коммиты расположены справа. Имена выбирают единственную крайнюю правую фиксацию в этой строке. Каждая из этих фиксаций имеет родительскую фиксацию, которая является фиксацией слева от них: родительский элемент
H
-G
, и родительJ
являетсяI
родитель.I
этоG
снова родитель.G
этоF
иF
есть родитель , который просто не показан здесь: это часть...
раздела).В этом особенно простом случае мы можем использовать:
для просмотра
I-J
или:H
только для просмотра . Имя справа после двух точек говорит Git: да, эти коммиты . Имя слева перед двумя точками говорит Git: нет, не эти коммиты . Git начинается с конца - при фиксацииH
или фиксацииJ
- и работает в обратном направлении . Для (гораздо) более подробной информации см. Think Like (a) Git .Исходный вопрос сформулирован так: желание состоит в том, чтобы найти коммиты, которые доступны по одному конкретному имени, но не по любому другому имени в той же общей категории. То есть, если у нас более сложный график:
мы могли бы выбрать одно из этих имен, например
name4
илиname3
, и спросить: какие коммиты можно найти по этому имени, но не по другим именам? Если мы выберемname3
ответ - совершитьL
. Если мы выберемname4
, то ответ - никаких коммитов: коммит, которыйname4
называет коммитом,N
но коммит,N
можно найти, начав с негоname5
и работая в обратном направлении.Принятый ответ работает с именами удаленного отслеживания, а не с именами ветвей, и позволяет вам назначить одно - написанное по буквам
origin/merge-only
- как выбранное имя и просмотреть все другие имена в этом пространстве имен. Он также избегает показа слияний: если мы выберемname1
«интересное имя» и скажем, покажи мне коммиты, которые доступны изname1
но не по любому другому имени , мы увидим коммит слияния,M
а также обычный коммитI
.Самый популярный ответ - совсем другой. Все дело в обходе графика фиксации, не следуя обеим сторонам слияния и не показывая каких-либо коммитов, которые являются слияниями.
name1
Например, если мы начнем с , мы не будем показыватьM
(это слияние), но если предположить, что первым родителем слиянияM
является фиксацияI
, мы даже не будем смотреть на коммитыJ
иK
. Мы в конечном итоге показывая фиксацииI
, а также совершаетH
,G
,F
и так далее никто из них слияния коммитов , и все они достижимы, начинаясьM
и работать в обратном направлении, посещая только первый родитель каждого слияния совершить.Самый популярный ответ довольно хорошо подходит, например, для того, чтобы посмотреть,
master
когдаmaster
предполагается использовать ветвь только для слияния. Если вся «настоящая работа» была проделана над боковыми ветвями, которые впоследствии были объединеныmaster
, у нас будет такая картина:где все
o
коммиты без буквенного имени являются обычными (без слияния) коммитами, аM
иN
являются слиянием. ФиксацияI
- это начальная фиксация: самая первая когда-либо сделанная фиксация и единственная, которая должна быть на главном сервере, но не фиксация слияния. Еслиgit log --first-parent --no-merges master
показан какой-либо коммит, отличный отI
, у нас будет такая ситуация:где мы хотим видеть фиксацию,
*
которая была сделана непосредственноmaster
, а не путем слияния какой-либо ветки функции.Короче говоря, популярный ответ отлично подходит для просмотра
master
когдаmaster
предполагается использовать только слияние, но не так хорош для других ситуаций. Принятый ответ работает и в этих других ситуациях.Имена для удаленного отслеживания вроде
origin/master
названия веток ?Некоторые части Git говорят, что это не так:
говорит
on branch master
, но:говорит
HEAD detached at origin/master
. Я предпочитаю согласиться с тем, чтоgit checkout
/git switch
:origin/master
не является названием ветки, потому что вы не можете «войти» в него.В принятом ответе в
origin/*
качестве «имен веток» используются имена удаленного отслеживания :Средняя строка, которая вызывает
git for-each-ref
, перебирает имена удаленного отслеживания для указанного удаленного объектаorigin
.Причина, по которой это хорошее решение исходной проблемы, заключается в том, что здесь нас интересуют чужие имена веток, а не наши имена веток. Но это означает, что мы определили ветку как нечто иное, чем имена наших веток . Это нормально: просто помните, что вы делаете это, когда делаете это.
git log
пересекает некоторую часть (части) графа фиксацииНа самом деле мы ищем здесь серию так называемых даглетов: см. Что именно мы подразумеваем под «ветвью»? То есть мы ищем фрагменты в некотором подмножестве общего графа фиксации. .
Всякий раз, когда у нас есть Git, смотрим на имя ветки, например
master
, имя тега, напримерv2.1
или на имя удаленного отслеживания, какorigin/master
правило, мы хотим, чтобы Git сообщал нам об этом коммите и каждом коммите, к которому мы можем перейти из этого коммита: начиная с этого , и работая в обратном направлении.В математике это называется ходьбой по графику . Граф фиксации Git - это направленный ациклический граф или DAG , и этот вид графа особенно подходит для прогулок. Обходя такой граф, можно посетить каждую вершину графа, достижимую по используемому пути. Вершины в графе Git - это коммиты, а ребра - это дуги - односторонние ссылки, идущие от каждого дочернего элемента к каждому родительскому элементу. (Здесь Think Like (а) Git приходит . Односторонняя природа дуг означает, что Git должен работать в обратном направлении, от дочернего к родительскому.)
Две основные команды Git для обхода графов:
git log
иgit rev-list
. Эти команды очень похожи - на самом деле, они в основном построены из одних и тех же исходных файлов, - но их вывод отличается:git log
вывод для чтения людьми, аgit rev-list
вывод, предназначенный для чтения другими программами Git. 1 Обе команды выполняют такой вид обхода графа.Обход графа, который они делают, специфичен: с учетом некоторого набора коммитов отправной точки (возможно, только одного коммита, возможно, группы хэш-идентификаторов, возможно, группы имен, которые разрешаются в хеш-идентификаторы), обход графа, посещение коммитов . Конкретные директивы, такие как
--not
или префикс^
, или--ancestry-path
, или--first-parent
, каким-то образом модифицируют обход графа .Во время обхода графа они посещают каждую фиксацию. Но они печатают только некоторое выбранное подмножество пройденных коммитов. Директивы, такие как
--no-merges
или--before <date>
сообщают коду обхода графа, который выполняет печать .Для выполнения этого посещения, по одной фиксации за раз, эти две команды используют очередь приоритетов . Вы запускаете
git log
илиgit rev-list
и даете ему отправную точку коммитов. Они помещают эти коммиты в очередь с приоритетом. Например, простой:превращает имя
master
в необработанный идентификатор хеша и помещает этот идентификатор в очередь. Или:превращает оба имени в хеш-идентификаторы и - при условии, что это два разных хеш-идентификатора - помещает оба в очередь.
Приоритет коммитов в этой очереди определяется еще большим количеством аргументов. Например, аргумент
--author-date-order
указываетgit log
илиgit rev-list
использовать метку времени автора , а не метку времени коммиттера. По умолчанию используется временная метка коммиттера и выбирается самая последняя по дате фиксация: та, которая имеет наибольшую числовую дату. Итак, приmaster develop
условии, что они разрешены для двух разных коммитов, Git покажет, какой из них позже первым, потому что он будет в начале очереди.В любом случае код обхода ревизий теперь выполняется в цикле:
--no-merges
: ничего не печатать, если это фиксация слияния;--before
: ничего не печатать, если его дата не раньше назначенного времени. Если печать не подавлена, распечатайте фиксацию: дляgit log
, покажите ее журнал; дляgit rev-list
, напечатайте его хэш-идентификатор.--first-parent
подавляет все, кроме первого родителя каждого слияния.(Оба
git log
иgit rev-list
могут выполнять упрощение истории с родительской перезаписью или без нее на этом этапе, но мы пропустим это здесь.)Для простой цепочки, такой как начало
HEAD
и работа в обратном направлении, когда нет коммитов слияния, в очереди всегда есть одна фиксация в верхней части цикла. Есть одна фиксация, поэтому мы извлекаем ее, печатаем и помещаем ее (единственного) родителя в очередь и снова обходим ее, и мы следуем по цепочке назад, пока не дойдем до самой первой фиксации, или пользователь устанет отgit log
вывода и выйдет программа. В этом случае ни один из вариантов упорядочивания не имеет значения: отображается только одна фиксация.Когда происходит слияние, и мы следуем за обоими родителями - обеими «ногами» слияния - или когда вы отдаете
git log
илиgit rev-list
более одного стартового коммита, параметры сортировки имеют значение.Наконец, рассмотрите эффект спецификатора фиксации
--not
или^
перед ним. Их можно записать несколькими способами:или:
или:
все означают одно и то же. Это
--not
похоже на префикс,^
за исключением того, что он применяется к более чем одному имени:означает не ветка1, не ветка2, да ветка3; но:
означает не ветвь1, не ветка2, не ветка3, и вы должны использовать секунду,
--not
чтобы отключить ее:что немного неудобно. Две директивы not объединяются с помощью XOR, поэтому, если вы действительно хотите, вы можете написать:
иметь в виде , не branch1, а не branch2, да branch3 , если вы хотите Затемнение .
Все они работают, влияя на обход графа. В качестве
git log
иgit rev-list
ходит граф, он убеждается не ставить в приоритет очереди любой коммит , который доступен из любого из отрицаний ссылок. (Фактически, они также влияют на начальную настройку: отрицаемые коммиты не могут попасть в приоритетную очередь прямо из командной строки, поэтомуgit log master ^master
, например, ничего не показывает.)Это используется во всем причудливом синтаксисе, описанном в документации gitrevisions , и вы можете раскрыть это с помощью простого вызова
git rev-parse
. Например:Трехточечный синтаксис означает коммиты достижимы с левой или правой стороны, но исключают коммиты, доступные с обеих сторон . В этом случае
origin/master
фиксацияb34789c0b
,, сама доступна изorigin/pu
(fc307aa37...
), поэтомуorigin/master
хэш появляется дважды, один раз с отрицанием, но на самом деле Git достигает синтаксиса из трех точек, помещая две положительные ссылки - два неотрицательных идентификатора хэша - и один отрицательный, представленный^
префиксом.Аналогично:
В
^@
синтаксических средств все родители данного обязательство , иmaster^
сам-первый родитель коммит выбрано ответвление имяmaster
-эт слияние фиксацию, поэтому он имеет два родителей. Это двое родителей. А также:^!
Суффикс означает само обязательство, но ни один из его родителей . В данном случаеmaster^
это0b07eecf6...
. Мы уже видели обоих родителей с^@
суффиксом; вот они снова, но на этот раз отрицаемые.1 Многие программы Git буквально запускаются
git rev-list
с различными параметрами и читают их вывод, чтобы узнать, какие коммиты и / или другие объекты Git использовать.2 Поскольку граф является ациклическим , можно гарантировать, что ни один из них еще не был посещен, если мы добавим ограничение никогда не показывать родительский элемент, прежде чем показывать всем его дочерним элементам приоритет.
--date-order
,--author-date-order
И--topo-order
добавить это ограничение. Порядок сортировки по умолчанию, у которого нет имени, не имеет. Если временные метки фиксации ошибочны - если, например, некоторые фиксации были сделаны «в будущем» компьютером с отключенными часами, - это в некоторых случаях может привести к странному виду вывода.Если вы зашли так далеко, теперь вы много знаете о
git log
Резюме:
git log
показывает некоторые выбранные коммиты при прохождении некоторой или всей части графика.--no-merges
Аргумент, найденный в обоих принятых и в настоящее время, топ-рейтинг ответов, подавляет показывая некоторые коммиты , которые являются шли.--first-parent
Аргумент, с текущей-топ-рейтинг-ответ, подавляет ходьбе некоторые части графика, в течение граф-ходить сам.--not
Префикс аргументов командной строки, используемый в общепринятом ответ, подавляет когда - либо посещать некоторые части графика вообще с самого начала.Используя эти функции, мы получаем ответы, которые нам нравятся, на два разных вопроса.
источник