2013-11-15 2 views
1

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

Вопросы: Делает ли git дельтами в затронутых файлах, чтобы ни один разработчик не просматривал его, чтобы найти и исправить изменения вручную? Или git отслеживает только версии и перезаписывает первый push вторым? Или возникает другая вещь? Спасибо :)

ответ

3

Вы начинаете с неправильного представления: Git не держит commits как deltas. Любая заданная фиксация хранит полное дерево каталогов со всеми его файлами в целом. Учитывая коммита SHA-1 ID, чтобы увидеть содержимое файла, имя которого, например, top/mid/bottom.ext, вы:

  1. извлечь дерево для фиксации (путем извлечения фиксации, которая имеет SHA-1 этого дерева в ID) и найти его поддерево под названием top. Это включает в себя идентификатор SHA-1 этого поддерева.
  2. экстракт что дерево и найти поддерево с именем mid (что дает еще один алгоритм SHA-1)
  3. экстракт что дерево и найти двоичный объект (файл) с именем bottom.ext, который дает вам последнюю SHA-1
  4. экстракта blob с использованием SHA-1. Это полное содержимое файла.

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

Помимо этого, каждый фиксатор имеет вместе с деревом идентификатор SHA-1 набор «parent commit». Выполнение транзитивного закрытия над родителями каждого коммита создает направленный ациклический граф (или, возможно, несколько групп DAG). Края на этом графике - это то, что люди любят думать как «ветви» (хотя git вычисляет их динамически, «имя ветки» просто называет узел на графике).

Все, что сказано, когда вы делаете git push, вы связываетесь с удаленным репо и получаете его представление о том, какие имена ветвей соответствуют идентификаторам фиксации, и предлагать, чтобы какое-либо конкретное имя (ы) идентификатор (ы).Вы также отправляете все «отсутствующие» идентификаторы SHA-1 и данные, необходимые для восстановления деревьев, файлов, тегов и/или коммитов для них. Удаленное репо рассматривает ваш запрос («пожалуйста, измените develop с фиксацией ID 1234567, чтобы зафиксировать ID ba98765») и принимает или отклоняет его, как правило, исходя из того, добавляет ли он новые коммиты в ветку, не удаляя старые.

Если разработчик 1 сначала подталкивает и добавляет новые фиксации к ветке develop, все идет хорошо. Затем, когда разработчик 2 толкает, ее коммиты добавляются в develop, но они инструктируют удаленное репо удалять фиксацию разработчика 1. Когда все начиналось у них было что-то вроде этого (клонированный с центрального сервера):

...<--B<--C<--D<--E  <-- develop 

где B, C, D и E представляют фиксации узлов (идентифицированные этих идентификаторов SHA-1, которые являются слишком болезненным для людей, поэтому у нас есть имя develop, чтобы отслеживать идентификатор SHA-1 для E).

Когда разработчик 1 добавляет коммит, это становится (по его собственной репо):

...<--B<--C<--D<--E<--F <-- develop 

Если он толкает это на центральный сервер, а затем добавить F прекрасно, это новое обязательство, что является «вниз по течению ». Таким образом, сервер добавляет F и изменяет develop, чтобы получить этот идентификатор.

Между тем разработчик 2 добавляет коммит, но она получает это:

...<--B<--C<--D<--E<--G <-- develop 

Ее SHA-1 ID не соответствует (поскольку идентификаторы SHA-1 являются глобально уникальными: они криптографической хэш коммита, включая все его деревья и файлы). Когда она пойдет на это, центральный сервер увидит, что она предлагает добавить G, но для этого удалите F. (Помните, что идентификатор фиксации содержит родительский идентификатор, поэтому Gдолжен указать на E. Его нельзя изменить: изменение даже одного бита в любом месте фиксации или его содержимое изменяет идентификатор SHA-1.)

С обычным (не «силовым») нажатием, сервер отклонит это.

Developer 2 должен затем git fetch (или эквивалент), чтобы забрать совершить F, давая ей это:

