Создать ветку из головы и зафиксировать из предыдущего коммита - PullRequest
0 голосов
/ 28 января 2020

Для моей работы мне нужно управлять своим проектом с помощью GIT. Для меня это ново, и я не знаю всех хитростей.

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

A
|
B
|
C (head)

Однако мне нужно исправить ошибка в версии B без потери версии C (которая в настоящее время не является официальной). Я думал сделать это:

A
|
B
| \
D  C

D:(head)

Но если бы я мог создать ветвь C, я не смог бы "go вернуться" в B и зафиксировать файлы для создания D. Может быть, это не так правильный способ использования GIT, однако, как я могу это сделать?

Спасибо

Ответы [ 3 ]

3 голосов
/ 28 января 2020

я не могу "go вернуться" к B и зафиксировать файлы для создания D

Да, вы можете:

# create a brackup branch to store commit C for later
git branch <name-for-your-store-branch>

# then return to B
git reset --hard B

# make your needed changes here

# then add and commit as usual, for example
git add .
git commit -m "Done this and that"

Вы закончите с (здесь я принял «мастер» для вашей основной ветви)

A---B---D <<< master <<< HEAD
     \
      C <<< your "store" branch
1 голос
/ 28 января 2020

Чтобы немного рассказать о ответе RomainValeri , запомните эти вещи о Git:

  • Git хранилищах коммитов . «Истинное имя» любого коммита - это его sh ID, эта большая уродливая строка букв и цифр, которую git log печатает после слова «коммит». (Вы можете сокращать их, если хотите, до определенного момента.) Эти выглядят случайными, но на самом деле вовсе не случайны.

  • Каждый коммит содержит полный и полный снимок каждого файла. 1 Он также содержит обратную ссылку на свой родительский коммит, который мы рисуем, когда делаем эти A--B--C виды диаграмм. Мне нравится рисовать их слева направо для StackOverflow и по вертикали с новыми коммитами к вершине - как их git log --graph dr aws - в некоторых других ситуациях. Вы можете и должны практиковать рисование этих вещей.

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

A--B--C

, а затем решить, что C - это плохо, и использовать git commit --amend, чтобы исправить это. Это на самом деле не меняет C вообще, потому что не может. Вместо этого он отбрасывает C в сторону и делает новый и улучшенный коммит: C'. Родитель C' совпадает с родителем C:

     C
    /
A--B--C'

Старый коммит все еще там, он просто убран, чтобы освободить место для C'.

Как только вы отключите этот материал - который фиксирует файлы хранилища в режиме только для чтения и ссылается на предыдущие коммиты - вы поймете две вещи:

  1. Как можно мы можем сделать какую-нибудь работу? Файлы внутри коммитов доступны только для чтения, заморожены навсегда и абсолютно нечитаемы для всего , но Git. Нам нужны обычные файлы, которые мы можем изменить .

  2. Как нам найти вправо commits?

Ответ на вопрос № 1 заключается в том, что Git предоставляет нам место для выполнения нашей работы, которое Git вызывает рабочее дерево или рабочее дерево . (Старые версии Git раньше называли этот рабочий каталог или аналогичными именами, но это слишком легко спутать со строкой рабочего каталога, которую печатает команда pwd, так что теперь это рабочее дерево или рабочее дерево.) Git скопирует файлы из коммитов в эту рабочую область. 2

Ответ на вопрос №2 - где приходят имена ветвей . Каждое имя ветки хранит идентификатор ha sh всего one commit. Когда мы рисуем коммиты следующим образом:

A--B--C   <-- branch

или:

C  <-- branch
|
B
|
A

мы рисуем то, что Git действительно имеет внутренне: имя, например branch, , указывающее в (содержащий га sh ID) коммит, например C. Между тем сам коммит C имеет идентификатор ha sh - или указывает на - его родительский коммит B и т. Д.

Вы можете в любое время создать новое имя ветки, выбрав любой существующий коммит и сказав: Сделать это новое имя ветви указанным на этот существующий коммит. Вы делаете это с помощью команды git branch. Таким образом, чтобы указать какое-то новое имя, например hotfix, указать на существующий коммит, вы можете выполнить:

git branch hotfix <hash>

, где <hash> - идентификатор ha sh, полученный, возможно, путем вырезания и паста га sh ID, напечатанная git log. Теперь у вас есть:

A--B   <-- hotfix
    \
     C   <-- branch

Когда вы запускаете git checkout <em>name</em>, Git использует name для поиска коммита. Это коммит , который появляется в вашем рабочем дереве (и индекс; см. Сноску 2), так что вы можете работать с ним. Когда вы запускаете git commit, Git делает * новый коммит (из того, что находится в вашем индексе на тот момент), который выбирает случайный га sh ID. 3

