Как я могу согласовать отделенную головку с мастером / источником?

Я новичок в ветвящихся сложностях Git. Я всегда работаю над одной веткой и фиксирую изменения, а затем периодически нажимаю на мое удаленное начало.

Где-то недавно я сделал сброс некоторых файлов, чтобы вывести их из стадии фиксации, а позже сделал rebase -i чтобы избавиться от пары недавних местных коммитов. Сейчас я нахожусь в состоянии, которое я не совсем понимаю.

В моей рабочей зоне git log показывает именно то, что я ожидал - я на правильном поезде с коммитами, которые я не хотел, и новыми там и т. д.

Но я только что отправил в удаленный репозиторий, и тут есть что-то другое - пара коммитов, которые я убил в ребазе, были перенесены, а новых, зафиксированных локально, там нет.

Я думаю, что "master/origin" отделен от HEAD, но я не на 100% уверен в том, что это значит, как визуализировать его с помощью инструментов командной строки и как это исправить.

28 ответов

Решение

Во-первых, давайте выясним, что такое HEAD и что он означает, когда он отсоединен.

HEAD - это символическое имя для текущего извлеченного коммита. Когда HEAD не отсоединен ("нормальная" 1 ситуация: у вас есть ветвь извлечена), HEAD фактически указывает на "ref" ветки, а ветвь указывает на коммит. Таким образом, HEAD "привязан" к ветке. Когда вы делаете новый коммит, ветка, на которую указывает HEAD, обновляется, чтобы указывать на новый коммит. HEAD следует автоматически, так как он просто указывает на ветку.

  • git symbolic-ref HEAD доходность refs/heads/master
    Ветка с именем "мастер" извлечена.
  • git rev-parse refs/heads/master Уступать 17a02998078923f2d62811326d130de991d1a95a
    Этот коммит является текущим наконечником или "головой" главной ветви.
  • git rev-parse HEAD также дает 17a02998078923f2d62811326d130de991d1a95a
    Это то, что значит быть "символическим реф". Он указывает на объект через какую-то другую ссылку.
    (Символические ссылки изначально были реализованы как символические ссылки, но позже были заменены простыми файлами с дополнительной интерпретацией, чтобы их можно было использовать на платформах, которые не имеют символических ссылок.)

У нас есть HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

Когда HEAD отсоединен, он указывает непосредственно на коммит, а не косвенно указывает на один через ветвь. Вы можете думать об отделенной ГОЛОВЕ как о неназванной ветви.

  • git symbolic-ref HEAD не удается с fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD доходность 17a02998078923f2d62811326d130de991d1a95a
    Поскольку это не символьная ссылка, он должен указывать непосредственно на коммит.

У нас есть HEAD17a02998078923f2d62811326d130de991d1a95a

Важно помнить при использовании отдельного HEAD, что если на коммит, на который он указывает, в противном случае нет ссылки (ни один другой реф не сможет его достичь), то он станет "висящим", когда вы извлекаете какой-то другой коммит. В конечном итоге такие оборванные коммиты будут удалены в процессе сборки мусора (по умолчанию они хранятся не менее 2 недель и могут храниться дольше, если на них ссылается reflog HEAD).

1 Совершенно нормально выполнять "обычную" работу с отдельным HEAD, вам просто нужно следить за тем, что вы делаете, чтобы не выискивать выпавшую историю из reflog.


Промежуточные шаги интерактивной перебазировки выполняются с помощью отдельного HEAD (частично, чтобы не загрязнять рефлог активной ветки). Если вы завершите полную операцию перебазирования, она обновит вашу исходную ветвь с совокупным результатом операции перебазирования и снова присоединит HEAD к исходной ветке. Я предполагаю, что вы никогда полностью не завершили процесс ребазирования; это оставит вас с отключенным HEAD, указывающим на коммит, который был недавно обработан операцией rebase.

Чтобы выйти из вашей ситуации, вы должны создать ветку, которая указывает на коммит, на который в данный момент указывает ваша отдельная голова:

git branch temp
git checkout temp

