Как нажать на коммит после проверки предыдущего коммита и внесения в него изменений - PullRequest
0 голосов
/ 27 октября 2018

Я боюсь, что мой текущий рабочий код не будет испорчен.

Итак, допустим, у меня есть следующий коммит

7abd390c269d4abc9f3208d3c1b0a27ef5ae4162 -> Latest commit 

5488da9335eb51eed274aa9b4a0f8f205643a8e0 -> 2nd commit

a31e310304404eb4452e6465e0a92dd472c5329a -> 1st commit

Я проверил свой первый коммит , используя

git checkout a31e310304404eb4452e6465e0a92dd472c5329a

И начал вносить изменения здесь,Теперь я хочу зафиксировать это и отправить на github.

но Вещи, которые я пытаюсь избежать Git pull и Git Merge

Потому что на данный момент я сделал так много изменений.

Вопрос: Может кто-нибудь сказать мне, можно ли принудительно нажать этот коммит и если да, то как?

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

TL; DR

Что вы, вероятно, хотите сделать, - это создать новое имя ветки для вашего последнего коммита, например, git checkout -b <em>newname</em>. Затем вы можете использовать это новое имя для всей своей работы или использовать его для запоминания ваших коммитов, когда вы возвращаетесь к старым именам и выполняете работу.

Long

Я проверил свой первый коммит, используя

git checkout a31e310304404eb4452e6465e0a92dd472c5329a

Выполнение этого приводит к тому, что Git называет обособленным HEAD. Хотя это может показаться страшным, но на самом деле это не смертельно, это просто означает, что HEAD не присоединен.

Обычно специальное имя HEAD (записанное во всех заглавных буквах, вот так 1 ) прикрепляется к какому-либо существующему имени ветви. Название ветки в Git - это то, как Git отслеживает, кто и что делает. Более конкретно, само имя хранит необработанный хэш-идентификатор этих коммитов. Таким образом, имя ветки, такое как master или develop, будет хранить этот большой уродливый хэш-идентификатор, вещь a31e310304404eb4452e6465e0a92dd472c5329a. Это позволяет вам, человеку, присвоить значимое имя этой, казалось бы, случайной вещи.

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


1 В Windows и MacOS вы можете использовать head в нижнем регистре, но это что-то вроде аварии / странности системы. Лучше придерживаться варианта с прописными буквами, поскольку строчный не будет работать в Linux. Если вам не нравится вводить HEAD заглавными буквами, вместо него можно использовать @, что означает то же самое.


Фиксирует и названия филиалов

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

Давайте посмотрим на действительно крошечный, почти новый репозиторий, в котором всего три коммита. Каждый из этих трех коммитов будет иметь свой собственный уникальный хэш-идентификатор, но чтобы избавить нас от головной боли, вместо этого я буду использовать для них одну заглавную букву. Я назову первый сделанный коммит A, второй коммит B, а третий C.

Каждый коммит хранит полный снимок дерева исходных текстов вместе с некоторыми метаданными , которые являются просто причудливым словом для материала git log может напечатать о коммите: who сделал это и когда, и какое сообщение журнала они ввели для этого. Метаданные также включают необработанный хэш-идентификатор коммита parent commit, который является коммитом, который был вместо , когда человек сделал этот коммит.

Другими словами, каждый коммит указывает на свой предыдущий коммит. Итак, давайте нарисуем это:

A  <-B  <-C

Commit A, будучи самым первым коммитом, имеет no parent, потому что не может. Но коммит B помнит, что A был коммитом, когда было сделано B, поэтому B указывает на A. Аналогично, commit C помнит для нас, что B был его родителем, поэтому C указывает на B.

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

A--B--C   <-- master

Мы говорим, что имя ветви master, указывает на последний коммит в цепочке. Мы используем имя ветви для получения идентификатора хеша, и это позволяет нам (через Git) совершать коммит C. Commit содержит хэш B, поэтому из C мы можем найти B, а из B мы можем найти A. A не имеет родителя, поэтому мы можем остановиться на этом.

Теперь, если у нас есть только одно имя ветви, это довольно просто. Мы git checkout master, что заставляет нас совершать C. Затем мы вносим некоторые изменения, git add наши измененные файлы, и запускаем git commit. Это упаковывает новый снимок, добавляет наше собственное имя и текущее время, добавляет наше лог-сообщение, сохраняет хэш-идентификатор C и делает новый коммит, который теперь получает новый, уникальный, большой уродливый хеш-идентификатор, и теперь происходит ключевой шаг: Git записывает новый хэш-идентификатор в имя master:

A--B--C--D   <-- master

Но что, если у нас есть два имени ветви? Давайте создадим новое имя ветки сейчас:

A--B--C--D   <-- master, develop

В настоящее время оба имени хранят один и тот же хэш-идентификатор для фиксации D. Теперь Git должен знать , какое имя ветки обновлять . Поэтому для этого Git прикрепляет HEAD к одному из них, который мы даем git checkout. Например:

git checkout master

A--B--C--D   <-- master (HEAD), develop

но:

git checkout develop

A--B--C--D   <-- master, develop (HEAD)

В любом случае, мы начинаем с коммита D. Разница в том, какая ветвь name изменяется, когда мы делаем новый коммит E:

A--B--C--D   <-- master
          \
           E   <-- develop (HEAD)

