Используя Git, покажите все коммиты, которые существуют * только * на одной конкретной ветки, а не * любые * другие
Учитывая ветку, я хотел бы увидеть список коммитов, которые существуют только на этой ветке. В этом вопросе мы обсудим способы определения, какие коммиты находятся на одной ветки, но не одну или несколько указанных других ветвей.
Это немного отличается. Я хотел бы видеть, какие коммиты находятся на одной ветке, но не на любых других ветвях.
Вариант использования находится в стратегии ветвления, где некоторые ветки должны быть объединены и никогда не выполняться непосредственно. Это будет использоваться для проверки того, были ли сделаны какие-либо коммиты непосредственно в ветке слияния.
РЕДАКТИРОВАТЬ: Ниже приведены шаги по настройке фиктивного репозитория 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
Должно появиться только сообщение с сообщением "bad commit on on merge-only", которое было сделано непосредственно в ветке слияния.
Ответы
Ответ 1
Предоставлено моим дорогим другом Redmumba:
git log --no-merges origin/merge-only \
--not $(git for-each-ref --format="%(refname)" refs/remotes/origin |
grep -Fv refs/remotes/origin/merge-only)
... где origin/merge-only
- ваше имя для удаленного имени слияния. Если вы работаете в локальном репозитории git, замените refs/remotes/origin
на refs/heads
и замените имя удаленной ветки origin/merge-only
на имя локальной ветки merge-only
, то есть:
git log --no-merges merge-only \
--not $(git for-each-ref --format="%(refname)" refs/heads |
grep -Fv refs/heads/merge-only)
Ответ 2
Мы только что нашли это элегантное решение
git log --first-parent --no-merges
В вашем примере, конечно, первоначальный коммит все еще обнаруживается.
этот ответ не совсем отвечает на вопрос, потому что первоначальный коммит все еще появляется. С другой стороны, многие приезжающие сюда, кажется, находят ответ, который ищут.
Ответ 3
git log origin/dev..HEAD
Это покажет вам все фиксации, сделанные в вашей ветке.
Ответ 4
Возможно, это могло бы помочь:
git show-branch
Ответ 5
@Ответ Prakash работает. Просто для ясности...
git checkout feature-branch
git log master..HEAD
перечисляет коммиты на ветке функций, но не ветку вверх по течению (обычно это ваш мастер).
Ответ 6
Попробуйте следующее:
git rev-list --all --not $(git rev-list --all ^branch)
В основном 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
Это набор коммиттов, которые только в ветке. Возьмем простой пример:
master
|
A------------B
\
\
C--------D--------E
|
branch
Здесь цель состоит в том, чтобы получить D и E, коммит не в какой-либо другой ветки.
git rev-list --all ^branch
дают только B
Теперь git rev-list --all --not B
- это то, к чему мы сводим. Который также git rev-list -all ^B
- мы хотим, чтобы все коммиты не достигались от B. В нашем случае это D и E. Это то, что мы хотим.
Надеюсь, это объяснит, как команда работает правильно.
Изменить после комментария:
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 rev-list --all --not $(git rev-list --all ^merge-only)
, вы получите комманду, которую вы искали, - "bad commit directly on merge-only"
.
Но как только вы сделаете последний шаг на шагах git merge master
, команда не даст ожидаемого результата. Поскольку на данный момент нет коммита, которого нет в слиянии, только после того, как одна дополнительная фиксация в master также была объединена с объединением. Таким образом, git rev-list --all ^branch
дает пустой результат и, следовательно, git rev-list -all --not $(git rev-list --all ^branch)
даст все, коммиты только для слияния.
Ответ 7
Еще одна вариация принятых ответов для использования с master
git log origin/master --not $(git branch -a | grep -Fv master)
Отфильтровать все фиксации, которые происходят в любой ветки, отличной от основной.