Как вытащить другую удаленную ветку и конфликты слияния - PullRequest
0 голосов
/ 20 марта 2019

Я использовал seed для запуска своего проекта и добавил изменения, сначала путем клонирования начального проекта, внесения изменений и изменения этого remote с origin на boilerplate, теперь, когда яПолучив проект для работы над мастером, я добавил свой собственный пульт дистанционного репо.Но я хочу иметь ветку для более новой версии проекта, и репозиторий шаблонов уже имеет удаленную ветку phaser3, которую я хочу в основном извлекать и заменять конфликты, чтобы я мог начать переход на новую версию.вот что я попробовал:

<b>➜  </b><b>dir</b> <b>git:(</b><b>master</b><b>)</b> git fetch boilerplate phaser3
From https://github.com/lean/phaser-es6-webpack
 * branch            phaser3    -> FETCH_HEAD
<b>➜  </b><b>dir</b> <b>git:(</b><b>master</b><b>)</b> git checkout phaser3
Branch &apos;phaser3&apos; set up to track remote branch &apos;phaser3&apos; from &apos;boilerplate&apos;.
Switched to a new branch &apos;phaser3&apos;
<b>➜  </b><b>dir</b> <b>git:(</b><b>phaser3</b><b>)</b> git pull
Already up to date.
<b>➜  </b><b>dir</b> <b>git:(</b><b>phaser3</b><b>)</b> git pull --rebase
Already up to date.
Current branch phaser3 is up to date.

Так что мне кажется, что я получил мою локальную ветвь phaser3 для отслеживания boilerplate/phaser3, но как мне теперь загрузить обновленный phaser3package.json и другие файлы, которые отличаются между двумя ветвями phaser3?

1 Ответ

0 голосов
/ 21 марта 2019

Кажется, здесь нет ничего неправильно .Тем не менее, в вашем выводе есть что-то слегка подозрительное, что говорит о том, что, возможно, вы используете Git версии 1.8.3 или более ранней, а может и нет.(Вы можете легко проверить это с помощью git --version. Если ваш Git до версии 2.0, возможно, пришло время обновить его. Текущий выпуск v2.21 на этот ответ.)

Интересная часть этого бита:

➜  dir git:(master) git fetch boilerplate phaser3
From https://github.com/lean/phaser-es6-webpack
 * branch            phaser3    -> FETCH_HEAD

Сравните это с тем, что я получаю, когда я git fetch origin master в моем репозитории Linux сегодня днем:

$ git fetch origin master
remote: Counting objects: 235, done.
remote: Compressing objects: 100% (160/160), done.
remote: Total 235 (delta 120), reused 124 (delta 71)
Receiving objects: 100% (235/235), 273.62 KiB | 230.00 KiB/s, done.
Resolving deltas: 100% (120/120), done.
From git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
 * branch                      master     -> FETCH_HEAD
   9e98c678c2d6..54c490164523  master     -> origin/master

Помимо дополнительной детализации (считая,сжатие, получение и т. д.), последние две строки очень важны:

 * branch                      master     -> FETCH_HEAD
   9e98c678c2d6..54c490164523  master     -> origin/master

Они показывают, что мой Git записал новый хэш-идентификатор в origin/master.В частности, до я бегал git fetch Я получил:

$ git rev-parse origin/master
9e98c678c2d6ae3a17cb2de55d17f69dddaa231b

После я бежал git fetch, я получил:

$ git rev-parse origin/master
54c490164523de90c42b1d89e7de3befe3284d1b

Это потому, что git fetch origin master обновлено два важных элементов в моем собственном репозитории Git.Одним из них является мое имя для удаленного отслеживания , refs/remotes/origin/master, обычно сокращенно origin/master.Другой файл - это специальный файл .git/FETCH_HEAD, который git fetch всегда пишет, основываясь на том, что вы сказали ему выбрать и что он получил от другого Git.

Ваш вывод показывает, что ваш Git обновляется только один из этих пунктов, а именно файл .git/FETCH_HEAD.Но это может быть нормально и не признак старой версии Git, потому что, если я сразу же после этого перезапущу тот же git fetch, это произойдет:

$ git fetch origin master
From git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
 * branch                      master     -> FETCH_HEAD

и это выглядит так же, как ваш собственный вывод.Поэтому я подозреваю, что ваш git fetch по сути ничего не сделал, так же, как мой второй git fetch, потому что не было ничего общего.Это привело бы к остальному поведению, которое вы видите.

Что здесь происходит

Ключ к пониманию того, что происходит - что делает git fetch, заключается в осознании этого имена веток не очень важны для Git .Для важно важно для Git каждый коммит .Каждый коммит уникально идентифицируется по его хеш-идентификатору , который выглядит случайным, но на самом деле является криптографической контрольной суммой его содержимого.

