Как набрать sh все коммиты и объединить с мастером и pu sh в GitHub - PullRequest
1 голос
/ 25 февраля 2020

Итак, по сути, я создал Git и GitHub-репозиторий для LaTeX-проекта (тезис). Я создал макрос в TexStudio для автоматической фиксации и отправки изменений. В начале я просто зафиксировал и перенес все в локальную и удаленную ветку master . Поскольку я использую commit / pu sh как способ сохранения небольших добавочных изменений, я создал для этой цели новую ветку ученик , которая сливается с мастером только после внесения существенных изменений. Однако при объединении вся история коммитов для ученика была передана мастеру. Я не хотел, чтобы это произошло.

Поэтому, по сути, я запускаю следующий код:

git add .
git commit "message"
git push origin apprentice

git checkout master
git merge apprentice
git push origin master

Это, очевидно, не делает то, что я хочу.

  1. Итак, во-первых, мне нужен способ "привести в порядок" локальную и удаленную master ветку. На данном этапе мне не нужно отслеживать какие-либо предыдущие коммиты в master. Я попытался создать "тестовую" ветку, там я запустил git rebase --interactive [first commit hash]. Тем не менее, запуск git log по-прежнему перечисляет все зафиксированные коммиты. Как я могу объединить все коммиты в мастере в последний как в локальной, так и в удаленной ветке master?
  2. Для будущего объединения коммитов из ученик в мастер я бы хотел сделать это без передачи всей истории коммитов на apprentice. Я пытаюсь найти способ отслеживания незначительных изменений в моем документе, и в то же время могу отслеживать более существенные изменения, такие как добавления разделов и абзацев. Поэтому мне нужен способ собрать изменения, сделанные в apprentice (начиная с последнего коммита для мастеринга), в один коммит в m̀aster и перенести его в удаленное репо. Я попытался проиллюстрировать ниже, что я хочу.
master:     [1st commit]----------------------[big commit]--------------------[big commit]
                    \                            /                                /     
apprentice:          [commit]---[commit]-[commit]---[commit]---[commit]---[commit]---[commit]---

Как мне лучше всего это сделать sh? ... а есть ли полуавтоматический способ сделать это, например, вызвать скрипт?

Ответы [ 3 ]

2 голосов
/ 25 февраля 2020

git rebase --i определенно то, что вы можете использовать. Вы можете перебазировать главу локального мастера на себя и объединить все свои коммиты sh в один:

git checkout master
get rebase -i HEAD~<nuber of your commits>

Важно понимать разницу между merge и rebase. Одним из них является то, что вы перезаписываете историю git. Так что вам, вероятно, придется приложить силу pu sh к источнику.

1 голос
/ 27 февраля 2020

Я перерисовал ваш паттерн здесь, используя заглавные буквы для обозначения коммита ha sh Идентификаторы:

A------------F--------J   <-- master
 \          /        / 
  B--C--D--E--G--H--I--K   <-- apprentice

Обратите внимание, что имена ветвей - это метки, которые указывают на ( или прикрепить к) указать c совершает . Всякий раз, когда вы находитесь на ветке и делаете новый коммит, Git делает новый коммит таким образом, чтобы он указывал на старый кончик ветки, а затем настраивает ветку name так что он указывает на новый коммит, который теперь является новым tip-tip. Тот факт, что коммиты A, F и J находятся в режиме «мастер», подразумевается тем фактом, что, начиная с фиксации слияния J и возвращаясь к его первому родителю, вы получаете F, который также является коммитом слияния. Возвращаясь к первому родителю F, вы получаете коммит A. Коммит A является самым первым коммитом, поэтому у него вообще нет родителя, и процесс останавливается.

Команда git log сделает эту работу в обратном направлении. Вам нужно --first-parent, чтобы предотвратить , а также , работающее в обратном направлении с J до I.

Команды, которые производят этот шаблон, являются повседневными Git , Единственные особые случаи: * ie при первоначальном создании master, затем при первоначальном создании apprentice и выполнении слияния first :

$ git init        # makes the new, empty repository
... create files and `git add` them all ...
$ git commit      # creates commit `A` and thereby allows the name `master` to exist

На данный момент у вас есть:

A   <-- master (HEAD)

в вашем хранилище. Затем:

git checkout -b apprentice

приводит к:

A   <-- apprentice (HEAD), master

Теперь вы можете создавать коммит B обычным способом: редактировать файлы в рабочем дереве, git add их и и так далее, и запустить git commit. Это создает коммит B, который заставляет два имени ветви указывать на разные коммиты:

A   <-- master
 \
  B   <-- apprentice (HEAD)

Обратите внимание, как коммит B указывает на существующий коммит A, а Git установил новый коммит ha sh ID в имя apprentice, к которому прикреплено специальное имя HEAD.

Теперь вы создаете коммиты C-D-E таким же (обычным, повседневным) способом:

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

Чтобы сделать коммит F, вы должны git checkout master:

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

