... Говорят, что ветвь - это просто указатель на этот коммит, который sh не является записью истории. Это правда?
Это правильно. История в Git представляет собой набор коммитов . имя ветви просто выбирает один коммит в качестве конца истории для этой ветви. Выполнение git checkout <em>branch-name</em>
выбирает данное имя ветви в качестве текущей ветви и, следовательно, фиксацию, на которую указывает имя в качестве текущей фиксации. Это извлекает выбранный коммит в индекс Git (из которого Git сделает коммит next ) и в ваше рабочее дерево (где вы можете просматривать и работать с вашими файлами).
Выполнение git commit
принимает все, что находится в индексе Git на тот момент, добавляет соответствующие метаданные, включая текущий коммит ha sh ID, записывает new commit - который получает свой уникальный идентификатор ha sh в процессе - и затем записывает идентификатор ha sh нового коммита в имя текущей ветви, таким образом, имя указывает на новый коммит.
Ни один коммит - ни один внутренний Git объект любой формы, на самом деле - никогда не может быть изменен, ни один бит, как только он будет сделан. Причина этого в том, что идентификатор ha sh представляет собой простую криптографическую c контрольную сумму содержимого объекта. Измените содержимое, и вы измените идентификатор ha sh: у вас есть новый, другой объект; существующий объект остается неизменным.
Поскольку commit L
(независимо от того, какой у него реальный идентификатор ha sh) уже существует, его содержимое теперь заморожено на все времена. Это включает в себя тот факт, что у него есть только один родитель, commit K
. Вы можете сделать новый коммит слиянием - коммит с двумя (или более) родителями - чьи родители оба I
и что угодно, например, скажем O
- и сделать ваше имя филиала PostgreSQL
указывает на этот новый коммит:
K--L--M--N--O <-- master (using MySQL)
/ \
...--F--G--H \
\ \
I---------------P <-- PostgreSQL
Вы можете получить это состояние, запустив:
git checkout PostgreSQL; git merge master
, возможно, с некоторыми дополнительными опциями и, возможно, с некоторыми шагами по разрешению конфликтов.
Снимок (т. Е. Данные, содержащиеся во всех файлах), хранящиеся в коммите P
, может быть чем угодно, хотя обычно рекомендуется Git создавать снимок сам по себе. Git делает это путем объединения проделанной работы (внесенных изменений) с базы слияния *1042*, в этом случае фиксируя H
, путем дифференцирования снимка в H
против этого в I
, чтобы увидеть что вы изменили, отобразив снимок в H
против этого в O
, чтобы увидеть, что они изменились, и объединив два набора изменений.
Поскольку снимок в O
содержит изменения, которые были введенный в снимок в K
, разница от H
до O
будет включать изменения, которые вы увидите, сравнив H
с K
. Таким образом, результат этого объединения будет включать изменения, которые вы не хотите.
Опять же, снимок в P
может быть любым, что вам нравится: вы можете сказать Git не делать коммит P
пока , а затем внесите дополнительные изменения в копии ваших файлов, которые Git сохранили в индексе Git. 1 То есть вы можете запустить git merge --no-commit
: Git сделает все возможное, чтобы объединить изменения, как обычно, и, возможно, даже добиться успеха самостоятельно. Но затем вы взяли бы получившиеся файлы - как в настоящее время хранятся в индексах Git и вашего рабочего дерева - и изменили бы их, по сути, на "отмену" фиксации K
. Поскольку вы можете редактировать только копию рабочего дерева, вы должны git add
обновленные файлы, как обычно, после чего:
git merge --continue
(или git commit
) передаст результат. Это производит то, что иногда называют злым слиянием .
Вместо злого слияния вы можете совершить обычное (не злое? Доброе?) Слияние и немедленно запустите:
git revert <hash-of-K> # or master~4, if I counted correctly
, чтобы создать новый, дополнительный коммит , который приведет к отмене изменений из коммита K, в результате чего:
K--L--M--N--O <-- master (using MySQL)
/ \
...--F--G--H \
\ \
I---------------P--Q <-- PostgreSQL
Если вы сравните снимок в P
со снимком в Q
, изменения, которые вы увидите, будут противоположны изменениям, которые вы увидите, если сравнить снимок в H
с изменением в K
. Таким образом, commit Q
будет соответствовать P
, за исключением отмены (возврата) K
.
Как обсуждалось в комментариях, хранение информации о конфигурации отдельно, а не в зафиксированных файлах, вероятно, является способом к go вместо; но вышесказанное является одним из способов достижения желаемого результата. Различия между каждым из возможных подходов проявляются не сегодня, а в какой-то момент в будущем , когда вы хотите, чтобы две ветви были менее разными, или даже не иметь двух отдельных ветвей вообще.
1 Технически это не отдельные копии, но суть в том, что коммит P
будет сделан из того, что есть в индексе Git. Если вы используете git merge --no-commit
, а затем изменяете файлы рабочего дерева, вы также должны запустить git add
для этих измененных файлов рабочего дерева, чтобы обновить индекс.