Подтвердить что ты не робот

Используя 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", которое было сделано непосредственно в ветке слияния.

4b9b3361

Ответ 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)

Отфильтровать все фиксации, которые происходят в любой ветки, отличной от основной.