Здесь следует помнить следующее: Всякий раз, когда мы добавляем новый коммит, Git заставляет новый коммит иметь предыдущий текущий коммит в качестве своего родителя. Затем Git записывает новый идентификатор коммита в имя ветви , к которому прикреплен HEAD.

Обратите внимание, что шаг git checkout делает две вещи:

  • выбирает коммит, на который указывает имя ветки; и
  • присоединяет HEAD к имени этой ветви.

Здесь первый пункт не имел значения только потому, что и master, и develop указывали на одинаковый коммит.

Отсоединенный HEAD почти такой же, но имя ветки не задействовано

Если вы git checkout делаете коммит по его необработанному хеш-идентификатору, то Git по-прежнему выбирает тот коммит как текущий коммит, но на этот раз он не присоединяет HEAD к имени ветки , Допустим, например, что вы выбрали хеш-идентификатор commit C. Нет имени ветки, указывающего на C, поэтому Git должен сделать это вместо:

          E   <-- develop
         /
        D   <-- master
       /
A--B--C   <-- HEAD

Все, что мы здесь сделали, - это отогнали D и E с пути, чтобы мы могли нарисовать HEAD, указывая прямо на фиксацию C. Git сделал здесь, чтобы записать необработанный хэш-идентификатор в имя HEAD вместо того, чтобы иметь имя ветви в HEAD. (Если хотите, вы можете посмотреть файл .git/HEAD: он либо содержит необработанный хэш-идентификатор, подобный этому, либо, если он присоединен к ветви, содержит текст ref: refs/heads/<em>branch</em>.)

Теперь мы можем сделать новый коммит как обычно, отредактировав файлы, запустив git add при необходимости и запустив git commit. Git собирает наше сообщение о коммите как обычно и делает новый коммит как обычно. Родительский коммит нового коммита - это текущий коммит - коммит C, чей идентификатор хеша находится в файле HEAD. Затем вместо записи хеш-идентификатора нового коммита в ветвь с именем в файле HEAD Git просто записывает ID нового коммита в HEAD напрямую:

          E   <-- develop
         /
        D   <-- master
       /
A--B--C--F   <-- HEAD

Если вы продолжите делать еще два коммита, процесс просто повторяется:

          E   <-- develop
         /
        D   <-- master
       /
A--B--C--F--G--H   <-- HEAD

Обратите внимание, что Git может легко найти коммит H прямо сейчас, потому что его хэш-идентификатор находится в файле HEAD. Начиная с H, Git может найти G и F (а затем C и так далее). Но если вы, например, git checkout master или git checkout develop, Git сделает коммит D или E текущим, а запишет имя ветви в файл HEAD, потеряв H. ID хэша .

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


2 По умолчанию это длится не менее 30 дней, используя reflog для HEAD. Reflog содержит все хеш-идентификаторы, которые HEAD названы за последние 30–90 дней или дольше, в зависимости от ряда деталей, которые я здесь не буду раскрывать, поскольку это уже слишком долго. : -)


Задание имени для хэша коммита

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

git branch xyzzy

          E   <-- develop
         /
        D   <-- master
       /
A--B--C--F--G--H   <-- HEAD, xyzzy

Обратите внимание, что не прикрепил HEAD к имени xyzzy. После создания имени вы можете git checkout xyzzy сказать Git переключиться с коммита H, где HEAD указывает, на коммит H, где xyzzy указывает. Этот переключатель ничего не делает, но теперь применяется вторая часть git checkout, и Git присоединяет HEAD к имени xyzzy:

          E   <-- develop
         /
        D   <-- master
       /
A--B--C--F--G--H   <-- xyzzy (HEAD)

Вы можете сделать оба этих действия одновременно, используя git checkout -b xyzzy: это создает xyzzy, указывая на текущий коммит, и в то же время присоединяет HEAD к новому имени xyzzy.

Как только вы это сделали, у вас теперь есть имя для ваших коммитов. Теперь можно использовать git push для отправки коммитов в другой Git-репозиторий, сообщая, что другой Git-репозиторий должен установить свой xyzzy, чтобы он указывал на коммит H (независимо от фактического хэша H). Идентификатор есть).

Когда другой репозиторий Git получает H, он также получает G и F и, при необходимости, C и B и даже A (при условии, что этот конкретный чертеж графика корректен). По сути, git push отправляет все коммиты, которые содержатся в - или достижимы из (см. Думайте как (а) Git ) - ветви, если только другой Git уже имеет их. Затем ваш Git установил в Git какое-то имя, обычно такое же имя, чтобы запомнить последний коммит, как это делают ветви.

Если вы не хотите сохранять два снимка F и G и их метаданные фиксации, теперь пришло время использовать git rebase или аналогичный для перезаписи некоторых коммитов, но это тема для другого вопроса (и на StackOverflow уже есть много ответов по этому поводу).

0 голосов
/ 27 октября 2018

Если вы принудительно отправите свой новый коммит, вы потеряете 2 других коммита, которые находятся в сети (я предполагаю, что у вас есть новый локальный коммит, без причины, почему бы и нет).

Создайте новую локальную ветвь, еслиВы не хотите сливаться прямо сейчас.Но вам «придется» вытянуть то, что есть в сети, а затем объединить.

Вытаскивание и объединение не уничтожат ваше локальное объединение, но вы должны объединиться, если вы останетесь в той же ветке, потому что может бытьтолько один главный коммит на именованную ветку с git.

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