Идентификация фактических названий веток git коммитов

введите описание изображения здесь

Это простой репозиторий git. Я пометил коммиты номерами для удобства ссылок. Репо имеет следующие филиалы:

  • мастер: 13 коммитов (1,2,3,4,5,6,7,8,9,10,11,12,13)
  • new_branch: 8 коммитов (1,2,3,4,5,6,14,15)
  • test_branch: 3 коммитов (1,2,3)
  • still_another_branch: 14 коммитов (1,2,3,4,5,6,7,8,9,10,11,12,16,17)

Коммит 5,6 относится к запросу извлечения, поэтому синяя часть с 5,6 не является ветвью.

Обратите внимание, что коммит 1,2 рассматривается как часть всех ветвей, но я хочу рассмотреть все коммиты черного цвета как часть мастера. Аналогично, для 'test-branch' я хочу рассматривать только commit 3 как часть ветви.

from git import Repo

git_url = "https://github.com/unimamun/test-repo.git"
repo_dir = "/mnt/hdd/aam/J2_Repos/test-repo/test-repo"

repo = Repo.clone_from(git_url, repo_dir)

# get all commits by branches    
def get_commits(repo, ref_name):
    commits = []
    for commit in repo.iter_commits(rev=ref_name):
        commits.append(commit)
    return commits

print('\nCommits in Branches:')
for ref in repo.references:
    print(ref.name,': ', str(len(get_commits(repo, ref.name))))


print('\nCommits in master:')
commits = list(repo.iter_commits('master'))
commits.reverse()
i = 0
for commit in commits:
    i += 1
    print(i,': ', commit.hexsha)

    # to see parents of the commit 
    #print('Parents: ',commit.parents)

Из приведенного выше кода у меня есть следующий вывод:

Commits in Branches:
master :  13
origin/HEAD :  13
origin/master :  13
origin/new_branch :  8
origin/test-branch :  3
origin/yet_another_branch :  14

Commits in master:
1 :  694df9fee2f9c03a33979725e76a484bce1738a0
2 :  c0fe1b76131b7fcb103f171fd93d85cda17b756c
3 :  0199ad335f65d52a2895a678a19e209e1e16a1a7
4 :  dd0903259b0aadbf2d8fb00e566eee014264f7c0
5 :  7ed55c51e2527f47bc6344cd960ff5beb90cc65d
6 :  d10f19c85fbc1c27b7719a2dc64989255697181d
7 :  c41bdfaeae1f801776420ce161ca2555dffc5aad
8 :  56b5d6e1831a477c79e0fd336acc96ca266d5dea
9 :  6305a72d4e257ebe74b10ca538906f1eceb091bf
10 :  4c5d1ebe5f2f8168ee8bf4a969855821d04caf09
11 :  362bc52be00af3fb917196cf27a8ddc0bb8fd4ba
12 :  5a70a46394eb08b4b48f9eb05798048ca7269a9d
13 :  f4a8bdd318b2678191d06616a55df26416a28363

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

Commits in master:
1 :  694df9fee2f9c03a33979725e76a484bce1738a0 master
2 :  c0fe1b76131b7fcb103f171fd93d85cda17b756c master
3 :  0199ad335f65d52a2895a678a19e209e1e16a1a7 test-branch
4 :  dd0903259b0aadbf2d8fb00e566eee014264f7c0 master
5 :  7ed55c51e2527f47bc6344cd960ff5beb90cc65d master
6 :  d10f19c85fbc1c27b7719a2dc64989255697181d master
7 :  c41bdfaeae1f801776420ce161ca2555dffc5aad master
8 :  56b5d6e1831a477c79e0fd336acc96ca266d5dea master
9 :  6305a72d4e257ebe74b10ca538906f1eceb091bf master
10 :  4c5d1ebe5f2f8168ee8bf4a969855821d04caf09 master
11 :  362bc52be00af3fb917196cf27a8ddc0bb8fd4ba master
12 :  5a70a46394eb08b4b48f9eb05798048ca7269a9d master
13 :  f4a8bdd318b2678191d06616a55df26416a28363 master