(эти две команды могут быть сокращены как git checkout -b temp )

Это присоединит вашу ГОЛОВУ к новой temp ветка.

Затем вы должны сравнить текущий коммит (и его историю) с обычной веткой, над которой вы ожидали работать:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(Возможно, вы захотите поэкспериментировать с параметрами журнала: добавить -p, перестань --pretty=… просмотреть все сообщения журнала и т. д.)

Если ваш новый temp ветка выглядит хорошо, вы можете обновить (например) master указать на это:

git branch -f master temp
git checkout master

(эти две команды могут быть сокращены как git checkout -B master temp )

Затем вы можете удалить временную ветку:

git branch -d temp

Наконец, вы, вероятно, захотите нажать на восстановленную историю:

git push origin master

Вам может понадобиться добавить --force до конца этой команды нажать, если удаленная ветвь не может быть "быстро перенаправлена" к новому коммиту (т. е. вы удалили, или переписали какой-то существующий коммит, или иным образом переписали некоторый фрагмент истории).

Если вы выполняли операцию перебазирования, вам, вероятно, следует ее очистить. Вы можете проверить, выполнялась ли перебазировка, ища каталог .git/rebase-merge/, Вы можете вручную очистить выполняющуюся перебазировку, просто удалив этот каталог (например, если вы больше не помните цель и контекст активной операции перебазировки). Обычно вы бы использовали git rebase --abort, но это делает некоторый дополнительный сброс, который вы, вероятно, хотите избежать (он перемещает HEAD обратно в исходную ветвь и сбрасывает его обратно в исходный коммит, что отменит часть работы, которую мы проделали выше).

Просто сделай это:

git checkout master

Или, если у вас есть изменения, которые вы хотите сохранить, сделайте это:

git checkout -b temp
git checkout -B master temp

Я столкнулся с этой проблемой, и когда я прочитал в верхнем голосовании ответ:

HEAD - это символическое имя для текущего извлеченного коммита.

Я подумал: ах-ха! Если HEAD является символическим именем для проверки текущей валюты, я могу согласовать его с master опровергнув его master:

git rebase HEAD master

Эта команда:

  1. проверяет master
  2. идентифицирует родительские коммиты HEAD вернуться к сути HEAD отклонился от master
  3. играет эти коммиты поверх master

Конечным результатом является то, что все коммиты, которые были в HEAD но нет master затем также в master, master остается проверенным.


По поводу пульта:

несколько коммитов, которые я убил в ребазе, были перенесены, а новых, зафиксированных локально, там нет.

Удаленную историю больше нельзя пересылать с использованием локальной истории. Вам нужно будет принудительно нажать (git push -f) перезаписать удаленную историю. Если у вас есть соавторы, обычно имеет смысл согласовать это с ними, чтобы все были на одной странице.

После нажатия master к удаленному origin, ваша ветка удаленного слежения origin/master будет обновлен, чтобы указать на тот же коммит master,

Смотрите здесь для основного объяснения отстраненной головы:

http://git-scm.com/docs/git-checkout

Командная строка для визуализации:

git branch

или же

git branch -a

вы получите вывод, как показано ниже:

* (no branch)
master
branch1

* (no branch) показывает, что вы в отстраненной голове.

Вы могли бы прийти в это состояние, выполнив git checkout somecommit и т.д., и он предупредил бы вас следующим:

Вы находитесь в состоянии "отсоединенная ГОЛОВА". Вы можете осмотреться, внести экспериментальные изменения и зафиксировать их, а также можете отменить любые коммиты, сделанные вами в этом состоянии, не влияя на какие-либо ветви, выполнив другую проверку.

Если вы хотите создать новую ветку для сохранения созданных вами коммитов, вы можете сделать это (сейчас или позже), снова используя -b с командой checkout. Пример:

git checkout -b new_branch_name

Теперь, чтобы получить их на мастера:

Сделать git reflog или даже просто git log и запишите ваши коммиты. Сейчас git checkout master а также git merge коммиты.

git merge HEAD@{1}

Редактировать:

Чтобы добавить, используйте git rebase -i не только для удаления / уничтожения коммитов, которые вам не нужны, но и для их редактирования. Просто укажите "изменить" в списке коммитов, и вы сможете изменить свой коммит, а затем выпустить git rebase --continue идти вперед. Это гарантировало бы, что вы никогда не заходите на отдельную ГОЛОВУ.

Получите ваш отдельный коммит на свою ветку

Просто беги git checkout -b mynewbranch,

Тогда беги git logи вы увидите, что коммит сейчас HEAD на этой новой ветке.

Я нашел этот вопрос при поиске You are in 'detached HEAD' state.

Проанализировав, что я сделал, чтобы попасть сюда, по сравнению с тем, что я делал в прошлом, я обнаружил, что совершил ошибку.

Мой нормальный поток:

git checkout master
git fetch
git checkout my-cool-branch
git pull

На этот раз я сделал:

git checkout master
git fetch
git checkout origin/my-cool-branch
# You are in 'detached HEAD' state.

Проблема в том, что я случайно сделал:

git checkout origin/my-cool-branch

Скорее, чем:

git checkout my-cool-branch

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

git checkout my-cool-branch
git pull

Если у вас есть только мастер ветка и вы хотите вернуться к "разработке" или функции, просто сделайте это:

git checkout origin/develop

Примечание: проверка происхождения / разработки.

Вы в отдельном состоянии ГОЛОВА. Вы можете осмотреться, внести экспериментальные изменения и зафиксировать их, и вы можете отменить любые коммиты, которые вы делаете в этом состоянии, не влияя ни на какие ветви, выполнив другую проверку...

затем

git checkout -b develop

Оно работает:)

Если вы хотите подтолкнуть вашу текущую отдельную ГОЛОВКУ (проверьте git log до), попробуйте:

git push origin HEAD:master

отправить свою отдельную ГОЛОВУ в главную ветку в источнике. Если ваш толчок отклонен, попробуйте git pull origin master сначала получить изменения от происхождения. Если вас не волнуют изменения от источника, и они отклонены, потому что вы сделали некоторую преднамеренную перебазировку и хотите заменить origin/master своей отсоединенной в данный момент веткой - тогда вы можете форсировать ее (-f). Если вы потеряли доступ к предыдущим коммитам, вы всегда можете запустить git reflog чтобы увидеть историю из всех отраслей.


Чтобы вернуться в основную ветку, сохраняя изменения, попробуйте следующие команды:

git rebase HEAD master
git checkout master

Смотрите: Git: "В настоящее время нет ни на одной ветке". Есть ли простой способ вернуться на ветку, сохранив изменения?

У меня сработало следующее (используя только ветку master):

git push origin HEAD:master
git checkout master        
git pull

Первый толкает отсоединенную ГОЛОВУ к удаленному источнику.

Второй переходит к мастеру ветки.

Третий восстанавливает ГОЛОВУ, которая присоединяется к мастеру ветвления.

Проблемы могут возникнуть при первой команде, если толчок отклонен. Но это больше не будет проблемой отсоединенной головки, а связано с тем фактом, что отсоединенная головка не знает о некоторых удаленных изменениях.

Я только что столкнулся с этой проблемой сегодня и уверен, что решил ее, выполнив:

git branch temp
git checkout master
git merge temp

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

Если вы абсолютно уверены, что HEAD - это хорошее состояние:

git branch -f master HEAD
git checkout master

Вы, вероятно, не можете подтолкнуть к происхождению, так как ваш мастер отклонился от источника. Если вы уверены, что никто не использует репо, вы можете принудительно нажать:

git push -f

Наиболее полезно, если вы находитесь в функциональной ветке, которой никто не пользуется.

Все, что вам нужно сделать, это "git checkout [имя-ветви]", где [имя-ветви] - это имя исходной ветви, из которой вы попали в состояние отсоединенного заголовка. (Отдельно от asdfasdf) исчезнет.

Так, например, в ветке 'dev' вы извлекаете коммит asdfasd14314 ->

'git checkout asdfasd14314'

