Git: история файлов через вилки - PullRequest
0 голосов
/ 09 мая 2018

Моя компания недавно мигрировала из Clearcase в GIT. Нам интересно, есть ли способ отобразить историю файлов между разветвленными репозиториями? Наша разработка состоит из репо основного продукта и серии «проектных вилок». Сопровождающие и разработчики хотели бы иметь возможность видеть изменения отдельных файлов со всех ветвей определенного репо (родительского). это было бы немного похоже на функцию «Дерево версий» в CC. У нас много вилок, и для каждого разработчика было бы нецелесообразно делать клон из них всех, а затем искать каждый клон. Мы используем Bitbucket 5.3

1 Ответ

0 голосов
/ 09 мая 2018

Git не имеет «историю файлов». Git имеет коммиты, а коммиты являются историей, потому что каждый коммит имеет некоторый набор родительских коммитов . Когда мы - или Git - связываем коммит с его родителем (-ями), а затем используем его / ее родитель (ы) для связи с другими родителями, мы получаем график:

A <-B <-C   <--master
     \
      D   <--develop

Здесь имя master выбирает коммит C, чьим родителем является коммит B. Имя develop выбирает коммит D, родитель которого также является коммитом B. Коммит B имеет коммит A в качестве родителя, и поскольку этот репозиторий настолько мал, коммит A является самым первым коммитом и вообще не имеет родителя.

Следовательно, история в этом хранилище такова, что C ведет к B, что приводит к A, а D ведет к B, который мы уже видели. Это это история. Это все есть ... кроме ...

Хорошо, мы знаем, что каждый коммит представляет собой снимок всех файлов. Так что commit C содержит некоторый набор файлов. Зафиксировать B также имеет снимок всех файлов. Если набор файлов в коммите C совпадает с набором файлов в коммите B, за исключением одного конкретного файла, такого как README, который отличается, почему тогда мы можем синтезировать a история для файла README: она была изменена в C относительно его родителя B.

Файл просто там , в C и B, но в этих двух коммитах он отличается . Два коммита связаны - B является родителем C (что означает, что C является дочерним элементом B, хотя нам нужно вычислить , поскольку Git хранит только обратные ссылки ). Таким образом, это позволяет нам синтезировать историю файлов: мы смотрим историю фиксации и извлекаем информацию о файле, который нас интересует. Если он изменил от одного дочернего элемента до своего родителя, мы можем утверждать, что это интересное изменение, записывающее идентификаторы дочернего и родительского идентификатора (и если у дочернего элемента только один родитель, нам даже не нужно записывать родительский идентификатор).

Добавление нового коммита просто добавляет больше истории

Предположим, у нас есть вышеуказанный репозиторий с четырьмя коммитами, и мы его клонируем, чтобы мы могли работать над ним. В нашем клоне мы извлекаем ветку develop, так что commit D является текущим коммитом, а наш HEAD присоединяется к имени develop:

A--B--C   <-- master
    \
     D   <-- develop (HEAD)

Теперь мы редактируем файл README, запускаем git add README и запускаем git commit. Наш Git делает новый коммит E, который получает новый, уникальный, большой уродливый хеш-идентификатор и сохраняет его в нашем репозитории. Он устанавливает parent из E в D - фиксацию, которая была текущей, когда мы запустили git commit - и затем сохраняет хэш-идентификатор E в нашем имени develop, давая нам :

A--B--C   <-- master
    \
     D--E   <-- develop (HEAD)

Наше имя develop теперь указывает на фиксацию E вместо фиксации D.

Если мы теперь хотим изучить историю файла README, мы должны начать с коммитов E и commit C и работать в обратном направлении. README изменился с E на D? Да, так что commit E (parent D) интересен. README изменился с C на B? Да, так что commit C (parent B) интересен. Мы должны повторить это для каждого коммита в этом хранилище, и это дает нам синтезированную историю файла README.

О "вилках"

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

В св одиночку, эта ссылка на оригинал имеет имя , которое Git называет remote . Стандартное название origin. Git использует это, чтобы автоматически получать новые коммиты из исходного репозитория, используя git fetch, и отправлять новые коммиты, сделанные в клоне, в исходный репозиторий, используя git push. Шаг выборки выбирает коммиты, сделанные с момента последней выборки или с момента первоначального клона. То есть у них есть коммиты, которых у вас нет. Шаг толчка дает им коммиты, которые у вас есть, а они нет. Опять же, мы видим, что Git имеет и заботится о коммитах.

Когда вы используете кнопку веб-страницы "fork a repository" веб-сервера, сам сервер записывает, каким-то закулисным способом, ответвление. Можно ли и как получить этих записей, чтобы найти соответствующие URL-адреса сервера для каждого такого клона, зависит от сервера. Если вы можете найти их все, вы можете просто добавить URL-адрес к существующему клону, одно дополнительное имя для каждого URL-адреса, а затем использовать git fetch --all для извлечения из всех пультов ( все серверные клоны) в один клон.

