Кажется, здесь нет ничего неправильного. Тем не менее, в вашем выводе есть что-то слегка подозрительное, что говорит о том, что, возможно, вы используете 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 sup >
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 запоминает из em> эти пульты:
$ 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
git status
? - person isherwood   schedule 20.03.2019phaser2
иphaser3
, но как вы думаете, почему существует разница междуphaser3
иboilerplate/phaser3
? - person isherwood   schedule 20.03.2019git diff phaser3 boilerplate/phaser3
. - person isherwood   schedule 20.03.2019git diff phaser3 boilerplate/phaser3|cat
Я получаю длинный пустой вывод, и передача его в cat ни к чему не приводит - person Quantum Spaghetti   schedule 20.03.2019