В чем сходство и разница между git reset --hard HEAD ~ 1 и git revert HEAD? - PullRequest
0 голосов
/ 15 апреля 2019

Я пытаюсь обернуть голову вокруг этого.

Из того, что я могу сказать, "git reset --hard HEAD ~ 1" удалит последний коммит, и этот коммит не будет виден в "git log".

И "git revert HEAD" поместит меня в nano, где я могу редактировать сообщение коммита, а также сохранит возврат как новый коммит в "git log"

Я прав?

Ответы [ 3 ]

2 голосов
/ 15 апреля 2019

На самом деле, git revert создаст новый коммит, который отменяет эффекты другого данного коммита, воспроизводя отрицательную версию его ревизии.В частности, git revert не будет делать то, что будет делать mercurial .

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

git reset, однако, вернет указатель ветви в заданную позицию.В соответствии с указанным параметром, --soft, --mixed (по умолчанию) или --hard, git соответственно изменит только указатель ветви, ветвь и состояние индекса или содержимое ветвления, индекса и рабочего каталога.Поэтому это то, что используется для полного избавления от кончика ветви, но команда может действовать за пределами этого единственного случая.

Обратите внимание, что даже если вы пересылаете коммит, используя git reset --hard или что-то еще, этот коммит будетсохраняться в коллекции объектов до тех пор, пока не будет запущен сборщик мусора, и выбрасывать его можно только в том случае, если он достаточно стар (обычно три месяца).

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

1 голос
/ 15 апреля 2019

См. Превосходные (и повторяющиеся) вопросы и ответы по адресу В чем разница между Git Revert, Checkout и Reset? Но мы должны начать с чего-то еще более простого.

Почему мы используемконтроль версий?

Цель системы контроля версий *1007* - сохранить все, что когда-либо было сделано, навсегда.Ну, кроме случаев, когда это не так: иногда целью является сохранение некоторых вещей, выполненных за все времени, некоторых вещей для некоторых время и некоторые вещи за очень короткое время.

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

Имея это в виду, мы можем посмотреть на эти три глагола Git (Iя тоже добавлю git checkout):

git checkout - чтобы получить что-то, сделанное за некоторое время

Мы используем git checkout, чтобы получить один конкретный коммит.Коммит - это моментальный снимок, сделанный кем-то в какое-то время.Предположительно, этот снимок был хорош для какой-то цели.Мы используем git checkout, чтобы получить этот снимок, точно так, как он был сделан в то время, независимо от того, какой может быть наша следующая цель.

В Git, как побочный эффект использования git checkout с имя филиала , теперь мы готовы сделать новую работу.Но мы также можем использовать git checkout с необработанным хэшем коммита, после чего новые коммиты ... ну, немного сложно.(Они все еще возможны, но Git вызывает этот режим detached HEAD , и вы можете не захотеть использовать его, пока не узнаете больше о Git.)

Причина, по которой git checkout masterНапример, чтобы получить последний коммит на master, каждый раз, когда мы делаем новый коммит на master, Git автоматически обновляет наше имя master, так чтоэто означает новейший такой коммит.Новейший коммит запоминает своего родителя, который раньше был самым новым.Этот второй коммит с одним ответом запоминает его родителя, который был самым новым, когда не существовало коммит с одним ответом, и т. Д.

Что это означает, что name master действительно просто найдите последний коммит, из которого мы находим каждый более ранний коммит:

... <-F <-G <-H   <--master

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

git revert - отмена плохого коммита

Учитывая, что каждый коммит записывает своего родителя, и поэтому Git может сказать нам, что человек, который сделал этот коммит изменил , мы всегда можем сделать Git отменить чужое изменение (илидаже наш).Мы выбираем коммит, рассматриваем его как изменение - именно так Git показывает его нам, когда мы используем git log -p или git show, - и обнаруживаем, что, эй, это изменение было неправильным .Это изменение должно быть отклонено или «отменено». 1


1 Глагол revert здесь на самом деле плохой выбор.За наиболее распространенным определением в английском языке почти всегда следует вспомогательное слово от до , так как в возвращаются к , и это означает возврат в прежнее состояние.Но отказ от некоторых изменений не обязательно возвращает нас к старому состоянию!Мы вернемся в наше предыдущее состояние, только если откажемся от самого последнего изменения.

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


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

Git's reset глагол чрезвычайно сложен.В одной конкретной форме он делает до трех вещей.С другими формами это делает другие вещи.В частности, тот, о котором вы спрашивали, git reset --hard HEAD~1, говорит Git:

  1. Сделать текущую ветку name , что бы это ни было, указать на родителя текущегоcommit.
  2. Сотрите текущий index - который мы здесь не описали, но index , область подготовки и даже кеш - это всего лишь три имени для одной и той же вещи в Git, и заполните его из коммита, выбранного на шаге 1.
  3. Удалите все файлы work-tree , которые были в комплекте синдекс до того, как мы его сбросим, ​​и заменим их копиями, извлеченными из фиксации, выбранной на шаге 1 и скопированной в индекс на шаге 2.

Так что если у нас было:

... <-F <-G <-H   <--master

мы изменили имя master, чтобы оно указывало на G, что повлекло за собой H:

            H
           /
... <-F <-G   <-- master

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

Запомните нашу цель для коммитов

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

...--F--G--H--I--J--K--L   <-- master

Если мы сделали H некоторое время назад, и все это встроено так, трудно удалитьпотому что каждый коммит полностью заморожен, поэтому удалить H, мы должны скопировать I в новый и другой коммит I' с G в качестве егоparent, затем скопируйте J в новый коммит с I в качестве родителя и т. д.:

          H--I--J--K
         /
...--F--G--I'-J'-K'  <-- master

Здесь проще вернуть H, добавивновый коммит, который отменяет все, что мы изменили в H.Коммиты с I по K остаются прежними - возможно, немного сломанными, но так они и были на самом деле все время - и теперь у нас есть новый коммит L, чтобы отменить то, что мы сделали в H:

...--F--G--H--I--J--K--L   <-- master

Но если H был довольно недавним, мы можем просто полностью удалить его, используя git reset --hard.Мы забудем, что когда-либо совершали эту ошибку.Больше не нужно никому рассказывать.

1 голос
/ 15 апреля 2019

вы правы ... они могут дать вам один и тот же "конечный результат" с точки зрения того, как выглядит рабочее дерево ... но итоговая история проекта радикально отличается .... Если бы вы спросили меня , если вы только что заметили, что последний коммит не нужен, просто полностью удалите его из истории (git reset --hard). если нет основной причины не делать этого. Некоторые люди говорят, что, как только он будет опубликован, его не следует возвращать ... я полагаю, что любой опытный пользователь git знает, как перебазировать материал с помощью --onto и указать ревизию для skip , так что даже если опубликовано, вы должны просто удалить его (сообщить другим разработчикам, что вы сделали) .... но это только мое предположение / мнение.

...