Чи є варіант git-merge --dry-run?


724

Я зливаюся у віддалену гілку, яка може мати багато конфліктів. Як я можу визначити, чи будуть конфлікти чи ні?

Я не бачу нічого подібного в положення --dry-runON git-merge.


5
Оскільки розгалуження з Git дешеве, чому б не оформити копію і тоді вам не потрібно робити пробіг? Ви можете просто викинути копію після цього.
Олександр Міллс

Відповіді:


811

Як зазначалося раніше, передайте --no-commitпрапор, але щоб уникнути швидкої передачі вперед, також перейдіть --no-ffтак:

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

Щоб переглянути поетапні зміни:

$ git diff --cached

І ви можете скасувати злиття, навіть якщо це швидке злиття вперед:

$ git merge --abort

51
Це чудово, але все одно модифікує вашу робочу копію. Якщо ваш репо є
активним

21
Ви дійсно не можете зробити злиття, не впливаючи на робочу копію.
mipadi

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 - це шістнадцятковий ідентифікатор, який друкується на попередньому кроці)

Тепер припустимо, що ви хочете об'єднати віддаленого майстра з місцевим майстром, але ви можете використовувати будь-які гілки. git merge-treeвиконає злиття в пам’яті та надрукує результат на стандартний вихід. Греп за візерунок <<або >>. Або ви можете роздрукувати вихід у файл і перевірити це. Якщо ви знайдете рядок, що починається з "змінено в обох", то, швидше за все, виникне конфлікт.


41
Ця відповідь є недооціненою, IMHO, оскільки це чисте рішення, не торкаючись робочої копії чи покажчика.
sschuberth

23
BTW, кроки 2 і 3 можна об'єднати в один крок, використовуючи оператор git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
зворотного вибору

15
Додайте до [псевдонім] у .gitconfig: dry = "! F () {git merge-tree` git merge-base $ 2 $ 1` $ 2 $ 1;}; f "#перевірте, як перейде злиття dev в master: git dry dev master
Ноель

8
Мій новий рядок GIT: git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"Просто приголомшливо! +100
Rudie

4
Перевіряючи це, я виявив прив'язку до "змінених обох" прапорів злиття, де обидві гілки модифікують один і той же файл, навіть якщо вони не призводять до конфлікту злиття. Щоб визначити лише фактичні конфлікти, я вважав за потрібне схватитись за розмітку конфлікту, яка починається так: +<<<<<<< .ourтому я використовую вираз grep на зразокgrep -q '^+<* \.our$'
Хлопець

55

Моє просте рішення жорстокої сили:

  1. Створіть відділення "попереднього майстра" (від майстра курсу)

  2. Об’єднайте всі речі, які ви хочете зробити, з цим попереднім майстром.
    Тоді ви можете побачити, як відбулося злиття, не торкнувшись майстра.

    • Об'єднайте попереднього майстра в головний АБО
    • Об’єднайте всі звільнені від гілки банери в майстер

У будь-якому разі я б дотримувався порад @ 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

EDIT: Як зазначено у коментарях нижче, якщо у вас є зміни в робочому каталозі чи області постановки, ви, ймовірно, захочете їх приховати перед тим, як зробити вищезазначене (інакше вони зникнуть після git resetвищезазначеного)


7
Просто перевірити, чи буде злиття швидким вперед (FF), це питання перевірити список git branch --contains HEADчи, навіть, безпосередньо, просто скористайтесяgit merge --ff-only
Брайан Філліпс

7
git reset --hard є однією з небагатьох команд видалення інформації без зворотного зворотного зв'язку, які має git, тому слід застосовувати її з особливою обережністю. Як такий, -1
Kzqai

8
@Tchalvak ще є рефлог.
Кіссакі

3
--dry-runне буде "просто перевірити, чи буде злиття швидким вперед". Це поверне точний результат, який злиття буде: файли, конфлікти тощо. Чи буде FF не дуже цікавим, чи не так?
Rudie

3
як щодо git stash; git reset --hard? @BrianPhillips
Whisperer Code

41

Я зробив псевдонім для цього і працює як шарм, я роблю це:

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

Зараз я просто дзвоню

git mergetest <branchname>

Щоб з’ясувати, чи є конфлікти.


Блискуче! Я зберігаю це.
qbert65536

28

Просто відрізняйте поточну гілку від віддаленої гілки, це скаже вам, що буде змінюватися, коли ви будете робити потяг / злиття.

#see diff between current master and remote branch
git diff master origin/master

1
Цікава ідея. Як я б дивився на цей вихід і визначав, чи буде злиття працювати чи ні?
MatrixFrog

6
Цей звичай не скаже вам, чи виникнуть конфлікти ... але це дасть вам загальне уявлення про те, що відбуватиметься, якщо ви зробили потяг / злиття.
тайм

10
Це лише скаже вам різницю між двома гілками, і не скаже, яким буде результат злиття. Це важлива відмінність, оскільки злиття в деяких випадках автоматично прийме зміни від різних гілок залежно від того, коли вони були вчинені. Отже, по суті, різниця може змусити вас думати, що деякі зміни будуть повернені, коли в дійсності процес злиття автоматично прийме новіші зміни в порівнянні зі старими. Сподіваюся, що це має сенс.
markquezada

3
Щоб спиратися на коментар @ mirthlab, буде значна різниця між diff і merge, якщо хтось раніше здійснив злиття зі "нашою" стратегією злиття (або якимись іншими ручними виправленнями злиття); diff також покаже вам відмінності, які вже зараховуються як "об'єднані".
Дао

21

Для цього я використовую команду request-pull git. Це дозволяє вам бачити всі зміни, які відбудуться під час об'єднання, але нічого не роблячи у ваших локальних або віддалених сховищах .

Наприклад, уявіть, що ви хочете об'єднати гілку з назвою "особливість-х" у свою головну гілку

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 для кожного зміненого файлу.


3
Ви можете зробити це трохи зрозуміліше, додавши, що masterі originробити в параметрах командного рядка, а що робити, якщо я, наприклад, локальний branch1і хочу зробити request-pullлокальну гілку функції branch2? Мені ще потрібно origin? Звичайно, документацію завжди можна прочитати.
Ela782

На жаль, ця команда працює лише у тому випадку, якщо Rev # 2 - це назва гілки, вона не працює для хешів: /
Jared Grubb

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:

--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 не зміг використати" рекурсивну "стратегію злиття" та "файл патчу дає помилку для нових файлів". Інакше здається чудовим.
нено

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
кайзер

Чистий копія може бути отримана з 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


- Тільки

Відмовтеся від злиття та виходу з ненульовим статусом, якщо поточна 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, щоб побачити, що змінилося на функції функції з головного відділення

git log does_this_branch..contain_this_branch_changes

наприклад - щоб побачити, які комісії є у ​​гілці функцій, яка не була об'єднана в головний:

git log master..feature_branch

3

Якщо ви хочете перейти з B до A, тоді ви повинні переконатися, що журнал git B..A нічого не показує, тобто A не має нічого, що B не має. Але навіть якщо B..A має щось, ви все-таки зможете злитися без конфліктів, тому вищесказане свідчить про дві речі: що буде швидкий рух вперед, і, таким чином, конфлікту ви не отримаєте.


2

Моє рішення - злитися назад.

Замість того, щоб об’єднувати свою гілку у віддалену гілку "цільової", об'єднайте її у свою.

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

Ви побачите, чи є конфлікти, і можете планувати, як їх вирішити.

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


-2

Зробіть тимчасову копію вашої робочої копії, потім зробіть її та розрізніть дві.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.