Истинное имя коммита - его хэш-идентификатор

Во вселенной Git каждый коммит имеет уникальный хэш-идентификатор, отличный от любого другого коммита. Два репозитория Git решают, есть ли в одном из них коммит, а в другом нет, путем сравнения хеш-идентификаторов, поэтому эти должны быть уникальными. Не вдаваясь в подробности, это действительно работает: два коммита одинаковы, если их хэши совпадают, и разные, если нет. Это означает, что независимо от того, сколько времени прошло с тех пор, как два хранилища разошлись, если в какой-то момент они совместно использовали некоторый набор коммитов в силу того, что один был клонирован из другого, они будут делиться некоторыми коммитами. 1 Истории подключиться в этой точке. Все уникальные последующие коммиты, конечно, будут уникальными, хотя, если кто-то, кто сделал форк (т.е. клон), каким-то образом перенес этот коммит обратно на один из других форков (т. Е. На другой клон), эти два клона будут совместно использовать фиксированный возврат.


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


Каждый клон является полным и независимым от всех других клонов, за исключением случаев, когда вы их перекрестно соединяете

Хотя верно, что любой коммит, чей хэш-идентификатор совпадает с одинаковым во всех клонах (по определению), каждый клон не зависит от каждого другого клона всегда. Под этим мы подразумеваем, что тот, кто управляет этим клоном, может добавить к нему новые коммиты или изменить имена его ветвей, чтобы эти имена ссылались на разные коммиты. Например, после того, как мы добавим коммит E в наш репозиторий, мы можем удалить коммит E снова, используя git reset. Если мы сделаем это, и не никуда не продвинет наш новый коммит E, никто больше никогда не увидит, что мы его сделали. Изменение, которое мы внесли в README в коммите E (относительно его родителя D), исчезает:

A--B--C   <-- master
    \
     D   <-- develop (HEAD)
      \
       E   [abandoned]

Это особенность распределенных репозиториев. Коммиты существуют только там, где они существуют - тавтологические, но истинные. Когда коммит отправляется из нашего клона в какой-либо другой репозиторий, коммит существует в двух репозиториях. Его уникальный идентификатор хэша теперь в обоих. Единственный способ избавиться от него сейчас - убедиться, что в обоих репозиториях есть имена, в которых найти коммит E, так что эти имена больше не находят коммит E. Обычно мы не пытаемся удалить коммиты, если они не были переданы кому-либо еще, , хотя, поскольку для этого требуется , перейдите к каждому клону, которому мы дали коммит, и убедитесь, что они тоже отбрасывают этот коммит действие. Следовательно, после публикации в общедоступном клоне, таком как веб-форк, коммиты становятся постоянными.

Git в общем очень липкий с коммитами. Если мы кросс-соединяем наш клон с коммитом E в нем (достижимым от имени develop) к другому клону, и имеем другой Git делает выборку, его Git спросит обо всех наших коммитах, которых у них нет, и возьмет новый коммит и даст ему имя типа ourclone/develop. Таким образом, git fetch -ing с каждого форка будет собирать каждый коммит, доступный в каждом репозитории, давая нам своего рода супер-набор клонов.

Этот супер-набор клонов позволит вам делать то, что вы хотите

Как только у нас есть супер-набор, в котором собраны все вилки, мы можем заставить наш Git находить каждый интересный коммит, начиная с каждого имени для удаленного отслеживания (forkA/master, forkA/develop, forkB/master и т. Д. ), ищет дочерние коммиты с README, который отличается от их родительских коммитов. Поскольку хэш-идентификаторы универсальны, теперь мы можем, глядя на любой отдельный форк, сказать, есть ли у этого форка конкретная версия этого файла. Но нам нужно построить довольно массивную историю комбинированных коммитов, чтобы точно видеть , где каждый экземпляр этого файла находится в фактической истории, которая является набором всех коммитов, потому что файлы не имеют истории.

Обратите внимание, что на самом деле вам не нужно создавать супер-набор клонов - но вам делать нужен доступ к каждому коммиту по его хеш-идентификатору, чтобы увидеть, какая версия README является в , которые фиксируют, и посмотрите, что является (являются) родителем (ями) этого коммита, и какая версия README находится в родителе (ях). Это означает, что вы должны иметь доступ к каждому форку и видеть все коммиты на этом форке. Работа, которую вы выполняете для создания всей этой информации, - это такая же , как и работа, которую вы выполняете, чтобы построить супер-набор клонов, так что вы также можете построить супер-набор клонов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...