(обратите внимание, как вы сейчас используете коммит A вместо коммита E и HEAD теперь присоединен к master), а затем git merge apprentice. Однако в этот момент вы должны заставить Git не использовать тут что-то Git мгновенно.

Способ git merge работает так, что он находит объединить базу коммит вашего текущего коммита A и выбранного вами коммита E. Это лучший общий коммит, который начинается с E и работает в обратном направлении, начинается с A и работает в обратном направлении одновременно. Но это, очевидно, сам коммит A, который не только является общим, но и текущий коммит. На этом этапе git merge будет использовать ярлык: на самом деле он не будет объединять вообще. Вместо этого он выполнит операцию fast-forward , которая не является слиянием. Это заставит имя master просто указывать непосредственно на существующий коммит E и проверить коммит E. Это не то, что мы хотим: мы хотим заставить Git сделать фактический коммит слияния F.

Для этого мы запускаем git merge --no-ff apprentice. Git затем сравнивает снимок в A, базовом коммите слияния, с снимком в A, текущим коммитом. Это, конечно, не показывает никаких изменений. Затем Git сравнивает снимок в A с снимком в E. Git теперь объединяет два набора изменений - это объединение , конечно, тривиально - и применяет объединенные изменения к базовому снимку слияния в A и делает наш новый коммит слияния F:

A------------F   <-- master (HEAD)
 \          /
  B--C--D--E   <-- apprentice

Снимок в коммите F совпадает с коммитом в E. Но F - это новый, другой коммит, один с двумя родителями: коммит слияния. Его два родителя - A и E, в этом порядке.

Теперь мы можем git checkout apprentice и возобновить работу. Сделав еще три коммита, мы имеем:

A------------F   <-- master
 \          /
  B--C--D--E--G--H--I   <-- apprentice (HEAD)

Теперь мы можем git checkout master, переместить HEAD в master и выбрать коммит F, а затем запустить git merge apprentice. Опция --no-ff больше не требуется. Вы можете использовать его, если хотите; это не имеет никакого эффекта. база слияния из F и I является коммитом E: один шаг назад, вдоль второго родителя, от F достигает E, и три шага назад, вдоль единственного родителя доступно каждый раз, с I достигает E. Коммит E не является коммитом F, поэтому у git merge нет возможности выполнить быструю перемотку вместо слияния.

Git теперь будет отличаться E против F до посмотрите, что изменилось «вы» (опять ничего), а затем diff A против I, чтобы увидеть, что изменилось «они» (все ваши изменения, чтобы добраться до I). Затем процесс слияния объединяет их - ничего с чем-то - и применяет объединенные изменения к снимку в базе слияния E. Результат, конечно, такой же, как у снимка в I, и Git делает новый коммит с двумя родителями J, чтобы сохранить этот снимок и указать на существующие коммиты F и I:

A------------F--------J   <-- master (HEAD)
 \          /        /
  B--C--D--E--G--H--I   <-- apprentice

Теперь вы можете git checkout apprentice и продолжить работу. В любой момент вы повторяете «переключение на master и слияние», чтобы сделать новый крупный коммит (слияние). Вы переключаетесь обратно на apprentice, чтобы выполнять новые незначительные (ежедневные) коммиты, и шаблон продолжает расти.

На следующих нескольких рисунках мы можем опустить специальное имя HEAD, так как мы просто ищем в общем хранилище, а не там, где вы собираетесь сделать свой следующий коммит. Со временем ваш репозиторий продолжает расти:

A------------F--------J   <-- master
 \          /        /
  B--C--D--E--G--H--I--K--L   <-- apprentice

A------------F--------J-----M   <-- master
 \          /        /     /
  B--C--D--E--G--H--I--K--L   <-- apprentice

A------------F--------J-----M   <-- master
 \          /        /     /
  B--C--D--E--G--H--I--K--L--N--O--P   <-- apprentice

Шаблон "сшивания" здесь означает, что если вы выполните все коммиты - как git log делает по умолчанию - из кончика master, вы видите все, но если вы переходите только по ссылкам first-parent , как git log --first-parent, вы видите только основные коммиты, каждая из которых является коммитом слияния (и затем на конец, начальный коммит A).

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

1 голос
/ 27 февраля 2020

Полагаю, вы хотите, чтобы master был историей вех на apprentice. Что-то вроде:

*------------A-----------B (master)
 \            \           \
  a1--a2--a3---am--b1--b2--bm (apprentice)

Это общий рабочий процесс , когда вам нужна простая линейная история на master за счет потери некоторой истории из вашей topi c ветви.

Каждый раз, когда вы хотите обновить master, вы должны;

git checkout master
git merge --squash apprentice
git commit
# edit your commit message as you see fit the details of your squashed 
# commits will be available to you as a default merge commit
git checkout apprentice
git merge --no-ff -X theirs master

В последней строке происходит слияние без ускоренной перемотки с master в apprentice и разрешит все конфликты с изменениями из master. Это объединение полезно, потому что следующий коммит sh будет пытаться собрать sh всего от последнего общего предка. Без этого слияния ваш последний общий предок всегда будет * вместо am, bm и т. Д.

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