Git log, чтобы получить фиксацию только для определенной ветки

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

При следующем перечислении всех коммитов из ветки, а также из родительского (основного)

git log mybranch

Другой вариант, который я нашел, заключался в том, чтобы исключить коммиты, достижимые мастером, и дает мне то, что я хочу, НО я бы хотел избежать необходимости знать имена других ветвей.

git log mybranch --not master

Я пытался использовать git for-each-ref, но он также перечисляет mybranch, поэтому на самом деле он исключает все:

git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

Update:

Я тестирую новый вариант, который я нашел некоторое время назад, и до сих пор кажется, что это может быть то, что я искал:

git log --walk-reflogs mybranch

Обновление (2013-02-13T15: 08):

Параметр -walk-reflogs хорош, но я проверил, что есть срок действия для логов (по умолчанию 90 дней, gc.reflogExpire).

Думаю, я нашел ответ, который я искал:

git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/mybranch")

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

Ответ 1

Похоже, что вы должны использовать cherry:

git cherry -v develop mybranch

Это покажет все коммиты, которые содержатся внутри mybranch, но НЕ разрабатываются. Если вы оставите последний параметр (mybranch), вместо этого будет сравнивать текущую ветку.

Как указывал VonC, вы ВСЕГДА сравниваете свою ветку с другой ветвью, так что узнайте свои ветки, а затем выберите, с кем сравнивать.

Ответ 2

НО я хотел бы избежать необходимости знать имена других ветвей.

Я не думаю, что это возможно: ветвь в Git всегда основана на другой или, по крайней мере, на другой фиксации, как объясняется в git diff doesn 't достаточно показать:

enter image description here

Вам нужна контрольная точка для вашего журнала, чтобы показывать правильные фиксации.

Как упоминалось в "git - откуда я вступил?:

Разъемы

- это просто указатели на определенные коммиты в DAG

Так что даже если git log master..mybranch - один ответ, он все равно будет показывать слишком много коммитов, если mybranch основан на myotherbranch, сам основан на master.

Чтобы найти эту ссылку (происхождение вашей ветки), вы можете анализировать только коммиты и видеть, в какой ветки они находятся, как показано в:

Ответ 3

Наконец-то я нашел способ сделать то, что хотел OP. Это так же просто, как:

git log --graph [branchname]

Команда отобразит все коммиты, которые достижимы из предоставленной ветки в формате графика. Но вы можете легко отфильтровать все фиксации на этой ветке, посмотрев на график коммитов, чей * - первый символ в строке фиксации.

Например, давайте рассмотрим выдержку git log --graph master в репозитории cakephp GitHub ниже:

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <[email protected]>
| | Date:   Tue Aug 30 08:01:59 2016 +0200
| |
| |     Merge pull request #9367 from cakephp/fewer-allocations
| |
| |     Do fewer allocations for simple default values.
| |
| * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
| | Author: Mark Story <[email protected]>
| | Date:   Mon Aug 29 22:21:16 2016 -0400
| |
| |     The action should only be defaulted when there are no patterns
| |
| |     Only default the action name when there is no default & no pattern
| |     defined.
| |
| * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
| | Author: Mark Story <[email protected]>
| | Date:   Sun Aug 28 22:35:20 2016 -0400
| |
| |     Do fewer allocations for simple default values.
| |
| |     Don't allocate arrays when we are only assigning a single array key
| |     value.
| |
* |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
|\ \  Merge: 10e5734 43178fd
| |/  Author: Mark Story <[email protected]>
|/|   Date:   Mon Aug 29 22:15:30 2016 -0400
| |
| |       Merge pull request #9322 from cakephp/add-email-assertions
| |
| |       Add email assertions trait
| |
| * commit 43178fd55d7ef9a42706279fa275bb783063cf34
| | Author: Jad Bitar <[email protected]>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

Как вы можете видеть, только коммиты 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4 и c3f45e811e4b49fe27624b57c3eb8f4721a4323b имеют *, являющийся первым символом в строках фиксации. Эти коммиты взяты из ведущей ветки, а остальные четыре - из некоторых других ветвей.

Ответ 4

Следующая команда оболочки должна делать то, что вы хотите:

git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)

Предостережения

Если вы выбрали mybranch, вышеуказанная команда не будет работать. Это потому, что фиксации на mybranch также достижимы на HEAD, поэтому Git не считает коммиты уникальными для mybranch. Чтобы заставить его работать, когда вычеркнуто mybranch, вы также должны добавить исключение для HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD \
    --all)

Однако вы не должны исключать HEAD, если не будет отмечен mybranch, иначе вы рискуете отображать коммиты, не относящиеся к mybranch.

Аналогично, если у вас есть удаленная ветвь с именем origin/mybranch, которая соответствует локальной ветке mybranch, вам нужно будет ее исключить:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --all)

И если удаленная ветка является ветвью по умолчанию для удаленного репозитория (обычно это значение только для origin/master), вам также нужно будет исключить origin/HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Если у вас проверена ветка, а там удаленная ветка, а удаленная ветка по умолчанию для удаленного репозитория, вы в конечном итоге исключаете много:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Объяснение

Команда git rev-list представляет собой низкоуровневую (сантехническую) команду, которая выполняет указанные изменения и сбрасывает найденные идентификаторы SHA1. Подумайте об этом как эквивалент git log, за исключением того, что он показывает только сообщение журнала SHA1-no, имя автора, временную метку, ни один из этих "причудливых" материалов.