вы сейчас находитесь в отстраненном состоянии

'git branch' перечислит что-то вроде ->

* (detached from asdfasdf)
  dev
  prod
  stage

но выйти из состояния оторванной головы и вернуться к dev ->

'git checkout dev'

и тогда 'git branch' отобразит список ->

* dev
  prod
  stage

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

Как указал Крис, у меня была следующая ситуация

git symbolic-ref HEAD не удается с fatal: ref HEAD is not a symbolic ref

тем не мение git rev-parse refs/heads/master указывал на хороший коммит, откуда я мог восстановить (в моем случае последний коммит, и вы можете увидеть этот коммит, используя git show [SHA]

После этого я сделал много грязных вещей, но то, что, похоже, исправило, это просто

git symbolic-ref HEAD refs/heads/master

И голова прикреплена!

если вы хотите сохранить изменения, внесенные в отдельную головку, просто сделайте следующее: создайте временную ветвь и зафиксируйте ее с внесенными изменениями, а затем перейдите в YOUR-BRANCH и объедините временную ветвь с ней. Наконец, удалите временную ветку.

      git checkout -b temp
git add . && git commit -m 'save changes'
git checkout YOUR-BRANCH
git merge temp
git branch -d temp

Вместо того чтобы делать git checkout origin/master

просто делать git checkout master

затем git branch will confirm your branch.

У меня была та же проблема, и я решил ее, выполнив следующие шаги.

Если вам нужно сохранить ваши изменения

  1. Сначала нужно бежать git checkout master команда вернуть вас в основную ветку.
  2. Если вам нужно сохранить ваши изменения, просто запустите git checkout -b changes а также git checkout -B master changes

Если вам не нужны ваши изменения

  1. Чтобы удалить все неотслеживаемые файлы из вашей ветки, запустите git clean -df,

  2. Затем вам нужно очистить все неустановленные изменения в вашем хранилище. Для этого нужно бежать git checkout --

  3. Наконец, вы должны вернуть свою ветку в основную ветку, используя git checkout master команда.

Для меня это было так же просто, как снова удалить локальную ветку, так как у меня не было локальных коммитов, которые я хотел нажать:

Так я и сделал:

git branch -d branchname

А затем снова проверяем ветку:

git checkout branchname

Если вы сделали несколько коммитов поверх мастера и просто хотите "слить назад" master там (то есть вы хотите master указать на HEAD), однострочник будет:

git checkout -B master HEAD
  1. Это создает новую ветку с именем master, даже если он уже существует (что похоже на перемещение master и это то, что мы хотим).
  2. Вновь созданная ветвь будет указывать на HEAD, где вы находитесь.
  3. Новая ветка проверена, поэтому вы находитесь на master после этого.

Я нашел это особенно полезным в случае суб-репозиториев, которые также довольно часто оказываются в отключенном состоянии.

У меня была эта проблема сегодня, когда я обновил подмодуль, но не был ни в одной ветке. Я уже совершил, так что копить, проверять, расстегивать не получится. Я закончил тем, что выбрал коммит из оторванной головы. Так что сразу после того, как я совершил (когда толчок не удался), я сделал:

git checkout master
git cherry-pick 99fe23ab

Мое мышление пошло: я нахожусь на отдельной голове, но я хочу быть на хозяине. Предполагая, что мое отсоединенное состояние не очень отличается от мастера, если бы я мог применить свой коммит к мастеру, я был бы настроен. Это именно то, что делает вишня.

Когда я лично оказываюсь в ситуации, когда оказывается, что я внес некоторые изменения, пока я не в master (т.е. HEAD отделен прямо над master и между ними нет коммитов) может помочь запоминание:

git stash # HEAD has same content as master, but we are still not in master
git checkout master  # switch to master, okay because no changes and master
git stash apply  # apply changes we had between HEAD and master in the first place

Самое простое решение - создать новую ветку,

      git checkout -b new-branch-name

затем проверьте журналы фиксации с помощью команды,

      git log

если все совпадает, выйти: q

теперь отправьте все свои изменения в новую ветку по команде

      git push --set-upstream origin new-branch-name

Теперь, когда проблема решена и ваш локальный git HEAD прикреплен к новой ветке, вы можете поднять запрос на вытягивание с портала.

Проще говоря, состояние отсоединенного HEAD означает, что вы не зачислены на HEAD (или в наконечник) какой-либо ветви.

Понять с примером

Ветвь в большинстве случаев является последовательностью нескольких коммитов, таких как:

Фиксация 1: master ->branch_HEAD(123be6a76168aca712aea16076e971c23835f8ca)

Фиксация 2: мастер ->123be6a76168aca712aea16076e971c23835f8ca ->branch_HEAD(100644a76168aca712aea16076e971c23835f8ca)

Как вы можете видеть выше в случае последовательности коммитов, ваша ветвь указывает на ваш последний коммит. Таким образом, в этом случае, если вы извлекаете заявку на фиксацию 123be6a76168aca712aea16076e971c23835f8ca, то вы будете в состоянии отдельного заголовка, поскольку HEAD вашей ветви указывает на 100644a76168aca712aea16076e971c23835f8ca, и технически вы проверены в HEAD ни одной ветви. Следовательно, вы находитесь в отсоединенном состоянии HEAD.

Теоретическое объяснение

В этом блоге четко указано, что Git-репозиторий является деревом коммитов, причем каждый коммит, указывающий на своего предка, обновляется с каждым указателем коммита, и эти указатели на каждую ветку хранятся в подкаталогах.git/refs. Теги хранятся в.git/refs/tags, а ветки хранятся в.git/refs/head. Если вы посмотрите на любой из файлов, то обнаружите, что каждый тег соответствует одному файлу с хешем фиксации из 40 символов, и, как объяснено выше @Chris Johnsen и @Yaroslav Nikitenko, вы можете проверить эти ссылки.

Это сработало для меня отлично:

1.git stash сохранить ваши локальные модификации

Если вы хотите отменить изменения
git clean -df
git checkout -- .
git clean удаляет все неотслеживаемые файлы (предупреждение: хотя он не удаляет проигнорированные файлы, упомянутые непосредственно в.gitignore, он может удалять игнорируемые файлы, находящиеся в папках), а git checkout удаляет все неотмеченные изменения.

2.git checkout master переключиться на основную ветку (при условии, что вы хотите использовать мастер)
3.git pull вытащить последний коммит из ветки master
4.git status чтобы проверить все выглядит отлично

On branch master
Your branch is up-to-date with 'origin/master'.

Если вы используете EGit в Eclipse: предположите, что ваш мастер - ваша основная ветка разработки

  • зафиксировать изменения в ветке, обычно новую
  • затем вытащить из пульта
  • затем щелкните правой кнопкой мыши узел проекта, выберите команду, затем выберите Показать историю
  • затем щелкните правой кнопкой мыши мастер, выберите проверить
  • если Eclipse скажет вам, что есть два мастера один локальный один удаленный, выберите удаленный

После этого вы сможете снова подключиться к origin-master.

В моем случае я побежал git status, и я увидел, что у меня есть несколько неотслеживаемых файлов в моем рабочем каталоге.

Чтобы заставить ребейс работать, мне просто нужно было их почистить (так как они мне не нужны).

Я попал в действительно глупое состояние, я сомневаюсь, что кто-то еще найдет это полезным.... но на всякий случай

git ls-remote origin
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        HEAD
6f96ad0f97ee832ee16007d865aac9af847c1ef6        refs/heads/HEAD
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        refs/heads/master

который я в конце концов исправил

git push origin :HEAD

У меня такая же проблема. Я прячу свои изменения с git stash и жестко сбросить ветку в локальной к предыдущему коммиту (я думал, что это вызвало это) затем сделал git pull и я не отрываю эту голову сейчас. Не забывай git stash apply чтобы ваши изменения снова.

git checkout checksum  # You could use this to peek previous checkpoints
git status # You will see HEAD detached at checksum
git checkout master # This moves HEAD to master branch
Другие вопросы по тегам