Потерянные git данные после оформления заказа из «отсоединенного ГОЛОВА» - PullRequest
0 голосов
/ 17 марта 2020

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

git add *
git commit -m "comment"

Я пытался использовать git push, но я получил

роковым: вы в настоящее время не находитесь на ветке.
То пу sh история, ведущая к текущий (отсоединенный HEAD)

Я использую git checkout master, и изменения были возвращены для фиксации ветки master, удаленная ветвь HEAD была удалена, и я не знаю, как вернуть потерянный код.

Ответы [ 3 ]

2 голосов
/ 17 марта 2020

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

Затем используйте git checkout <commit> до go назад к отделенной ГОЛОВКЕ. Лучше всего вместо этого запустить git checkout -b foo <commit>, чтобы создать локальную ветвь foo из коммита, чтобы можно было отслеживать коммит. Эта команда равна git branch foo <commit> && git checkout foo.

Если вы действительно намеревались сделать новый коммит на master, после того как вы найдете коммит, вы можете выбрать его непосредственно на master, git checkout master && git cherry-pick <commit> .

Если вы действительно хотите поместить sh отдельную HEAD в ветку, вам нужно указать пульт и номер c вместо простого git push.

git pull origin -r foo   # before push, pull first to avoid non-fast-forward error
                         # -r is recommended to do a rebase pull
git push origin HEAD:foo # push the detached HEAD in the local repository to "foo" in "origin" 
1 голос
/ 17 марта 2020

(суммируя информацию в других ответах)

Ваш коммит не потерян, его можно найти с помощью git reflog:

# Here is a sample output :
# your commit should appear as 'HEAD@{xx}: commit: comment'
#    ('comment' is the commit message you used)
$ git reflog
f9a32813c (HEAD -> master) HEAD@{0}: checkout: moving from 92e0cd0c6... to master
92e0cd0c6 HEAD@{1}: commit: comment
046a74ef8 (tag: foo) HEAD@{2}: checkout: moving from master to 046a74ef87ea...

Скопируйте га sh, которую вы видите в начале строки (в примере выше: 92e0cd0c6) и из текущей ветви master выполните:

git merge --ff-only 92e0cd0c6
0 голосов
/ 17 марта 2020

Хорошей новостью является то, что ваши коммиты все еще доступны. Вам нужно будет использовать от git reflog до find их.

Первое, что нужно знать, это то, что Git не о файлах и не о филиалов либо. Речь идет о коммитах . Каждый коммит содержит файлы, а набор коммитов образует ветвь или набор ветвей, но центральным элементом в Git является сам коммит.

Every Коммит имеет уникальный номер. Это число принимает форму большого уродливого случайного вида га sh ID , например 51ebf55b9309824346a6589c9f3b130c6f371b8f. Каждый коммит, который вы делаете, сохраняет полный и полный снимок всех ваших файлов - ну, в любом случае, все ваши отслеживаемые *1022* файлы - в режиме «только для чтения», сжатый, «замороженный на все время», Git только формат, который может использовать только Git. Поэтому, когда вы делаете коммит, Git создает новый случайный идентификатор ha sh: новый номер, отличный от любого другого коммита. Вот почему число должно быть таким большим.

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

Каждый коммит, который мы делаем, запоминает идентификатор ha sh некоторого более раннего коммита. То есть мы выбираем коммит, например, по некоторому идентификатору ha sh, с git checkout. Это то, что вы сделали, когда попали в состояние HEAD . Этот коммит - тот, который мы извлекли - это текущий коммит. Затем, когда вы делаете новый коммит, Git делает наш новый коммит и добавляет в него вместе со снимком некоторые метаданные: ваше имя и адрес электронной почты, дату и время, когда вы сделал коммит, ваше лог-сообщение и - что очень важно для Git самого себя - идентификатор ha sh коммита, который вы проверили, что было текущим коммитом.

Этот процесс создания нового коммита приводит к новому уникальному идентификатору ha sh, и теперь этот коммит становится текущим коммитом. То есть Git записывает новый коммит ha sh ID в HEAD. Так как текущий коммит содержит идентификатор предыдущего коммита, Git может найти путь назад к предыдущему коммиту:

... <--previous  <--current   <--HEAD

Отсоединенный HEAD не является нормальный способ работы, хотя. Обычно мы git checkout <em>branch-name</em>, например, git checkout master. В этом случае имя HEAD является , прикрепленным к имени ветви. Если мы используем единственные заглавные буквы для обозначения фактических идентификаторов ha sh, а текущая end ветви master - commit H, мы можем нарисовать это так:

... <-F <-G <-H   <--master(HEAD)

То есть Git сохранил идентификатор ha sh last commit в нашей ветке с именем master под нашим именем master. Затем прикрепил специальное имя HEAD к имени master. Из HEAD, Git можно найти имя master, а оттуда Git может найти га sh идентификатор коммита H.

Фиксация H, между тем, содержит идентификатор ha sh предыдущего коммита G, поэтому от H Git может работать в обратном направлении до G. Конечно, G содержит идентификатор ha sh предыдущего коммита F, поэтому Git может работать и там, обратно F ... и F содержит идентификатор ha sh другого более ранний коммит и т. д.

