Git merge - добавляет файлы, извлеченные без конфликтов, к следующему коммиту - PullRequest
0 голосов
/ 07 июня 2018

Я пытаюсь получить последний коммит, который, как мы скажем, имеет 3 разных файла: file1.txt file2.txt file3.txt

Я запускаю:

git pull origin master

Это сбрасывает3 файла выше и говорит мне, что в file1.txt есть конфликт, который я идентифицирую с помощью

git diff --name-only --diff-filter=U

. Я исправляю этот конфликт и вызываю

git add file1.txt

Однако, когда я звоню

git status -uno

Там написано

On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)

All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)

Changes to be committed:
modified:   text1.txt
modified:   text2.txt
new file:   text3.txt

Etc. Etc.

Почему он добавляет text2.txt и text3.txt в мой коммит?Я только что вытащил их из источника?

(к вашему сведению, я все это пишу и упростил для примера).Спасибо

1 Ответ

0 голосов
/ 07 июня 2018

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 оставил вработа дерево.Когда вы закончите объединение, вы должны:

  1. Оставить объединенную версию в рабочем дереве под именем text1.txt.
  2. Выполнить git add text1.txt.Это копирует версию из рабочего дерева в индекс, удаляя из индекса из трех версий более высокого уровня.

Теперь, когда в индексе есть только одна версия, котораяправильно слитый, готов к совершению.Между тем, text2.txt и text3.txt находятся также в индексе в нормальном (нулевая стадия) состоянии "готов к фиксации".Но так же каждый другой файл.

Вы видите эти три файла, но не другие файлы, потому что для этих трех файлов версия в индексе собрана и готова к следующему коммиту отличается от в текущем коммите.Для каждого другого файла в индексе значение совпадает с в текущем коммите, поэтому git status не сообщает «будет в коммите, но то же самое».

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