Коммит Git хранит снимок всех файлов вместе с некоторыми метаданными- некоторые данные о коммите.Метаданные включают имя и адрес электронной почты того, кто сделал коммит, , когда они сделали это (отметка времени), почему они сделали это (свое сообщение журнала), и - что крайне важно родительский хеш-код коммита .

Вот пример коммита из этого конкретного репозитория.Его хэш-идентификатор равен d1f0301b3333eef5efbfa1fe0f0edbea01863d5d:

$ git cat-file -p d1f0301b3333eef5efbfa1fe0f0edbea01863d5d | sed 's/@/ /'
tree 86c897e94952090eee579ed47f49cc7006c41fd6
parent 6b4703768268d09ac928c64474fd686adf4574f9
author Thomas Gleixner <tglx linutronix.de> 1533300299 +0200
committer Thomas Gleixner <tglx linutronix.de> 1533302341 +0200

genirq: Make force irq threading setup more robust

The support of force threading interrupts which are set up with both a
primary and a threaded handler wreckaged the setup of regular requested
threaded interrupts (primary handler == NULL).

[snip]

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

В результате, учитывая некоторый хэш-идентификатор коммита Git, Git всегда может найти коммит, который приходит до , которые совершают.Фактически родительская строка указывает на другую, более раннюю фиксацию.Поэтому, если у нас есть длинная цепочка коммитов:

... <-F <-G <-H ...

, мы можем выбрать один из этих коммитов и следовать за его стрелкой назад к предыдущему коммиту: от H до Gи затем F и т. д.

проблема в том, что эти хэш-идентификаторы кажутся совершенно случайными и частично зависят от того, в какое время, с точностью до секунды, кто-то их создал. Например, Томас Глейкснер сделал вышеупомянутый коммит во время 1533300299 +0200. 1 Вся эта деталь входит в хэш-идентификатор коммита. Это означает, что у нас нет возможности узнать, каким будет хеш-идентификатор - это эффективно случайно. Итак, как мы узнаем, какой коммит является последним коммитом?

Ответ в том, что Git помогает нам, позволяя us создавать имена ветвей . Мы говорим Git: хранить новейший / последний идентификатор хеша коммита под некоторым именем, например master или phaser3. Учитывая ID , Git может найти коммит . Этот коммит хранит идентификатор родителя, поэтому Git также может найти родителя. Родитель хранит другой родительский идентификатор - как бы прародителя этого коммита - так что Git может найти деда, а этот коммит сохраняет другой родительский идентификатор и т. Д. В истории.

История, по сути, является не чем иным, как набором коммитов, найденных при переходе от каждого коммита к его родителю (-ям). Посещенные коммиты, начиная с некоторого набора начальных точек и работающих в обратном направлении, являются историей в репозитории Git. Начальными точками являются все имена в хранилище: имена веток, имена тегов, такие как v2.1 и имена удаленного отслеживания , такие как origin/master или boilerplate/phaser3. 2


1 Ну, вот тогда он создал (оригинальную версию) коммит, но потом он совершил коммит в 1533302341, 34 минуты и 2 секунды спустя.

2 Хранилище может и после различных операций, таких как git rebase или git commit --amend , будет , содержать коммиты, которые не посещаются этим пройти все достижимые коммиты, начав с какого-то процесса . Эти оставшиеся или ненужные коммиты в конечном итоге очищаются и выбрасываются сборщиком мусора Git , git gc. Обратите внимание, что git gc делает много других дел, связанных с ведением домашнего хозяйства и улучшением производительности, или, по крайней мере, для улучшения производительности. Все это делается автоматически - обычно нет необходимости запускать его вручную.


Checkout создает ветки, иногда

Вы запустили git checkout phaser3, и ваш Git сказал это:

Branch 'phaser3' set up to track remote branch 'phaser3' from 'boilerplate'.
Switched to a new branch 'phaser3'

Обычно, когда вы говорите git checkout <em>somebranch</em>, Git просматривает в вашем хранилище для вашей ветви с именем somebranch. Это имя ветви идентифицирует новейший / последний коммит, который следует считать tip ветви. Ваш Git извлекает данные, которые фиксируются в вашем индексе и рабочем дереве, чтобы вы могли видеть его и работать с ним.

Иногда, однако, вы говорите Git проверить ветку, а у вас нет этой ветви . Вместо того, чтобы просто потерпеть неудачу - что все еще может произойти:

$ git checkout nosuchbranch
error: pathspec 'nosuchbranch' did not match any file(s) known to git

- ваш Git начинает с перечисления ваших собственных веток, а git branch:

$ git branch
* master

Запрошенного вами имени нет в списке, но Git еще не готов отказаться. Теперь он проверяет все ваши имена для удаленного отслеживания , которые вы можете перечислить с помощью git branch -r. Результат этого зависит от того, какие пультов у вас есть - у большинства людей есть только один, с именем origin, в своих хранилищах - и от каких имен ваш Git запоминает из эти пульты:

