У меня есть "основной" открытый репозиторий и "личный" голый репозиторий. Я хочу обновить формы изменений "main" до "personal", поэтому я запускаю:
$ git pull
fatal: /home/gimenero/applib/git/libexec/git-core/git-pull cannot be used without a working tree.
Как перенести изменения на "main"?
Ответ 1
A git pull
выполняет a fetch
, за которым следует merge
, и вы не можете объединиться без рабочего дерева. (Невозможно разрешить конфликты слияния, если они возникнут.)
Вместо этого вы можете просто извлечь. Предполагая, что ваш основной репозиторий настроен как удаленный названный источник в вашем личном репозитории:
$ git fetch origin master:master
Обратите внимание, что это будет успешным только в том случае, если главная ветка вашего личного хранилища зеркалирует основную ветвь основного репозитория. В противном случае Git отклонит выбор без быстрой перемотки вперед.
Ответ 2
Обновить с помощью:
$ git fetch origin +refs/heads/*:refs/heads/* --prune
Что это делает?
Сначала в сторону: когда мы говорим о ветке с именем "xyz", git фактически обращается к ней как к refs/heads/xyz
. Но вы можете ввести " xyz
" для краткости, потому что иначе это было бы безумием. (Между прочим, тегами являются refs/tags/xyz
.) Обычный xyz
является неоднозначным, поскольку это может быть ветвь, тег или первые N букв хеша коммита. refs/heads/xyz
с другой стороны, явно представляет собой ветвь.
Поэтому, даже если вы можете набрать git fetch origin foo:bar
чтобы захватить их ветку foo
качестве именованного bar
в вашем хранилище, вы можете более явно ввести git fetch origin refs/heads/foo:refs/heads/bar
чтобы сделать то же самое. (Хотя, если foo
самом деле был тегом, а не ветвью, последний потерпит неудачу, потому что их refs/heads/foo
не существуют. Явность ftw.)
git fetch origin refs/heads/*:refs/heads/*
означает, что все их ветки принадлежат нам. Команда запускается так, как будто часть *
заменяется именем их ветки для каждой из их ветвей. то есть git fetch origin refs/heads/abc:refs/heads/abc refs/heads/def:refs/heads/def...
(при условии, что они имеют ветки с именами abc
и def
).
Параметр --prune
означает, что все ветки, которые есть в нашем репозитории, которые соответствуют refs/heads/*
но не существуют в их репозитории, удаляются.
Наконец, префикс +
должен разрешать выборки без ускоренной перемотки вперед. Без этого любые обновления веток, требующие принудительного обновления, отклоняются.
Если сложить вместе, конечный результат состоит в том, что ветки в вашем хранилище выглядят точно так же, как и их.
Вот пример вывода:
- [deleted] (none) -> bar
* [new branch] foo -> foo
4812558a5f..a6aeec6517 abc -> abc
+ a1b2c3d4e5...1a2b3c4d5e def -> def (forced update)
- Пример говорит нам, что у них есть ветки
foo
, abc
, def
то время как у нас есть (был) один дополнительный: bar
- Обратите внимание на удаление
bar
помощью --prune
и принудительное обновление def
разрешенное префиксом +
.
Вот что происходит вместо этого, если +
и --prune
были отключены:
* [new branch] foo -> foo
4812558a5f..a6aeec6517 abc -> abc
! [rejected] def -> def (non-fast-forward)
Одна последняя вещь:
Сравните команду сверху со следующим:
$ git fetch origin +refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/* [--prune]
По сути, это то, что происходит, когда мы git fetch origin [--prune]
!