Есть ли опция git-merge --dry-run?

725

Я объединяюсь в удаленной ветке, которая может иметь много конфликтов. Как я могу определить, будут ли конфликты или нет?

Я не вижу ничего похожего --dry-runна git-merge.

эфирное масло
источник
5
Поскольку ветвление с Git обходится дешево, почему бы не получить копию, и тогда вам не нужно делать пробный прогон? Вы можете просто выбросить копию позже.
Александр Миллс

Ответы:

812

Как отмечалось ранее, передайте --no-commitфлаг, но чтобы избежать фиксации перемотки вперед, также передайте --no-ff, например, так:

$ git merge --no-commit --no-ff $BRANCH

Для изучения поэтапных изменений:

$ git diff --cached

И вы можете отменить слияние, даже если это ускоренное слияние:

$ git merge --abort
mipadi
источник
51
Это здорово, но все равно изменит вашу рабочую копию. Если ваш репозиторий является живым веб-сервером, то вы можете обслуживать файлы с конфликтами.
dave1010
21
Вы действительно не можете сделать слияние, не затрагивая рабочую копию.
Мипади
55
Правда, но что-то вроде git merge --only-if-there-wont-be-any-conflictsили git diff --show-conflicts <commit>было бы очень удобно. Позор, это еще не возможно, или я что-то упустил?
dave1010
344
@ dave1010 Вы никогда не должны обрабатывать слияния на живом веб-сервере !!! Вот для чего предназначена ваша разработка! Исправьте ветку "prod" и затем отправьте ее на настоящий веб-сервер.
jpswain
52
Если вы работаете на живом / производственном сервере, вы никогда не захотите ничего делать, кроме git pull --ff-only!
ThiefMaster
237

Мне просто нужно было реализовать метод, который автоматически находит конфликты между хранилищем и его удаленным. Это решение выполняет слияние в памяти, поэтому оно не затрагивает ни индекс, ни рабочее дерево. Я думаю, что это самый безопасный способ решить эту проблему. Вот как это работает:

  1. Принесите пульт в ваш репозиторий. Например: git fetch origin master
  2. Запустите git merge-base: git merge-base FETCH_HEAD master
  3. Запустите git merge-tree: git merge-tree mergebase master FETCH_HEAD( mergebase - шестнадцатеричный идентификатор, который merge-base напечатал на предыдущем шаге)

Теперь предположим, что вы хотите объединить удаленный мастер с вашим локальным мастером, но вы можете использовать любые ветви. git merge-treeвыполнит объединение в памяти и выведет результат на стандартный вывод. Grep для шаблона <<или >>. Или вы можете распечатать вывод в файл и проверить это. Если вы обнаружите строку, начинающуюся с «изменено в обоих», то, скорее всего, возникнет конфликт.

akostajti
источник
41
ИМХО этот ответ недооценен, поскольку это чистое решение, не затрагивающее рабочую копию или указатель.
sschuberth
23
Кстати, шаги 2 и 3 можно объединить в один шаг, используя оператор backtick консоли Linux, который оценивает его содержимое на месте:git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
jakub.g
15
Добавьте к [alias] в .gitconfig: dry = "! F () {git merge-tree` git merge-base $ 2 $ 1` $ 2 $ 1;}; f "# проверьте, как будет происходить слияние dev в master: git dry Мастер разработки
Ноэль
8
Моя новая любимая линия GIT: git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"просто потрясающе! +100
Руди
4
При тестировании этого я обнаружил, что для слияния флагов «изменено в обоих» было обнаружено, что обе ветви изменяют один и тот же файл, даже если они не приводят к конфликту слияния. Чтобы определить только реальные конфликты, я счел необходимым использовать grep для разметки конфликтов, которая начинается следующим образом: +<<<<<<< .ourпоэтому я использую выражение grep, например,grep -q '^+<* \.our$'
Guy
55