Это также, как вы делаете новые ветви в целом. Просто вы начинаете с:

A--B--C   <-- master

и затем создаете новое имя, например develop, которое указывает на фиксацию C:

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

Теперь нам нужно знать, какое имя ветви мы используем , поэтому на чертежах такого типа мы можем добавить специальное имя HEAD в верхнем регистре и прикрепить его к имени ветви, например:

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

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

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

Если мы сделаем имя hotfix точкой для фиксации B, а затем сделаем git checkout hotfix, мы получим:

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

Commit B в нашей работе область, чтобы мы могли изменить файлы (и в нашем индексе, чтобы мы могли зафиксировать). Мы выполняем свою работу, git add файлы (чтобы скопировать их обратно в индекс - см. Сноску 2), и git commit, и Git делает новый коммит, который получает новый уникальный большой уродливый ha sh ID, но мы просто назовем его E, а затем Git записывает E ha sh ID в имя hotfix, потому что именно там присоединено HEAD:

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

Обратите внимание: что бы мы ни делали, мы всегда добавляем новые коммиты в репозиторий. Существующие коммиты не меняются. Они не могут! Мы просто добавляем новые единицы.

имена ветвей перемещаются! Они всегда указывают на последний коммит (на ветке). Фактически, это одно из определений «ветви» в Git: это последний коммит. Или иногда, когда мы говорим «ветвь», мы имеем в виду само имя , или иногда мы имеем в виду некоторый набор коммитов, ведущих к последнему коммиту и включающий его . Слово ответвление в Git является двусмысленным. Это помогает в первую очередь думать о коммитах . Добавьте имена филиалов позже. Используйте имена, чтобы найти коммитов; это то, что делает Git.


1 Технически, каждый из них содержит только снимок файлов, которые он содержит. Рассмотрим, например, что произойдет, если вы сделаете коммит C после помещения в него совершенно нового файла, которого не было, когда вы делали коммит B. Существующий коммит B не может измениться, и у него нет этого файла. Таким образом, C и последующие коммиты будут иметь файл; B не будет иметь файл. Каждый коммит будет иметь полный и полный снимок всех файлов, которые у него есть.

Еще один способ думать об этом: коммит - это замороженная на все время копия из некоторый набор файлов. Какие копии файлов go в новый коммит? Ответ хранится в индексе Git; см. сноску 2.

2 Тогда вы можете подумать, что Git сделает новые коммиты из рабочей области, но это не так. Вместо этого Git делает новые коммиты из того, что есть в Git в index . Индекс, который Git также называет промежуточной областью или (редко в наши дни) кеш , представляет собой довольно большую топику c, и мы не будем охватывать ее должным образом Вот. Это важно понимать, чтобы эффективно использовать Git, но смотрите другие публикации или статьи об этом. Однако вы можете думать, что он содержит третью копию каждого файла. Когда вы запускаете git add, Git копирует копию рабочего дерева файла, который вы git add -ing, в индексную копию. Когда вы запускаете git checkout, Git копирует замороженную копию каждого файла из существующего коммита, который вы проверяете, в индексную копию, а также в рабочее дерево. Это не на 100% правильно, но достаточно для начала.

3 Этот идентификатор ha sh зависит от:

  • всего снимка;
  • родитель коммит ha sh ID;
  • ваше имя и адрес электронной почты и т. Д., Как записано в коммите;
  • ваше сообщение журнала, как записано в коммите; и
  • даже дата и время, когда вы делаете обязательство.

Если вы заранее знаете все эти вещи, вы можете предсказать, что ha sh ID вашего коммита будет. Но никто не знает, когда они собираются сделать новый коммит, пока они на самом деле не сделают это. Не стоит предварительно рассчитывать га sh, затем ждать точную правильную секунду и запускать git commit. Просто сделайте коммит и выясните, что он получил. И если вы сделаете это снова, даже если все остальное будет таким же, на этот раз он получит другой га sh, потому что он больше не тот же время .

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

0 голосов
/ 28 января 2020

Итак, у вас есть A-B-C на ветке, скажем, dev (со всем хорошо зафиксированным). Вы хотели бы иметь A-B-D на ветке dev, но вы хотели бы иметь A-B-C на ветке non_official.

ветвь неофициально

# we are on dev (A-B-C with head on C)
git checkout -b non_official

ответвление dev

# we are on dev (A-B-C with head on C, same as non_official) 
git reset --hard <hash-commit-B>

или в этом случае, поскольку B является коммитом непосредственно перед head:

git reset --hard HEAD~1

И теперь у нас есть A-B на dev, и вы можете добавить другой коммит (D).

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