Используя Git, покажите все коммиты, которые существуют *только* на одной конкретной ветке, а не *любые* другие


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

Это немного отличается. Я хотел бы видеть, какие коммиты находятся на одной ветке, но не на любой другие филиалы.

вариант использования находится в стратегии ветвления, где некоторые ветви должны быть только объединены и никогда не фиксируются прямо сейчас. Это будет использоваться для проверки того, были ли какие-либо фиксации сделаны непосредственно в ветке "только слияние".

EDIT: Ниже приведены шаги по настройке фиктивного РЕПО 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 непосредственно на merge-only", которая была сделана непосредственно на ветке merge-only.

7 60

7 ответов:

мой коллега только что нашел это элегантных решение git log --first-parent --no-merges. В вашем примере, конечно, начальная фиксация все еще появляется.

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

любезность моего дорогого друга 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)

может быть, это может помочь:

git show-branch

git log origin/dev..HEAD

Это покажет вам все коммиты, сделанные в вашей ветке.

попробуйте это:

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 включительно А.

имея это в виду, что-то вроде

git rev-list --all ^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) вы получите фиксацию, которую вы искали-the "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) даст все фиксация только в слиянии.

@Prakash ответ работает. Просто для ясности ...

git checkout feature-branch
git log master..HEAD

перечисляет коммиты на feature-branch, но не восходящую ветвь (обычно ваш мастер).

еще один вариант принятых ответов, чтобы использовать с master

git log origin/master --not $(git branch -a | grep -Fv master)

фильтровать все коммиты, которые происходят в любой ветви, кроме master.