Параметр --no-walk, как следует из названия, предотвращает прохождение git rev-list от цепи родословной. Поэтому, если вы наберете git rev-list --no-walk mybranch, он будет печатать только один идентификатор SHA1: идентификатор фиксации наконечника ветки mybranch.

Аргументы --exclude=refs/heads/mybranch --all указывают git rev-list, чтобы начать с каждой ссылки, кроме refs/heads/mybranch.

Итак, когда вы запустите git rev-list --no-walk --exclude=refs/heads/mybranch --all, Git печатает идентификатор SHA1 фиксации наконечника для каждого рефвота, за исключением refs/heads/mybranch. Эти коммиты и их предки - это те коммиты, которые вас не интересуют - это те коммиты, которые вы не хотите видеть.

Другие коммиты - это те, которые вы хотите увидеть, поэтому мы собираем вывод git rev-list --no-walk --exclude=refs/heads/mybranch --all и рассказываем Git, чтобы показать все, кроме коммитов и их предков.

Аргумент --no-walk необходим для больших репозиториев (и это оптимизация для небольших репозиториев): без него Git придется печатать, и оболочке придется собирать (и хранить в памяти) еще много фиксации идентификаторов, чем это необходимо. С большим хранилищем количество собранных коммитов может легко превысить ограничение аргумента командной строки оболочки.

Git ошибка?

Я ожидал, что следующее будет работать:

git log --all --not --exclude=refs/heads/mybranch --all

но это не так. Я предполагаю, что это ошибка в Git, но, возможно, это намеренно.

Ответ 5

Быстрый ответ:

git log $(git merge-base master b2)..HEAD

Скажем:

  • У вас есть ветвь master

  • Сделайте несколько коммитов

  • Вы создали ветвь с именем b2

  • Сделайте git log -n1; Идентификатор commit - это база слияния между b2 и master

  • Сделайте несколько коммитов в b2

  • git log покажет вашу историю журналов b2 и master

  • Используйте диапазон фиксации, если вы не знакомы с этой концепцией, я приглашаю вас в Google или переполнение стека - это,

    Для вашего фактического контекста вы можете сделать, например,

    git log commitID_FOO..comitID_BAR
    

    ".." - это оператор диапазона для команды журнала.

    Это означает, что в простой форме дайте мне все журналы более свежими, чем commitID_FOO...

  • Посмотрите на пункт №4, база слияния

    Итак: git log COMMITID_mergeBASE..HEAD покажет вам разницу

  • Git может получить базу слияния для вас, как это

    git merge-base b2 master
    
  • Наконец, вы можете сделать:

    git log $(git merge-base master b2)..HEAD
    

Ответ 6

Вы можете попробовать что-то вроде этого:

#!/bin/bash

all_but()
{
    target="$(git rev-parse $1)"
    echo "$target --not"
    git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
    while read entry
    do
        eval "$entry"

        test "$ref" != "$target" && echo "$ref"
    done
}

git log $(all_but $1)

Или, заимствуя из рецепт в Git Руководстве пользователя:

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )

Ответ 7

Это выведет коммиты на текущую ветку. Если какой-либо аргумент передается, он просто выводит хэши.

git_show_all_commits_only_on_this_branch

#!/bin/bash
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF

  usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}

  Compares 2 different branches, and lists the commits found only 
  in the first branch (newest branch). 

  e.g. 

  $ME         -> default. compares current branch to master
  $ME B1      -> compares branch B1 to master
  $ME B1 B2   -> compares branch B1 to B2
  $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show commit msgs if any arg passed for arg 3
if [ "$3" ]
then
  OPT="-v"
fi

# get branch names
OLDER_BRANCH=${2:-"master"}
if [ -z "$1" ]
then
  NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
  NEWER_BRANCH=$1
fi

if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
then
  echo "  Please supply 2 different branches to compare!"
  show_help
fi

OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)

if [ -z "$OUT" ]
then
  echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
  exit;
fi

if [ "$OPT" == "-v" ]
then
  echo "$OUT"
else
  echo "$OUT" | awk '{print $2}'
fi

Ответ 8

git rev-list --exclude=master --branches --no-walk

будет перечислять советы каждой отрасли, которая не является master.

git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)

перечислит каждый коммит в master истории, которого нет в любой другой истории ветвления.

Последовательность важна для опций, которые устанавливают конвейер фильтра для выбора фиксации, поэтому --branches должен следовать всем шаблонам исключения, которые он должен применить, а --no-walk должен следовать фильтрам, предоставляющим коммиты rev-list не должен идти.

Ответ 9

В моей ситуации мы используем Git Flow и GitHub. Все, что вам нужно для этого: Сравните свою ветвь с вашей ветвью развития на GitHub.

Он покажет, что коммиты, сделанные только для вашей ветки функций.

Например:

https://github.com/your_repo/compare/develop...feature_branch_name

Ответ 10

Я нашел этот подход относительно простым.

Оформить заказ в филиал и чем

  1. Бежать

    git rev-list --simplify-by-decoration -2 HEAD
    

Это обеспечит всего два SHA:

1) последний коммит ветки [C1]

2) и зафиксировать родительский элемент для первого коммита ветки [C2]

  1. Теперь беги

    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
    

Здесь C1 и C2 - две строки, которые вы получите при запуске первой команды. Поместите эти значения без <> во второй команде.

Это даст список истории изменения файла в ветке.