Некоторые очень важные исправления:
Способ работает так, что каждый коммит имеет идентификационный номер. Если бы идентификационные номера просто подсчитывались, это могло бы быть более понятным, но идентификационные номера имеют sh идентификаторы и выглядят случайными. Но это все еще идентификаторы.
Эти идентификаторы являются общими во всех Git репозиториях. Независимо от того, сколько коммитов имеет какой-либо данный репозиторий, этот репозиторий может получить еще один коммит от какого-то другого Git. Когда это происходит, он использует такой же ID номер. Это означает, что каждый идентификатор фиксации является уникальным для всех всех Git репозиториев. Это позволяет каждому Git легко узнать, есть ли у него какой-либо коммит: другой Git говорит у вас есть _____? (заполните пробел), а ваш Git проверяет идентификационные номера .
Поскольку каждый коммит имеет уникальный идентификатор, каждый коммит может указать свой предыдущий идентификатор ID коммита. Это заставляет коммиты образовывать обратную цепь. Если мы рисуем эти коммиты, заменяя фактический идентификатор ha sh одной заглавной буквой, это выглядит следующим образом:
... <-F <-G <-H
где H
- идентификатор ha sh последнего последнего коммит в цепочке. В коммите H
хранится необработанный ха sh ID предыдущего коммита G
; G
хранит идентификатор ha sh предыдущего коммита F
; и т. д.
Каждый коммит, тем временем, сохраняет полный снимок каждого файла . И когда вы git push
совершаете коммит, у вас есть Git вызов другого Git и выдается ему этот коммит с его идентификатором ha sh. Другие Git проверки: есть ли у меня этот коммит? Если нет, другой Git запрашивает его - и ваш Git теперь обязан предложить родительский коммит, Поэтому, если вы предлагаете им H
, и они говорят, что хотят H
, вы должны предложить им G
. Если у них еще нет G
и, следовательно, вы хотите его, вы должны предложить им F
и т. Д.
Обратите внимание, что в именах ветвей просто хранится ха sh ID последнего коммита в каждой ветви. Следовательно, если последний коммит в вашем master
является коммитом H
, у вас есть:
...--F--G--H <-- master
(где я стал слишком ленив, чтобы нарисовать коммит-коммит стрелки в правильном направлении, т. е. в обратном направлении). Обратите внимание, что ваш мастер ваш ; В каком-то другом Git хранилище будет его собственное имя master
, в котором будет храниться некоторый идентификатор ha sh. Этот ha sh ID может быть тем же H
, что и в вашем хранилище, но не может.
Следовательно:
git push github-repo master
... сделает эти два хранилища то же самое, верно?
Близко, но не совсем точно. Это вызовет любой Git номер телефона Inte rnet по URL-адресу, указанному под вашим именем github-repo
. Затем он предложит им последний коммит в вашей ветке master
. Если им это понадобится, он предложит им секунду до последнего коммита и так далее. Как только они получат все эти коммиты - все коммиты, необходимые для перехода к последнему коммиту в вашем master
- ваш Git затем попросит их установить их мастер на указание на H
.
Если их master
уже указывает (скажем) на коммит F
- тот же идентификатор ha sh, который у вас есть в вашем Git - тогда они уже имеют F
и вы отправите G
и H
, и попросите их установить для своего мастера значение H
. Поскольку H
подключается обратно к F
, они, вероятно, примут этот запрос. Теперь у вас и у них будут все коммиты, необходимые для go с начала репозитория, вплоть до коммита H
.
Если, с другой стороны, у них есть что-то вроде :
...--F--I--J <-- master
если у них есть коммиты, которые у вас нет , ваше предложение даст им:
...--F--I--J <-- master
\
G--H [proposal: set master to point here]
Они скажут нет , потому что, если они установят для master
значение H
, они потеряют совершат I-J
.
Что мне нужно сделать вместо того, чтобы переписывать все, - это оставить свой второй репозиторий как есть, и только pu sh обновлений из того, что сделано в конкретном коммите в первом репозитории, так что я могу pu sh только некоторые обновления , которые не влияют на локализацию языка.
Опять же, Git не сохраняет изменений . Git магазины коммиты . Если у них есть:
...--F--I--J <-- master
в их хранилище, и вы хотите дать им исправление, которое вы сделали в H
в вашем хранилище, на начальном этапе вам нужно будет:
использовать git remote add
, чтобы добавить имя для URL, по которому вы будете вызывать их Git:
git remote add github-repo <url>
используйте git fetch
для получения их коммитов:
git fetch github-repo
Теперь у вас будет в ваш репозиторий, последовательность, которая выглядит следующим образом:
...--F--G--H <-- master (HEAD)
\
I--J <-- github-repo/master
(* * * * * * * * здесь нужно запомнить, какая ветвь у вас git checkout
-ed. Сейчас у вас есть только одна , но мы собираемся добавить один.)
То есть ваш Git добавляет новое имя в ваш репозиторий. Это имя имя удаленного отслеживания , а не имя ветви. Он начинается с имени, которое вы изобрели, чтобы содержать URL для их Git, в данном случае github-repo
. Затем у него есть sla sh, чтобы отделить его от остальной части, и затем у него есть их имя ветви.
Это имя удаленного слежения - ваша память Git о название их Git. Все имена для удаленного отслеживания работают таким образом; Возможно, у вас сейчас есть origin/*
имена для удаленного отслеживания. Используйте git branch -r
, чтобы перечислить ваши имена для удаленного отслеживания. Используйте git branch -a
, чтобы перечислить имена ветвей и имена удаленного слежения. 1
Теперь вы можете создать новое имя ветки в ваш репозиторий. Это имя ветви ваше , и вы можете называть его как угодно, хотя если вы хотите назвать его master
, у вас есть проблема, что у вас уже есть имя ветви master
, которое вы используете для помните ha sh ID вашего коммита H
. Таким образом, вы, вероятно, хотите другое имя. Я буду использовать здесь имя them
(вам, вероятно, следует придумать более подходящее имя):
git branch them github-repo/master
git checkout them
или, чтобы объединить его в одну команду:
git checkout -b them github-repo/master
Теперь у вас есть, в вашем репозитории:
...--F--G--H <-- master
\
I--J <-- them (HEAD), github-repo/master
Теперь в вашем рабочем дереве (и индексе) будет результат проверки коммита J
. Это коммит, который вы получили от них на шаге git fetch
. Это последний коммит в их master
, а теперь и последний коммит в вашем them
.
Теперь вы должны сделать изменяется на этот коммит. Изменения, которые вы хотите, вполне могут быть теми, которые представлены сравнением вашего снимка H
с вашим снимком G
, при условии, что между G
и H
вы сделали то изменение, которое хотели бы им дать.
Мы будем предполагать, что вы не хотите передать им изменения, сделанные вами между коммитами F
и G
. Если эти изменения должны оставаться конфиденциальными, вам нужно быть уверенным, что вы не дадите им коммит G
или снимок, содержащий изменения, сделанные оттуда.
Теперь вам нужно копировать эффекты коммита H
. Для этого вы можете использовать git cherry-pick
.
1 Без видимой причины git branch -a
вставляет слово remotes/
перед вашими именами для удаленного слежения. Фактически, ваши имена для удаленного отслеживания все сокращаются, когда вы видите их либо с git branch -r
или git branch -a
: все они имеют полную форму refs/remotes/<em>remote</em>/<em>name</em>
, где remote
- это удаленное устройство, а name
- это имя филиала на , которое является удаленным. Но ваши имена ветвей также сокращены: master
действительно refs/heads/master
. Все имена Git - имена ветвей, имена тегов, имена для удаленного отслеживания и другие - объединяются с помощью этой вещи refs/
, а затем разделяются на различные пространства имен различать guish что такое вид имени каждого из них.
Cherry-pick копирует изменения коммита
Ранее мы говорили, что коммиты не сохраняют изменения. У них есть только снимки . Это правда, но предположим, что мы берем два коммита, которые расположены подряд, с их двумя снимками, и сравниваем два? То есть предположим, что у нас есть:
...--G--H--...
В коммите G
есть моментальный снимок, а в коммите H
еще один снимок. Если мы извлечем G
в одну временную область, H
в другую и сравним снимки , мы увидим, что изменилось .
Вот что git diff
, например: git diff <hash-of-G> <hash-of-H>
извлечет два снимка, сравнит их и скажет, что изменило . Это то же самое, что делает git log -p
, и то, что делает git show <hash>
: они оба находят родительский коммита, сравнивают родителя с коммитом и показывают, что изменило .
Команда cherry-pick использует это. Сравнивая родительские и дочерние коммиты, cherry-pick может увидеть, что изменило . Затем он может применить эти такие же изменения к вашему текущему коммиту. Итак, учитывая это:
...--F--G--H <-- master
\
I--J <-- them (HEAD), github-repo/master
и ваше рабочее дерево и индекс, совпадающий с существующим коммитом J
, вы можете выполнить:
git cherry-pick <hash-of-H>
или:
git cherry-pick master
и получите Git с сравните G
против H
, посмотрите, что изменилось, и внесите такие же изменения и внесите их. 2 Если все идет хорошо, результат:
...--F--G--H <-- master
\
I--J <-- github-repo/master
\
H' <-- them (HEAD)
, где H'
является своего рода копией H
: J
против H'
показывает те же изменения как G
против H
. Команда cherry-pick также копирует сообщение журнала фиксации из H
.
2 Это сравнение фактически использует Git механизм слияния, Git будет не только сравнивать G
против H
, но и сравнивать G
против J
, а затем объединить этих различий. Эффект, однако, почти такой же, как применение патча G
-vs- H
для фиксации J
.
Теперь мы готовы к git push
Теперь, когда мы зафиксировали H'
как последний коммит нашей ветви them
, мы можем использовать git push
, чтобы отправить этот коммит - H'
- Git в github-repo
. Для этого мы запустим:
git push github-repo them:master
Наши Git вызовут свои Git, используя URL-адрес, сохраненный в имени github-repo
. Теперь мы предложим им совершить H'
: тот, который обозначен именем нашего филиала them
. У них не будет этого коммита, поэтому они скажут , пожалуйста, отправьте этот . Мы немедленно предложим им совершить J
, потому что это родительский коммит H'
, но у них есть J
, поэтому они скажут нет, спасибо, у меня он уже есть .
Следовательно, мы просто отправим один коммит, который мы хотели отправить.
Теперь, когда у них есть H'
, мы попросим их установить их master
. Вот что значит them:master
в этой команде git push
: мы выбираем коммиты для отправки из нашего them
, а затем просим их установить их master
. Поскольку H'
просто добавляет к существующему коммиту J
, они могут принять этот запрос. Предполагая, что они do принимают это, они будут иметь в своем хранилище последовательность:
...--F--I--J--H' <-- master
, и наши Git обновят нашу память о своих master
, так что у нас есть:
...--F--G--H <-- master
\
I--J--H' <-- them (HEAD), github-repo/master
и сейчас у нас все хорошо - если, возможно, мы не хотим добавить к нашему master
. (В этом случае мы можем просто git merge github-repo/master
на данный момент. Здесь много вариантов, и что делать, зависит от того, как вы хотите работать с этим.)