$ git branch -r
  origin/develop
  origin/feature2
  origin/master
  upstream/master
  upstream/develop

Я попросил nosuchbranch, и ни один из них не выглядит так. Но что, если я попросил, скажем, feature2?

Git просканирует их, и будет точно одно имя, соответствующее feature2, а именно origin/feature2. Так что мой Git сказал бы: Ага, вы хотите, чтобы я создал новый feature2, используя origin/feature2 в качестве коммита! И теперь у меня может быть:

... <-H <-I <-J   <-- feature2 (HEAD), origin/feature2

с именами feature2 и origin/feature2 оба с запоминанием хеш-идентификатора коммита J.

Обратите внимание, чтов этой конкретной ситуации - где у меня нет develop, но у обоих origin и upstream есть один - если я запускаю:

git checkout develop

мой Git сдается, потому что он не знает, должен ли он сделать новый develop из origin/develop или из upstream/develop. Даже если они оба идентифицируют один и тот же коммит, скажем, коммит L, который я не нарисовал здесь на диаграмме - мой Git не знает, какой из этих двух использовать в качестве вверх по течению настройка для моего нового develop. Вместо этого я могу сделать следующее:

git checkout --track origin/develop

, который сообщает моему Git: Используя origin/develop, создайте новый develop, где develop обновляется и отправляется origin * develop.

Мы продвинулись очень быстро и не очень подробно , как все это работает, но я еще раз упомяну здесь, что это устанавливает настройку upstream недавно созданной ветви. Восходящий поток ветки - это то, как Git решает сказать «впереди» и / или «позади», когда вы запускаете git status, и как Git знает, какой коммит использовать, если вы запускаете git merge или git rebase без аргументов. Восходящий поток определяет, что будут делать git pull или git push, если вы не предоставите дополнительных аргументов, и какой пульт git fetch будет использовать, когда у вас более одного пульта. Таким образом, настройка upstream довольно полезна.

Резюме

git pull --rebase ничего не делает, потому что новых коммитов нет: ваш график выглядит так, когда я рисую так, как мне нравится рисовать коммиты в StackOverflow:

...--G--H   <-- phaser3 (HEAD), boilerplate/phaser3

или, возможно, так:

...--G--H   <-- boilerplate/phaser3
         \
          I   <-- phaser3

Работа, которую выполняет git rebase, заключается в копировании коммитов, которые у вас есть, таких как - I на этой диаграмме, - в новые коммиты, которые приходят после их последнего коммита. В этом случае это будет копировать I в новый коммит, который идет сразу после H вместо того, где I сейчас , но I уже сразу после H, поэтому нет необходимости делать такое копирование. (И в ситуации, когда оба имени указывают на один и тот же коммит H, нет никакого коммита для копирования, что также означает, что не нужно выполнять какую-либо работу.)

вверх по течению из phaser3 равно boilerplate/phaser3. Имя boilerplate само по себе - обычно - просто короткое имя для https://github.com/lean/phaser-es6-webpack; Git называет это удаленным .

Есть полный репозиторий Git на https://github.com/lean/phaser-es6-webpack; у него четыре собственные ветви. Ваш репозиторий скопировал свою ветвь phaser3 - хэш-идентификатор c9584e75521a3b94d4f883a246aad134b83dc12d, хранящийся под этим именем, то есть - в ваше собственное имя remote-tracking , boilerplate/phaser3.

Команды git fetch и git push - это команды, которые передают коммиты из одного хранилища в другое. В общем, отправитель отправляет коммиты, которых у получателя еще нет, так что, в конце концов, у получателя есть все, что есть у отправителя, плюс, может быть, больше, если у него уже есть вещи, которых у отправителя нет. Отправив коммиты от отправителя к получателю, теперь получателю необходимо обновить имя или имена , чтобы запомнить новые коммиты.

При использовании git fetch получатель - вы! - вернее, ваш Git - обновляет ваши имена для удаленного слежения . Вы берете их имя, phaser3, и добавляете префикс к вашему удаленному имени, boilerplate, и вставляете косую черту между ними. Это дает вам boilerplate/phaser3 как способ запомнить их коммит.

При использовании git push отправитель - вы снова - отвечает за запрос получателя установить какое-либо имя в получателе. Вы выбираете, какое имя вы просите их установить Если это имя, скажем, phaser3, вы просите их изменить их phaser3. У них нет имени для удаленного слежения: здесь нет quantum_spaghetti/phaser3. Вы просите их изменить их имя. В общем, вы должны убедиться, что независимо от того, какие новые коммиты вы им отправили, эти новые коммиты имеют свои существующие коммиты как часть истории.

...