Мое простое решение проблемы грубой силы:

  1. Создайте ветку «pre-master» (конечно же, от мастера)

  2. Объедините все, что вы хотите, с этим предварительным мастером.
    Тогда вы сможете увидеть, как произошло слияние, не касаясь мастера.

    • Объединить pre-master в master ИЛИ
    • Объедините все ветки, выпущенные подражателями, в мастера

В любом случае, я бы следовал совету @ orange80.

Аид
источник
5
Мне нравится решение @akostajti, но это еще один недооцененный вариант. На самом деле я предпочитаю защищаться и создавать новую временную ветвь (конечно, только когда я ожидаю конфликтов, иначе это будет перебор), и если что-то пойдет не так, просто удалите его.
jakub.g
1
Не знаю, грязное ли это решение или нет, но оно действительно делает свою работу. Мне это нравится! (Y)
Сара
3
Это должно быть принятое решение, IMO. Это быстрый, простой, безопасный, обратимый, интуитивно понятный интерфейс, и до тех пор, пока перед запуском не произойдет никаких изменений, у него не будет побочных эффектов.
Боб Рэй
3
Это решение говорит вам, что вы не понимаете, как работает git. Ветви - это просто указатели, а вы создаете только избыточный указатель. У вас плохое предчувствие, что вы можете как-то повредить слияние веток, но не можете. Вы всегда можете сделать, git merge --abortесли есть конфликты, git reset --hard HEAD~1если произошло слияние или git reset --hard origin/master. Создание другой ветки дает вам чувство безопасности, но если вы узнаете, как работает git, вы поймете, что это неуместный страх. Когда проблема заключается в том, чтобы не менять рабочую копию, это не дает решения.
Тибо Д.
@ thibault-d Подумайте, насколько сложным является решение, когда вы не начинаете с чистой ветки. git merge --no-commitне прервет слияние, если его можно быстро переслать. git merge --abortне работает, если он был объединен. Если вы хотите написать это как скрипт, это неловко, так git mergeкак не отвечает достаточно хорошими кодами ошибок, чтобы объяснить различные типы конфликтов. Работа со свежей веткой не позволяет сломанному сценарию оставлять репо в состоянии, требующем ручного вмешательства. Конечно, вы ничего не можете потерять. Но проще построить иначе.
Эрик Аронесты
47

Отменить слияние с git так легко, что вам даже не стоит беспокоиться о пробном запуске:

$ git pull $REMOTE $BRANCH
# uh oh, that wasn't right
$ git reset --hard ORIG_HEAD
# all is right with the world

РЕДАКТИРОВАТЬ: Как отмечено в комментариях ниже, если у вас есть изменения в вашем рабочем каталоге или промежуточной области, вы, вероятно, захотите сохранить их перед выполнением вышеупомянутых действий (в противном случае они исчезнут после git resetвышеуказанного)

Брайан Филлипс
источник
7
Просто проверить, будет ли слияние ускоренной (FF), - это вопрос проверки списка git branch --contains HEADили даже более прямой, просто используйтеgit merge --ff-only
Brian Phillips
7
git reset --hard - это одна из немногих команд git, которая позволяет удалять информацию, не имея при этом отказа, поэтому ее следует использовать с особой осторожностью. Таким образом, -1
Kzqai
8
@Tchalvak еще есть рефлог.
Киссаки
3
--dry-runне будет «просто проверять, будет ли слияние ускоренным». Он вернул бы точный результат, который произойдет при слиянии: файлы, конфликты и т. Д. Будет ли ff не очень интересным, не так ли?
Руди
3
как насчет git stash; git reset --hard? @BrianPhillips
код Whisperer
41

Я сделал псевдоним для этого и работает как шарм, я делаю это:

 git config --global alias.mergetest '!f(){ git merge --no-commit --no-ff "$1"; git merge --abort; echo "Merge aborted"; };f '

Теперь я просто звоню

git mergetest <branchname>

Чтобы выяснить, есть ли какие-либо конфликты.

Okonomiyaki3000
источник
Brilliant! Я держу это.
qbert65536
28

