Почему git не может сбросить запрос - PullRequest
0 голосов
/ 05 марта 2019

Иногда я вхожу в облачный экземпляр, вытягиваю репо, а затем хочу попробовать пул-запрос.Команда, которую я сейчас использую, это

git fetch origin pull/<ID>/head && git checkout FETCH_HEAD

, что очень долго.Я также попробовал более короткие пути

git reset --hard origin/pull/<ID>
git reset --hard origin/pull/<ID>/head
git reset --hard origin/pull/<ID>/HEAD

, которые дают следующую ошибку

$ git reset --hard origin/pull/27
 fatal: ambiguous argument 'origin/pull/27': unknown revision
 or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Почему работает git reset --hard origin/<some-branch>, но не ветвь запроса на извлечение?

Я заметил, чтов выводе

$ git ls-remote origin

существует различие между обычной ветвью и ветвью запроса на извлечение.Например

c31a55 refs / heads / fix-async-stdout-order

615f5a refs / pull / 10 / head

Как работает heads отличается от pull?(Я сократил хеш здесь, чтобы он стал чище)

Ответы [ 2 ]

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

Каждый репозиторий Git имеет свои собственные копии имен.Каждое имя соответствует точно одному хеш-идентификатору, например, в вашем примере:

c31a55 refs/heads/fix-async-stdout-order
615f5a refs/pull/10/head

вы предложили, что refs/heads/fix-async-stdout-order сопоставляется с хэш-идентификатором c31a55 и refs/pull/10/head отображаются на хеш-код 615f5a. 1

Имена - это то, что Git вызывает refs или ссылка .(Хеш-идентификаторы - это хеши, с которыми вы должны быть хорошо знакомы.)

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

Когда имя идентифицирует коммит, мы можем использовать имя напрямуючтобы найти фиксацию: refs/heads/fix-async-stdout-order, например, идентифицирует фиксацию c31a55.Но коммиты также позволяют нам находить их непосредственные родительские коммиты: с c31a55 мы можем работать в обратном направлении к тому, кем является его родитель, и из этого родителя мы можем работать в обратном направлении, еще один шаг к другому коммиту, и так далее,вплоть до начала времен в хранилище.Таким образом, имя, подобное этому, служит не только для поиска одного коммита, чей хеш-идентификатор он хранит, но также всех более ранних коммитов в его цепочке .

Когда имя является branch name - как и этот - Git также позволяет нам использовать его специально с git checkout.Команда git checkout присоединяет другое специальное имя, HEAD, к имени ветви.Теперь Git считает нас «включенными» в ветке, поэтому, если мы сделаем новые коммиты, Git автоматически изменит идентификатор хеша, хранящийся под именем этой ветви .

То есть после:

git checkout fix-async-stdout-order

, если мы выполним некоторую работу, а затем сделаем новый коммит, имя fix-async-stdout-order - которое на самом деле refs/heads/fix-async-stdout-order, мы простосократил его для целей отображения - перестанет указывать на коммит c31a55 и вместо этого начнет указывать на наш новый коммит.Наш новый коммит будет иметь c31a55 в качестве родительского элемента.

Это свойство, позволяющее получать «на» ветке, разрешено только для branch имён.У Git много имен: имена веток, имена тегов, имена для удаленного отслеживания и так далее.Все они ссылки , но только ссылки, написание которых начинается с refs/heads/, являются именами ветвей.

Ссылка refs/tags/v1.2, если она существует, является тегом named v1.2.

Ссылкой refs/remotes/origin/master, если она существует, является имя удаленного отслеживания origin/master.

Каждый из этих префиксов - refs/heads/, refs/tags/ и refs/remotes/ - представляет пространство имен .Ссылки в пространстве имен refs/heads/ являются именами ветвей .

Помимо того, что они являются специальными с точки зрения разрешения git checkout использовать их описанным выше способом, другая особенность branch name появляется, когда клиентский Git, такой как ваш собственный Git, подключается к серверу Git.Сервер Git отображает для клиента все его имена, включая имена ветвей, а также хэш-идентификаторы, которые представляют эти имена. клиент Git копирует ответвления имен сервера, но меняет их одновременно, так что сервер вызывает refs/heads/masterклиент вызывает refs/remotes/origin/master.

Этот процесс позволяет вашему Git иметь имена для удаленного отслеживания.У сервера Git есть свои ветви, и ваш Git приходит вместе - когда вы запускаете git fetch - и видит, а затем запоминает их ветви как ваши имена для удаленного слежения origin/*.Они живут в вашем Git, в пространстве имен refs/remotes/.

Этот процесс происходитurs только для имен ветвей! 3 Поскольку refs/pull/10/head не начинается с refs/heads/, это не имя ветви.Процесс не распространяется на refs/pull/10/head.Вот почему и чем heads отличается от pull.


1 Это оба сокращенные хеш-идентификаторы;фактические хеш-идентификаторы в настоящее время всегда имеют длину 40 символов.

2 Предупреждение здесь заключается в том, что без имени можно найти коммит или другой объект Git,этот коммит или другой объект теперь незащищен от процесса сборки мусора в Git.Таким образом, не только имена позволяют нам находить последний коммит в цепочке, они также защищают этот коммит и всех его предшественников от вывоза в качестве мусора.

3 Процесс программируется через то, что Git называет refspecs .Вышеприведенное описание относится только к стандартным refspecs, которые вы получаете при запуске git clone.Если вы создаете свои собственные refspecs, вы можете изменить то, что происходит здесь.См. документацию git fetch и обратите внимание, что remote.origin.fetch является совокупной настройкой ;каждый экземпляр remote.origin.fetch предоставляет один refspec.

По умолчанию во время клонирования Git создает один параметр remote.origin.fetch, который либо копирует все их ветвей в ваше дистанционное отслеживаниеимена или копии одной их ветвей на одну имя для удаленного слежения, если вы выбрали --single-branch во время клонирования.

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

GitHub предлагает : git fetch origin pull/ID/head:BRANCHNAME: таким образом вы управляете соглашением об именах локальных ветвей вместо создания (из-за refspec по умолчанию для GitHub для PR)

Но у вас есть более продвинутые техники здесь :

[alias]
copr = "!f() { git fetch -fu ${2:-origin} refs/pull/$1/head:pr/$1 &&
                    git checkout pr/$1; }; f"

А затем:

$ git copr 1234            # gets and switches to pr/1234 from origin
$ git copr 789 upstream    # gets and switches to pr/789 from upstream

хаб также известен для обертыванияPR импорт.

...