коммитов имеют идентификаторы ha sh. (Запустите git log
, чтобы увидеть их.) Идентификатор ha sh - это истинное имя каждого коммита, поэтому легко определить, есть ли у вас какой-либо коммит: у вас есть этот идентификатор ha sh? Если так, у вас есть этот коммит. Если нет, вы можете получить этот коммит из любого репозитория Git, который показал, что у вас есть sh ID.
Когда вы или кто-либо другой делаете коммит новый , этот новый коммит получает новый уникальный идентификатор ha sh. Ни один другой коммит нигде не может использовать этот га sh ID. Этот ha sh ID теперь предназначен для вашего коммита. (На самом деле, если мы заранее точно знали, что вы собираетесь добавить в свой коммит - ваше имя, адрес электронной почты, метки даты и времени, сообщение журнала, снимок источника, родительский коммит ha sh ID, et c. - мы могли бы сказать вам, что будет ha sh ID . Конечно, мы никогда не сможем заранее знать, в какое время вы сделаете свой коммит или какое сообщение в журнале вы введите * et c.)
Но каждый коммит также хранит необработанный идентификатор ha sh своего непосредственного родительского коммита. Итак, вы и этот другой разработчик начинаете работать. Давайте дадим вам два имени, чтобы сделать это проще. Я буду называть тебя "ты", а он / она / они "они". Вы делаете свой коммит; его родитель - какой-то большой уродливый га sh ID, a123456...
или что-то еще. Они делают их коммит; его родитель тоже a123456...
. Вы и они запускаете git push origin master
.
. На этом этапе мы должны сделать дополнительное замечание: внутри каждого коммита полный и полный снимок всех файлов . Ваш снимок имеет полную копию файла с тем, что вы сделали в этих строках. Их снимок имеет полную копию файла с тем, что они сделали в этих строках. Родительский коммит, a123456...
, имеет полную копию того, что было в файле ранее. Это не имеет прямого отношения к этому вопросу, но поможет позже, когда вы подумаете о процессе объединения.
В любом случае, вы и они оба запускаете git push origin master
. Один из вас «выигрывает гонку», потому что вы не можете одновременно вызвать третий Git на origin
: этот третий Git будет удерживать «телефонный звонок», пока один из Вы сделали. Допустим, вы выиграли гонку. Вы отправляете свой новый коммит - давайте назовем его b789abc...
- Git на origin
, и он говорит мой родительский коммит a123456...
. Git в origin
имеет свои master
в a123456
прямо сейчас. Таким образом, Git в origin
видит, что это просто добавляет к его коллекции коммитов: он помещает коммит b789abc
в его коллекцию и устанавливает его master
для запоминания b789abc
.
Теперь, когда ваш pu sh готов, их начинается по-настоящему. Они отправляют свой коммит, с каким бы ни был его sh ID, на Git в origin
. Их коммит говорит мой родительский коммит a123456
. * * * * * Git в оригинале говорит: Ух ты, подожди, мой master
равен b789abc
, и если я возьму твой и положу т sh ID как мой master
, я полностью забуду совершу b789abc
и потеряю его навсегда! Так что нет, я не возьму ваш коммит!
Кто бы ни проиграл эту гонку пу sh, он видит их пу sh rejected
как non-fast-forward
. Победитель выигрывает, а проигравший должен выполнить больше работы.
В этом случае они - кем бы они ни были - должны использовать git fetch
для получения вашего коммита, b789abc...
, из Git на origin
. (Это Git теперь вызывает этот конкретный коммит своим master
.) Теперь они будут иметь в своем хранилище последовательность коммитов, которая выглядит так:
c987654 <-- master (HEAD)
/
...--a123456
\
b789abc <-- origin/master
(при условии, что их коммит c987654...
) .
Теперь они - а не Git в origin
- должны объединить вашу работу и их работу, что они могут сделать любым количеством способов. Они имеют их снимок всех файлов, включая их работу, ваш снимок всех файлов, включая вашу работу, и общий начальный моментальный снимок. Они должны объединить эти три коммита некоторым подходящим способом, чтобы получить четвертый коммит:
c987654
/ \
...--a123456 d888888 <-- master (HEAD)
\ /
b789abc <-- origin/master
например, где этот d888888...
коммит представляет собой слияние , или, может быть:
c987654 [abandoned]
/
...--a123456 edcba98 <-- master (HEAD)
\ /
b789abc <-- origin/master
, где edcba98...
коммит происходит от rebase (копировать, но изменять при копировании) коммита c987654...
.
Теперь они могут git push
свой новый коммит, каким бы он ни был, в Git в origin
, потому что у них будет их новый коммит, помните, как его родитель, коммит, являющийся коммитом коммита master
в origin
, так что их новый коммит просто расширяет origin
master
.