Мне нужно перебрать коммит с 1 по 13 и по пути мне нужно определить, какой коммит принадлежит какой ветке. Большое спасибо.

2 ответа

Вы, вероятно, хотите попробовать "--first-parentопция:

git log --oneline --first-parent master

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

Если вы попробуете это в основной ветке большого проекта, такого как ядро ​​Linux, вы в основном попадете на точки слияния, имея только несколько прямых наборов изменений в ветке.

И если это именно то, что вы хотите знать, вы можете дополнительно указать "--no-merges"явно исключить точки слияния.

git --oneline --first-parent --no-merges master

Это, например, исключит точки 4 и 7 из вашего графика.

Наконец, чтобы ограничить поиск фиксациями, которые принадлежат только определенной ветви и которые не унаследованы от главной, используйте "..Оператор:

git log master..yourbranch

... будет показывать только коммиты, которые доступны из "yourbranch", но не из "master".

Как вы заметили:

коммит 1,2 считаются частью всех веток

То есть набор достижимых коммитов из любой данной ветви, как определено, начиная с коммита наконечника ветви и работая в обратном направлении через направленный ациклический граф коммитов, всегда включает коммиты 1 и 2.

но я хочу рассмотреть все чёрные коммиты как часть мастера [ветви]

В этом случае начните с нахождения графика всех коммитов. Как вы, вероятно, знаете, граф определяется как G = (V, E), где V - множество всех вершин, а E - множество всех ребер. Git хранит данные вершин и ребер вместе в коммите: идентичность коммита - это его хеш-идентификатор, а его ребра - в действительности исходящие дуги, поскольку это ориентированный граф - являются его родительскими хеш-идентификаторами коммита.

Затем используйте имя, которое вы хотите обозначить как "самую важную" ветвь (т.е. master) чтобы найти хеш-идентификатор своего коммита tip. Назначьте этот коммит на основной набор. Пройдите по доступной части графика, начиная с этого коммита, добавляя каждый коммит в набор коммитов в master,

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

  • Для любого коммита, который уже назначен какой-либо ветви, проигнорируйте его - и вы можете немедленно прекратить обход графика в этой точке, поскольку все его предшественники, по определению, будут назначены какой-либо ветви.
  • Множество коммитов, которые вы достигли во время этой прогулки, - это набор коммитов, которые вы хотите заявить как "принадлежащие" этой ветке.

Есть несколько способов реализовать это, в том числе пройтись по подграфу, определяемому набором-вычитанием: просто вычтите подграф каждой ветви из исходного G.

Если это более удобно - возможно, так как вам не нужно будет искать G- вы можете сделать это в другом направлении: начните с master и найти достижимые коммиты, которых нет в некотором наборе, который изначально пуст. Добавьте каждый коммит в набор, перечисляя их как "в мастере". Затем выполните итерации по оставшимся ветвям: если коммит находится в наборе до сих пор, он уже был востребован, в противном случае он получает эту ветку. Проблема с такой работой заключается в том, что вы можете выбрать какую-то ветку (feature-X), который содержит все коммиты, которые содержатся в какой-либо другой ветви (develop) прежде чем выбрать меньшую ветвь (develop): вы не можете выполнить топологическую сортировку без полного графика.

После того как вы сделали это для всех подсказок веток, вы теперь назначаете каждый коммит достижимости из ветки-подсказки одной ветке (вместо того, чтобы, как это делает Git, присваиваете каждой ветке, из которой она достижима).

Обратите внимание, что в графе Git могут существовать коммиты, которые не достижимы ни из одной ветви ветки (например, достижимы из тега, но не из ветви). Если вы покопаетесь во внутренностях Git, вы сможете найти коммиты, которые достижимы только из записей reflog, или даже те, которые полностью недоступны, обнаруживаемые только путем перебора всей базы данных значений ключей объекта. Последнее по сути то, что git gc выполняет: обход базы данных для поиска всех объектов, а затем выполняет операцию сбора мусора по меткам-и-разверткам, как это делает Лисп, сохраняя достижимые объекты и отбрасывая недоступные.

Другие вопросы по тегам