Просто сравните вашу текущую ветку с удаленной веткой, это скажет вам, что изменится, когда вы сделаете вытягивание / слияние.

#see diff between current master and remote branch
git diff master origin/master
timh
источник
1
Интересная идея. Как бы я посмотрел на этот вывод и определил, будет ли слияние работать или нет?
MatrixFrog
6
Это не скажет вам, возникнут ли какие-либо конфликты ... но это даст вам общее представление о том, что произойдет, если вы сделали вытягивание / слияние.
Тим
10
Это только скажет вам разницу между двумя ветвями, но не скажет, каким будет результат слияния. Это важное различие, так как в некоторых случаях слияние будет автоматически принимать изменения из разных веток в зависимости от того, когда они были зафиксированы. Таким образом, по сути, выполнение diff может заставить вас думать, что некоторые из ваших изменений будут отменены, когда в действительности процесс слияния автоматически примет более новые изменения по сравнению со старыми. Надеюсь, что это имеет смысл.
markquezada
3
Если опираться на комментарий @ mirthlab, между diff и merge будет существенная разница, если кто-то ранее выполнил слияние со "нашей" стратегией слияния (или некоторыми другими ручными исправлениями слияния); Разница также покажет вам различия, которые уже считаются «объединены».
Тао
21

Я использую команду request-pull git для этого. Это позволяет вам видеть все изменения, которые могут произойти при слиянии, но без каких-либо изменений в локальных или удаленных репозиториях .

Например, представьте, что вы хотите объединить ветку с именем «feature-x» в вашу основную ветку

git request-pull master origin feature-x

покажет вам сводку того, что произойдет (не делая ничего):

The following changes since commit fc01dde318:
    Layout updates (2015-06-25 11:00:47 +0200)
are available in the git repository at:
    http://fakeurl.com/myrepo.git/ feature-x
for you to fetch changes up to 841d3b41ad:
----------------------------------------------------------------
john (2):
    Adding some layout
    Refactoring
ioserver.js            |   8 +++---
package.json           |   7 +++++-
server.js              |   4 +--
layout/ldkdsd.js       | 277 +++++++++++++++++++++++++++++++++++++
4 files changed, 289 insertions(+), 7 deletions(-)
create mode 100644 layout/ldkdsd.js

Если вы добавите -pпараметр, вы также получите полный текст патча, точно так же, как если бы вы делали git diff для каждого измененного файла.

ArnaudR
источник
3
Вы могли бы сделать это немного яснее, добавив что masterи originделать в параметрах командной строки, и что если я, например, нахожусь в локальной сети branch1и хочу сделать request-pullлокальную ветвь функций branch2? Мне все еще нужно origin? Конечно, всегда можно прочитать документацию.
Ela782
К сожалению, эта команда работает, только если Rev # 2 является именем ветви, она не работает для хэшей: /
Джаред Грубб,
20

Я удивлен, что никто еще не предложил использовать патчи.

Допустим , вы хотите проверить слияние с your_branchв master(я предполагаю , что вы masterпроверили):

$ git diff master your_branch > your_branch.patch
$ git apply --check your_branch.patch
$ rm your_branch.patch

Это должно делать свое дело.

Если вы получаете ошибки, такие как

error: patch failed: test.txt:1
error: test.txt: patch does not apply

это означает, что патч не был успешным, и слияние приведет к конфликтам. Отсутствие вывода означает, что патч чистый, и вы сможете легко объединить ветку


Обратите внимание, что это на самом деле не изменит ваше рабочее дерево (кроме создания файла исправления, конечно, но вы можете безопасно удалить его впоследствии). Из документации git-apply:

--check
    Instead of applying the patch, see if the patch is applicable to the
    current working tree and/or the index file and detects errors. Turns
    off "apply".

Примечание для тех, кто умнее / более опытен с git, чем я: пожалуйста, дайте мне знать, если я ошибаюсь, и этот метод показывает поведение, отличное от обычного слияния. Кажется странным, что за 8 с лишним лет, когда этот вопрос существовал, никто не предложил бы это, казалось бы, очевидное решение.

