TL; DR
Действительно короткий ответ "да".Но есть множество заблуждений, что это простое «да, они потому что вы вытащили» оставляет позади.
Long
Во-первых, вам нужно перестать думать в терминах отдельных файлов, так какgit pull
не тянет файлы .Фактически, это просто оболочка для запуска двух команд Git.Если вы новичок в Git, я рекомендую избегать git pull
: используйте две отдельные команды, так как это даст вам гораздо лучшее представление о том, что происходит и что делать, когда одна из двух командтерпит неудачу.
(Это особенно важно в сценариях: избегайте ориентированных на пользователя команд высокого уровня в пользу машинно-ориентированных или сантехнических команд. Они предназначены для этого использования и неНе меняйте их поведение в зависимости от личных настроек каждого пользователя. Команда git pull
это , а не команда слесарного дела, но git fetch
есть или может быть. Вторая команда, которую мы рассмотрим isn 'т, но обойти это сложнее.)
git fetch
Первая из двух команд, которые запускает git pull
, это git fetch
: например, git pull origin master
запускает git fetch origin master
.Если вы запустите это самостоятельно, вы можете полностью исключить origin master
: ваш Git по умолчанию будет извлекать данные из другого Git, используя URL-адрес, сохраненный под именем origin
.
. 1035 * совершает *.Хотя верно, что коммиты содержат файлы (так что это приводит к файлам), лучше думать о них как о коммитах, которыми они являются.Каждый из них представляет собой снимок каждого файла, как это было в то время, когда кто-то сделал этот коммит.
Коммиты фактически идентифицируются по своим хэш-идентификаторам (например, commit b9c30a8...
), и каждыйcommit хранит хэш-идентификатор своего parent commit.Это позволяет Git связывать коммиты в цепочки, которые всегда смотрят назад. имя ветки просто содержит идентификатор последнего коммита на ветке:
... <-commit1 <-commit2 <-commit3 <--branch-name
Когда вы впервые git clone
хранилище Git, вы инструктируете свой Gitсоздать новый репозиторий и заполнить его из всех коммитов в каком-либо другом существующем Git-репозитории.Ваши коммиты совпадают с их коммитов (имеют одинаковые идентификаторы).Тем временем ваш Git запоминает, где их имена веток указывали, используя такие имена, как origin/master
, и делает ваше собственное имя ветви master
, указывающее на тот же коммит:
...--I--J <-- master (HEAD), origin/master
(к одному из имен ваших веток прикрепляется HEAD
, чтобы ваш Git знал, в какой ветке вы находитесь.)
Когда вы делаете новые коммиты, origin/master
- чтозапоминание их , origin
, master - остается на месте, но ваш master
движется так, что он запоминает ваш последний коммит.Ваш новый коммит запоминает идентификатор предыдущего коммита:
K <-- master (HEAD)
/
...--I--J <-- origin/master
Когда вы запускаете git fetch
или git fetch origin
, ваш Git снова вызывает другой Git и выясняет, какие коммиты он имеет, что вы не делаете.т - совершает что-то новое для вас.Ваш Git имеет свой Git, который отправляет эти коммиты, а затем обновляет ваши origin/*
имена, чтобы запомнить их последние указатели веток:
K <-- master (HEAD)
/
...--I--J--L <-- origin/master
Вот где приходит вторая команда.
Передмы доберемся, позвольте мне добавить примечание к терминологии.Когда вы делаете новый коммит, вы работаете с файлами в вашем рабочем дереве , но затем запускаете git add somefile.ext
. копирует файл из вашего рабочего дерева в то, что Git называет его index или staging-area .Индекс, возможно, лучше всего описать как , где вы строите следующий коммит, который вы сделаете .Он начинается с копии каждого файла из текущего коммита.Вы копируете новые версии в индекс, чтобы подготовить их для перехода к следующему коммиту, а файлы, которые вы не перезаписываете остаются в индексе и также , входят в следующий коммит.Вот почему каждый коммит представляет собой снимок каждого файла - ну, каждый файл, который был в индексе в то время.
Индекс принимает расширенную роль во время слияния, мывот-вот увидим.
git merge
ThВторая команда, которую запускает git pull
, обычно это либо git merge
, либо git rebase
, которая, среди прочего, зависит от настроек конфигурации пользователя.В вашем конкретном случае он, очевидно, использовал git merge
.В частности, он запускал git merge -m "Merge branch 'master' of <url>" <hash-id>
, но когда вы делаете это самостоятельно, обычно вы можете просто запустить git merge
без аргументов.
Команда слияния имеет несколько различных режимов работы.По умолчанию, однако, он просматривает как ваш текущий коммит / ветвь (как запомнилось прикрепленным HEAD
), так и другое имя коммита или ветки, которое вы предоставляете, или upstream текущей ветки. цель этой операции - объединить любую работу, которую вы сделали, с любой работой, которую они - кем бы они ни были - выполнили.Для этого Git должен найти первый коммит, который вы и они поделили .
Глядя на график, который мы нарисовали, очевидно, что вы оба начали коммит:
K <-- master (HEAD)
/
...--I--J--L <-- origin/master
Коммит, которым вы оба поделились до того, как вы пошли разными путями, был коммитом J
.Итак, теперь ваш Git в действительности запускает две команды git diff
:
git diff --find-renames <hash-of-J> <hash-of-K>
git diff --find-renames <hash-of-J> <hash-of-L>
Этот дифференциал находит, что вы изменили file1.txt
или text1.txt
(в зависимости от того, что это - я пойду с text1.txt
здесь), и что они также изменили text1.txt
.Возможно, вы не изменили text2.txt
, но они это сделали;и вы не создали новый файл text3.txt
, но они это сделали.
Теперь ваш Git пытается объединить все эти изменения, начиная со всехфайлы в самой базе слияния в качестве отправной точки.Вы и они оба изменили text1.txt
, поэтому ваш Git пытается объединить ваши изменения в этом файле с их изменениями в этом файле. Эта попытка не удалась, , поэтому Git скоро остановится с конфликтом слияний;но между тем он продолжает объединять их изменения в text2.txt
с отсутствием изменений в text2.txt
.Это действительно легко!Это просто берет их text2.txt
.Затем он объединяет их новое создание text3.txt
с вашим отсутствием создания text3.txt
, и это тоже очень просто.
Теперь ваш Git останавливается с конфликтом.Он оставляет все три версии из text1.txt
в вашем индексе / промежуточной области / кэше.Команда слияния также оставляет в вашем рабочем дереве свою собственную попытку объединить все три версии с маркерами <<<<<<<
... >>>>>>>
в ней, так что это четвертая версия файла.
Теперь ваша задача выяснить, какова правильная комбинация.Вы можете извлечь все три версии более высокого уровня (базовая, --ours
и --theirs
) из индекса - например, то, что делает git mergetool
- и / или работать с попыткой Git объединить их, которые Git оставил вработа дерево.Когда вы закончите объединение, вы должны:
- Оставить объединенную версию в рабочем дереве под именем
text1.txt
. - Выполнить
git add text1.txt
.Это копирует версию из рабочего дерева в индекс, удаляя из индекса из трех версий более высокого уровня.
Теперь, когда в индексе есть только одна версия, котораяправильно слитый, готов к совершению.Между тем, text2.txt
и text3.txt
находятся также в индексе в нормальном (нулевая стадия) состоянии "готов к фиксации".Но так же каждый другой файл.
Вы видите эти три файла, но не другие файлы, потому что для этих трех файлов версия в индексе собрана и готова к следующему коммиту отличается от в текущем коммите.Для каждого другого файла в индексе значение совпадает с в текущем коммите, поэтому git status
не сообщает «будет в коммите, но то же самое».