Если вы git checkout master выполнили некоторую работу, а затем создали новый коммит, Git создаст этот новый коммит с каким-то случайным образом выглядящим ха sh ID, но мы просто назовем его I. Commit I будет указывать назад на commit H:

...--F--G--H   <-- ???
            \
             I   <-- ???

Имя master указывало на H мгновение go, но потому что HEAD присоединено к имени master, Git теперь записывает коммит I ha sh ID в имя master, в результате чего master указывает на I:

...--F--G--H
            \
             I   <-- master (HEAD)

Как мы найдем коммит H? Ну, имя master имеет I ha sh ID, записанное в нем, так что мы можем легко найти I. И в commit I записан идентификатор H ha sh, записанный внутри него - так мы и найдем H, начав с HEAD, чтобы получить master, чтобы получить I, чтобы найти H.

Нам больше не нужен излом на чертеже, поскольку нам не нужен указатель, прямо указывающий на H. Но на самом деле у нас есть несколько. Один находится в reflog для HEAD, а другой - в reflog для master. Git хранит историю каждого коммита, который master когда-либо называл, и каждого коммита, который HEAD когда-либо называл, в том числе через имена веток, такие как master, поэтому на данный момент мы имеем:

...--F--G--H   <-- master@{1}, HEAD@{1}
            \
             I   <-- master (HEAD)

Если имя master ранее указывало на G, у вас также будет master@{2}.

Когда вы отсоедините HEAD - например, git checkout <hash-of-F> - вы получаете HEAD, указывающий непосредственно на коммит, потому что вместо имени ветви, HEAD теперь просто содержит необработанный коммит ha sh ID. Итак, у вас есть это - я нарисую HEAD@{1}, но не все остальные:

...--F   <-- HEAD
      \
       G--H--I   <-- master, HEAD@{1}

Если вы сейчас создадите новый коммит, он получит новый уникальный идентификатор ha sh, который мы ' Позвоните J:

       J   <-- HEAD
      /
...--F   <-- HEAD@{1}
      \
       G--H--I   <-- master, HEAD@{2}

Обратите внимание, что было *1153* HEAD@{1} сейчас HEAD@{2}; что было HEAD сейчас HEAD@{1}; и HEAD обозначает новый коммит J.

Каждый раз, когда вы перемещаете HEAD или присоединяете его к другой ветви, все числа увеличиваются на единицу, чтобы освободить место для предыдущее значение. Git сохраняет предыдущий га sh ID из HEAD в reflog для HEAD и записывает соответствующее имя ветви или ha sh ID в имя HEAD.

Итак: запустите git reflog HEAD. Обратите внимание, что он выдает как сокращенные идентификаторы ha sh, так и HEAD@{<em>number</em>}. Идентификаторы ha sh являются истинными именами коммитов. коммит - вот что такое Git; это то, что он хранит. Имена с @{1}, @{2}, et c., Все часто перенумеровываются. Обратите внимание, что Git хранит эти старые значения только некоторое время - по умолчанию от 30 до 90 дней. 1 После этого Git показывает, что вам, вероятно, уже все равно, и начинает стирать старый reflog records.

Как только вы увидите, какие записи reflog или записи являются коммитами, которые вы хотите вернуть, дайте им какое-то имя. Например, вы можете создать новое имя ветви для ссылки на последний коммит в цепочке. Если вы сделали это:

       J--K--L   <-- HEAD
      /
...--F
      \
       G--H--I   <-- master

, сделав три коммита с отсоединенной головой, а затем:

       J--K--L   <-- HEAD@{1}
      /
...--F
      \
       G--H--I   <-- master (HEAD)

, заново прикрепив HEAD к имени master, Вы можете сделать это:

git branch lazarus HEAD@{1}

и тогда у вас будет:

       J--K--L   <-- lazarus, HEAD@{1}
      /
...--F
      \
       G--H--I   <-- master (HEAD)

Новое имя lazarus теперь указывает на воскрешенный коммит. (Возможно, мне следовало сделать четыре из них?)

Подробнее на GIT восстановить последнюю отсоединенную ГОЛОВУ .


1 30-дневный лимит предназначен для недоступных коммитов, а 90-дневный лимит - для достижимых коммитов. Термин достижимый здесь взят из теории графов, а достижимость подразумевает отправную точку. Отправной точкой в ​​этом случае является текущий коммит га sh ID в ссылке. Если сохраненный идентификатор reflog ha sh доступен из значения ref-name, запись имеет более длительный срок действия.

После того, как запись reflog исчезла, у самого коммита есть еще меньше способов достичь его. , Коммиты должны быть доступны из некоторого имени - какого-то имени ветви, или имени тега, или любого другого типа имени - или иным образом Git сборщик мусора , git gc, будет в конце концов удалите их. Таким образом, эти записи reflog служат для поддержки самих коммитов. В то время как все коммиты замораживаются на все время, сами коммиты будут пожинаться (отбрасываться), если они недоступны, поэтому после того, как запись reflog исчезнет, ​​коммит должен быть доступен из какого-то другого достижимого коммита или назван напрямую каким-либо другим именем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...