Кристоф Бемвальдер
источник
Этот метод является приемлемым ответом на этот вопрос, и в комментариях есть некоторые оговорки, такие как «git не смог использовать« рекурсивную »стратегию слияния» и «файл патча дает ошибку для новых файлов». В противном случае кажется великолепным.
neno
1
Более короткий путь без создания временного файла заплатки: git diff master your_branch | git apply --check.
ks1322
9

Это может быть интересно: из документации:

Если вы попытались выполнить слияние, которое привело к сложным конфликтам, и хотите начать заново , вы можете восстановить с помощью git merge --abort .

Но вы также можете сделать это наивным (но медленным) способом:

rm -Rf /tmp/repository
cp -r repository /tmp/
cd /tmp/repository
git merge ...
...if successful, do the real merge. :)

(Примечание: это не сработает, просто клонируя в / tmp, вам понадобится копия, чтобы быть уверенным, что незафиксированные изменения не будут конфликтовать).


источник
2
Если все, что вам нужно, это молоток ... :) +1
kaiser
Чистая копия может быть получена с cp -r repository/.git /tmp/repository/.git, cd /tmp/repository, git reset --hard, git add --all, git reset --hard(для хорошей меры), git status(убедиться , что он чист).
ADTC
8

Я знаю, что это старый вопрос, но он появляется первым в поиске Google.

Git ввел опцию --ff-only при слиянии.

От: http://git-scm.com/docs/git-merge


--ff только

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

Выполнение этого попытается объединить и выполнить перемотку вперед, и если это не удастся, он прекратит работу и предложит вам, что перемотка вперед не может быть выполнена, но оставит вашу рабочую ветку нетронутой. Если он может выполнить ускоренную перемотку вперед, он выполнит объединение в вашей рабочей ветви. Эта опция также доступна на git pull. Таким образом, вы можете сделать следующее:

git pull --ff-only origin branchA #See if you can pull down and merge branchA

git merge --ff-only branchA branchB #See if you can merge branchA into branchB
Джейсон Маккиндли
источник
1
Это сделает слияние, если это можно сделать с помощью ускоренной перемотки вперед, а это не то, что я хотел в первоначальном вопросе. Я думаю, что у принятого ответа есть другая половина, которая это исправляет.
Отто
Правда, причудливые подсказки мерзавцев избавляют меня от необходимости в подобных вещах.
Отто
2
Это не совсем то же самое. Выход с ненулевым статусом, потому что слияние не может быть решено, так как ускоренная перемотка вперед не означает, что есть конфликты . Это просто означает, что история разошлась и необходим коммит слияния.
ADTC
7

Я использую git log, чтобы увидеть, что изменилось в ветви функций из основной ветви.

git log does_this_branch..contain_this_branch_changes

например, чтобы увидеть, что коммиты находятся в ветви функций, которые были / не объединены с master:

git log master..feature_branch
nelsonenzo
источник
3

Если вы хотите быстро перейти от B к A, то вы должны убедиться, что git log B..A ничего не показывает, то есть A не имеет ничего, чего нет у B. Но даже если у B..A есть что-то, вы все равно сможете объединяться без конфликтов, поэтому вышеизложенное показывает две вещи: что будет ускоренная перемотка вперед, и, следовательно, у вас не будет конфликта.

Эрик Каплун
источник
2

Мое решение состоит в том, чтобы слиться в обратном направлении.

Вместо того, чтобы объединить вашу ветку с удаленной «целевой» веткой, объедините эту ветку с вашей.

git checkout my-branch
git merge origin/target-branch

Вы увидите, есть ли какие-либо конфликты и сможете спланировать, как их решить.

После этого вы можете либо прервать слияние с помощью git merge --abort, либо (если не было никаких конфликтов и произошло слияние) откатиться к предыдущей фиксации с помощьюgit reset --hard HEAD~1

Ubeogesh
источник
-2

Сделайте временную копию вашей рабочей копии, затем объединитесь с ней и разведите их.

vanboom
источник