На самом деле это не связано с этим ответом, но я бы отказался от него git pull
, за которым git fetch
следует git merge
. Вы выполняете три слияния, которые заставят ваш Git запустить три операции выборки, когда вам достаточно одной выборки. Отсюда:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
Контроль самого сложного слияния
Самое интересное здесь git merge -X theirs
. Как заметил root545 , -X
параметры передаются стратегии слияния, и как recursive
стратегия по умолчанию , так и альтернативная resolve
стратегия принимают -X ours
или -X theirs
(то или иное, но не оба). Однако, чтобы понять, что они делают, вам нужно знать, как Git находит и обрабатывает конфликты слияния .
Конфликт слияния может возникнуть в каком-то файле 1, если базовая версия отличается как от текущей (также называемой локальной, HEAD или --ours
) версии, так и от другой (также называемой удаленной или --theirs
) версии того же файла. То есть слияние выявило три ревизии (три коммита): базовую, нашу и их. «Базовая» версия взята из базы слияния между нашей фиксацией и их фиксацией, как показано на графике фиксации (для получения дополнительной информации см. Другие сообщения StackOverflow). Затем Git обнаружил два набора изменений: «что мы сделали» и «что они сделали». Эти изменения (как правило) находятся построчно, чисто текстовымиоснование. Git не имеет реального понимания содержимого файлов; это просто сравнение каждой строки текста.
Эти изменения вы видите на git diff
выходе, и, как всегда, они имеют контекст . Возможно, что то, что мы изменили, находится в разных строках от того, что они изменили, так что кажется, что изменения не будут конфликтовать, но контекст также изменился (например, из-за того, что наше изменение было близко к верху или низу файла, так что файл в нашей версии закончился, но в их они также добавили больше текста вверху или внизу).
Если изменения происходят на разных линиях, например, мы изменяем color
к colour
строке 17 и они изменяются fred
в barney
на линии 71-то нет никакого конфликта: Git просто принимает оба изменения. Если изменения происходят в тех же строках, но являются идентичными изменениями, Git берет одну копию изменения. Только если изменения находятся в тех же строках, но представляют собой разные изменения, или этот особый случай мешающего контекста, вы получаете конфликт изменения / изменения.
Параметры -X ours
и -X theirs
сообщают Git, как разрешить этот конфликт, выбирая только одно из двух изменений: наше или их. Поскольку вы сказали, что объединяете demo
(их) с master
(нашим) и хотите изменений от demo
, вы бы захотели -X theirs
.
Однако слепое применение -X
опасно. Тот факт, что наши изменения не противоречили построчно, не означает, что наши изменения фактически не конфликтуют! Один классический пример встречается в языках с объявлениями переменных. В базовой версии может быть объявлена неиспользуемая переменная:
int i;
В нашей версии мы удаляем неиспользуемую переменную, чтобы отключить предупреждение компилятора, а в их версии они добавляют цикл на несколько строк позже, используя его i
как счетчик цикла. Если мы объединим два изменения, полученный код больше не будет компилироваться. Этот -X
вариант здесь не поможет, поскольку изменения касаются разных строк .
Если у вас есть автоматизированный набор тестов, самое важное - запустить тесты после слияния. Вы можете сделать это после фиксации и при необходимости исправить позже; или вы можете сделать это перед фиксацией, добавив --no-commit
в git merge
команду. Мы оставим детали для других публикаций.
1 Вы также можете получить конфликты в отношении операций «на уровне файла», например, возможно, мы исправим написание слова в файле (так, чтобы у нас было изменение), и они удаляют весь файл (чтобы у них был удалять). Git не разрешит эти конфликты самостоятельно, независимо от -X
аргументов.
Выполнение меньшего количества слияний и / или более умных слияний и / или использование перебазирования
В обеих последовательностях команд есть три слияния. Первый - внести origin/demo
в локальный demo
(ваши варианты использования, git pull
которые, если ваш Git очень старый, не смогут обновиться, origin/demo
но дадут тот же конечный результат). Во - вторых , чтобы принести origin/master
в master
.
Мне не понятно, кто обновляет demo
и / или master
. Если вы пишете свой собственный код в своей demo
ветке, а другие пишут код и отправляют его в demo
ветку origin
, тогда это слияние на первом этапе может иметь конфликты или производить настоящее слияние. Чаще всего для объединения работы лучше использовать rebase, чем merge (правда, это вопрос вкуса и мнения). Если это так, вы можете использовать git rebase
вместо него. С другой стороны, если вы никогда не делать какие - либо из ваших собственных фиксаций на demo
, вы даже не нужно в demo
отрасли. В качестве альтернативы, если вы хотите автоматизировать большую часть этого, но при этом иметь возможность тщательно проверять, есть ли коммиты, сделанные вами и другими, вы можете использоватьgit merge --ff-only origin/demo
: это переместит вас вперед, demo
чтобы соответствовать обновленному, origin/demo
если это возможно, и просто полностью потерпит неудачу, если нет (в этот момент вы можете проверить два набора изменений и выбрать реальное слияние или перебазирование, если это необходимо).
Эта же логика применима и к master
, хотя вы делаете слияние на master
, так что вы определенно нужны master
. Однако еще более вероятно, что вы захотите, чтобы слияние завершилось неудачно, если оно не может быть выполнено как быстрое вперед без слияния, так что это, вероятно, также должно быть git merge --ff-only origin/master
.
Допустим, вы никогда не выполняете свои собственные коммиты demo
. В этом случае мы можем полностью отказаться от названия demo
:
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
Если будут делать свои собственные demo
ветви фиксаций, это не полезно; вы также можете сохранить существующее слияние (но, возможно, добавить в --ff-only
зависимости от того, какое поведение вы хотите), или переключить его на выполнение перебазирования. Обратите внимание, что все три метода могут завершиться неудачно: слияние может завершиться сбоем с конфликтом, слияние с --ff-only
может не иметь возможности быстрой перемотки вперед, а перебазирование может завершиться сбоем с конфликтом (перебазирование, по сути, работает с помощью коммитов выбора вишни , которые используют слияние машины и, следовательно, может возникнуть конфликт слияния).
git push -f origin master