...<--B<--C<--D<--E<--G <-- develop 
        \ 
        `-F <-- origin/develop 

(origin быть "удаленный", что имена на центральный сервер).

Теперь ей предстоит выяснить, как объединить F и G. Два простых и автоматизированных альтернативы:

  • перебазироваться G на F
  • сделать «слиться совершить» объединение G и F в M

перебазироваться G на F ей нужно только запустить git rebase (при условии обычной настройки ветвления отслеживания).Это будет diff G против E (для получения delta-git не храните дельта!), Затем попытайтесь применить дельту к F. Если автоматизированная дельта применить работы, она не получает измененную копию G -Call него G':

...<--B<--C<--D<--E<--G 
        \ 
        F  <-- origin/develop 
        \ 
         G' <-- develop 

Старая G больше не имеет метки, поэтому она отказалась и в итоге сборщиком мусора. Новый G' является прямым потомком F и теперь может быть нажат.

другой ее вариант, слияние, создает новое обязательство M, выполнив стандартный трехстороннее слияние:

...-B--C--D--E--G--M  <-- develop 
       \ /
       F   <-- origin/develop 

Новый фиксации может быть перенесен на сервер, потому что M имеет F предком , поэтому на сервере сохраняется фиксация F.

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

Вопрос о том, следует ли переустанавливать или объединять, является одним из предпочтений. Слияние добавляет дополнительные узлы фиксации и затрудняет просмотр того, что произошло, но главная причина, по которой это сложнее, состоит в том, что он изобразил действительно. Rebasing делает его намного проще - он «выглядит», разработчик 2 ждал, пока разработчик 1 завершит свою работу, а затем написал ее на основе его. Но это не совсем то, что произошло, и достаточно часто, фиксация временных марок покажет это.


Git делает сделать дельта-сжатия внутри, но совсем по-другому. Теоретически git может сжимать содержимое файла против сообщения в фиксации, например (или наоборот). Это дельта-сжатие сохраняет размер того, что git вызывает «пакетный» файл. Деревья могут быть сжаты против других деревьев, поэтому, если вы добавляете или удаляете один файл в большой директории, соответствующее поддерево может иметь дельта-сжатие. Для производительности и удобства объекты git сохраняются «де-deltified» как «свободные объекты» и «повторно упакованы» в новые пакеты автоматически. Свободные объекты - deflate-compressed, а сжатие также используется в упаковках.

Сбор мусора также делает переупаковку, указанную выше. Большинство коммитов сохраняются на некоторое время (по 90 дней по умолчанию) через механизм «reflog» git, который позволяет вам (1) найти идентификаторы фиксации филиала по дате и (2) восстановить фиксацию удаленных случайно, до истечения срока действия логина

+0

О, мой бог, это так блестяще и имеет смысл. Спасибо, что пролили свет на эту проблему. – Karl

+0

Внутренний дизайн Git действительно потрясающий. Его пользовательский интерфейс, с другой стороны ... :-) – torek

+0

Да, нужно привыкнуть к пользовательскому интерфейсу. Но ваш ответ должен быть защищен, он так хорошо поставлен. Удивительно. – Karl

3

Когда второй разработчик пытается подтолкнуть его файл, git скажет, что его копия репозитория не обновлена, поэтому он заставит его вытащить/извлечь репозиторий. Затем, если git может автоматически фиксировать общий файл (например, потому что первый разработчик работал над строками 1-10, а второй - по строкам 50-100), тогда он сделает это. В противном случае он уведомит второго разработчика о возникновении конфликта, и ему придется вручную исправить файл.

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

+0

Звучит очень здорово. Это автоматическая дельта, объединяющая лучшие практики с git или есть другие способы сделать это? – Karl

+0

Если честно, я бы не знал. Я git-пользователь, но не эксперт :) Но то, что я описал, это то, что я всегда испытывал, и, конечно же, поведение по умолчанию; Я сомневаюсь, что есть другие способы, но некоторые git-гуру могут пригодиться сейчас. – rand

0

Git Дон» t перезаписать что-нибудь, в этом случае Git попросит вас объединить вручную.

Если разработчики работают с разными ветвями, разработчик 2 должен иметь возможность извлекать изменения, внесенные разработчиком 1 в собственное репо, а слияние - изменения.

Смежные вопросы