Как вытащить другую удаленную ветку и объединить конфликты

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

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

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


person Quantum Spaghetti    schedule 20.03.2019    source источник
comment
Какой результат git status?   -  person isherwood    schedule 20.03.2019
comment
Я считаю, что разницы нет. Что заставляет вас думать, что есть? Вы проверили нужную ветку.   -  person isherwood    schedule 20.03.2019
comment
dir git: (phaser3) git status В ветке phaser3 В вашей ветке установлена ​​последняя версия 'шаблона / phaser3'. нечего делать, рабочее дерево чистое   -  person Quantum Spaghetti    schedule 20.03.2019
comment
основная ветка, которую я проверил, изначально поддерживает Phaser2, в readme репозитория github он указывает ветку phaser3 для более новой версии, и переход к этой ветке показывает, что это: Эта ветка на 5 коммитов впереди, 32 коммитов позади master. Это заставляет меня думать, что между двумя шаблонными ветвями должны быть некоторые изменения файлов, и я хочу захватить их и перетащить в свою локальную ветку phaser3.   -  person Quantum Spaghetti    schedule 20.03.2019
comment
Вероятно, есть изменения между phaser2 и phaser3, но как вы думаете, почему существует разница между phaser3 и boilerplate/phaser3?   -  person isherwood    schedule 20.03.2019
comment
Попробуйте это: git diff phaser3 boilerplate/phaser3.   -  person isherwood    schedule 20.03.2019
comment
@isherwood, вот в чем проблема - на самом деле здесь нет различий, но я ожидаю, что это произойдет, поскольку я перешел от своего основного шаблона отслеживания / мастера к новому шаблону отслеживания локальных ветвей / phaser3, но я, похоже, не могу достать шаблон / phaser3, и нет никакой разницы в статусе git. Я мог либо неправильно сконфигурировать, либо пропустить шаг, но то, что я ожидаю, и то, что находится в репо, отличаются.   -  person Quantum Spaghetti    schedule 20.03.2019
comment
re: Попробуйте следующее: git diff phaser3 boilerplate/phaser3|cat Я получаю длинный пустой вывод, и передача его в cat ни к чему не приводит   -  person Quantum Spaghetti    schedule 20.03.2019
comment
Я предполагаю, что вы неправильно понимаете то, что вам следует увидеть. Вы смотрели фактическую кодовую базу на предмет изменений?   -  person isherwood    schedule 20.03.2019
comment
@isherwood да, я уверен, что это недоразумение, и я не уверен, с чего начать. Фактическая кодовая база имеет четкие и ясные изменения даже в package.json, которые, как я ожидал, побудят мой локальный экземпляр git обнаружить несоответствие и позволить мне запустить слияние. ссылка на шаблон   -  person Quantum Spaghetti    schedule 20.03.2019
comment
Трудно понять описание вашего вопроса. Есть некоторая двусмысленность в том, что где. Вы можете внести изменения, чтобы удалить все, что не является строго актуальным, и немного уточнить. Судя по отсутствию ответов на популярную тему, я не единственный в этом вопросе нечетко.   -  person isherwood    schedule 20.03.2019
comment
@isherwood, ты, наверное, прав, я тоже запутался, и я не знаю, как уточнить, какая часть является проблемой, а что не имеет отношения. Это то, что обычно происходит, когда я схожу с проторенного пути с помощью git, а затем я просто клонирую несколько экземпляров, вырезая и вставляя, пока это не сработает.   -  person Quantum Spaghetti    schedule 20.03.2019


Ответы (1)


Кажется, здесь нет ничего неправильного. Тем не менее, в вашем выводе есть что-то слегка подозрительное, что говорит о том, что, возможно, вы используете 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, и эти compare коммиты с более ранними коммитами, чтобы мы могли видеть, что отличается в два снимка. Это похоже на сравнение того, насколько тепло или дождливо сегодня, с тем, насколько тепло или дождливо было вчера: это говорит нам, что изменилось, что иногда для нас важнее, чем абсолютное состояние. Но это действительно показывает, что находится в коммите: у него есть дерево (с некоторым внутренним хеш-идентификатором Git), родительский с другим хеш-идентификатором коммита, а также автор и коммиттер. и сообщение журнала. (Некоторые коммиты содержат больше материала.) Дерево - это то, как Git хранит снимок. Строка parent сообщает нам, какая фиксация происходит до этой фиксации.

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

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

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

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

Ответ заключается в том, что Git помогает нам, позволяя нам создавать имена веток. Мы говорим 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 gc Git. Обратите внимание, что git gc выполняет множество других функций по уборке и повышению производительности, или, по крайней мере, для повышения производительности. Все это делается автоматически - обычно нет необходимости запускать это вручную.


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

Вы запустили git checkout phaser3, и ваш Git сказал следующее:

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

Обычно, когда вы говорите git checkout somebranch, Git ищет в вашем репозитории вашу ветку с именем somebranch. Это имя ветки определяет самый новый / последний коммит, который следует рассматривать как наконечник ветки. Ваш 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 не знает, какой из этих двух использовать в качестве восходящего потока < / em> настройка для моего нового develop. Вместо этого я могу сделать следующее:

git checkout --track origin/develop

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

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

Резюме

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, хранящийся под этим именем, то есть - в ваше собственное имя удаленного отслеживания, boilerplate/phaser3.

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

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

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

person torek    schedule 20.03.2019