Як я можу переглянути попередній злиття в git?


397

У мене є гіт git (основна лінія, наприклад), і я хочу об'єднатися в іншу галузь розвитку. Або я?

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

Поки що найкраще я можу придумати - merge --no-ff --no-commitі тоді diff HEAD.


17
Я просто git mergeі, git reset --keep HEAD@{1}якщо результат мені не подобається.
Ян Худек,

3
Зауважте, що перегляд списку комітетів з їх різницею не обов'язково розповідає всю історію - якщо злиття нетривіальне, а особливо, якщо є конфлікти, фактичний результат об'єднання може бути трохи цікавим.
Каскабель

2
Ваш оригінальний метод робить саме це. Суть мого коментаря полягає в тому, що, хоча перегляд окремих відмінностей - це все добре і добре, якщо у вас складене злиття, ви можете закінчитись дивовижними результатами, навіть якщо всі об'єднані комісії незалежно хороші.
Каскабель

2
@Jan: З яких причин git reset --keep HEAD@{1}повернули fatal: Cannot do a keep reset in the middle of a merge.Довідку?
moey

3
Чому --previewв git-merge немає опції?
Гауї

Відповіді:


283

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

Однак якщо ви хочете переконатися, що ви не зіпсуєте свою поточну гілку, або ви просто не готові до злиття незалежно від наявності конфліктів, просто створіть нову підгалузь із неї та об'єднайте:

Стратегія 1: Безпечний спосіб - злиття тимчасової гілки:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

Таким чином ви можете просто викинути тимчасову гілку, якщо ви просто хочете побачити, що таке конфлікти. Вам не потрібно заважати "переривати" злиття, і ви можете повернутися до своєї роботи - просто замовте "mybranch" ще раз, і у вас не буде конфлікту злитого коду або злиття.

Це в основному сухий хід.

Стратегія 2: Коли ви напевно хочете об'єднатись, але тільки якщо немає конфліктів

git checkout mybranch
git merge some-other-branch

Якщо git повідомляє про конфлікти (і ТІЛЬКО, якщо в них є конфлікти), ви можете зробити:

git merge --abort

Якщо злиття успішно, ви не можете його скасувати (лише скинути).

Якщо ви не готові до злиття, скористайтеся вище безпечним способом.

[EDIT: 2016-листопад - я змінив стратегію 1 на 2, тому що, здається, більшість людей шукають "безпечний шлях". Стратегія 2 тепер більше зауважує, що ви можете просто перервати злиття, якщо злиття має конфлікти, з якими ви не готові мати справу. Майте на увазі, читаючи коментарі!]


2
+1 для стратегії 2. Тимчасова гілка, яка показує, що саме буде входити при злитті. Стратегія 1 - це те, чого я намагаюся уникати для цього конкретного випадку.
Гордоліо

2
Я пропоную змінити стратегію, щоб спочатку була безпечніша (проходить моє психічне навчання - більшість людей вважають, що найкращим варіантом буде перший, незважаючи на чітке використання слова "безпечніший"), але, крім цього, відмінним робота.
paxdiablo

6
Ви можете зробити це, git merge --no-ff --no-commitякщо не хочете здійснювати зміни безпосередньо. Це виключає "потребу" в іншій гілці, робить її трохи простіше переглянути зміни, imo.
Джерард ван Хелден

і якщо ви вирішите, що ви взагалі не хочете об'єднуватись, і насправді, скоріше, напишіть ще якийсь код, а потім покладетеся на свою філію, щоб ви могли розгорнути ВІДПОВІДЬ свою філію на тестовому сервері, чи не все-таки вам доведеться повернути це git merge --no-ff --no-commit? Я думаю, ви все ще можете зробити це git merge --abort, якщо вам не сподобається те, що ви бачите? Навіть якщо злиття не створює конфліктів?
Kasapo

Більшість людей люблять копіювати та вставляти і не надто думають. Тому для Стратегії 1, можливо, також додамо, як скасувати злиття у тимчасовій локальній гілці, git reset --hard HEADа потім перевірити іншу гілку git checkout <different branch name>та видалити тимчасову гілку git delete -b <name of temporary branch>.
користувач3613932

400
  • git log ..otherbranch
    • перелік змін, які будуть об'єднані в поточну галузь.
  • git diff ...otherbranch
    • відрізняється від загального предка (злиття бази) до голови того, що буде злито. Зверніть увагу на три крапки , які мають особливе значення порівняно з двома крапками (див. Нижче).
  • gitk ...otherbranch
    • графічне зображення гілок, оскільки вони були об'єднані востаннє.

Порожній рядок має на увазі HEAD, так що саме тому ..otherbranchзамість HEAD..otherbranch.

Дві та три крапки мають дещо інше значення для відмінності, ніж для команд, що перелічують версії (log, gitk тощо). Для журналу та інших двох крапок ( a..b) означає все, що є, bале немає, aа три крапки ( a...b) означає все, що є лише в одній з aабо b. Але diff працює з двома редакціями, і там простіший випадок, представлений двома крапками ( a..b), є простою різницею від aдо bі трьома крапками ( a...b) означає різницю між загальним предком і b( git diff $(git merge-base a b)..b).


7
Третя крапка була тією частиною, яку мені не вистачало, дякую! Підхід до журналу також добре працює, журнал -p - зворотний .. інший відгалуження здається гарним способом побачити, що було б об'єднано.
Glenjamin

1
Я пропав, git checkout masterперш ніж спробувати це. Мені було цікаво, чому це говорить про те, що всі мої зміни будуть переписані ...
Droogans

5
git show ..otherbranchпокаже список змін та відмінностей, які будуть об'єднані у поточну гілку.
Гауї

4
Це не зовсім точно, особливо для вишні.
void.pointer

2
@ void.pointer, git не розглядає вишні особливо в звичайному злитті, тому його також немає. Можна було б написати стратегію злиття, але, наскільки я знаю, вона ніколи не була.
Ян Худек

19

Якщо ти схожий на мене, ти шукаєш рівнозначного svn update -n. Здається, що зробити трюк. Зауважте, що переконайтеся, що спочатку потрібно зробити git fetchтак, щоб місцева репорта мала відповідні оновлення для порівняння.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

або якщо ви хочете відрізнятись від голови до віддаленого:

$ git fetch origin
$ git diff origin/master

ІМО це рішення набагато простіше і менш схильний до помилок (і, отже, набагато менш ризикований), ніж верхнє рішення, яке пропонує "об'єднати, то скасувати".


1
має бути $ git checkout target-branchі тоді $ git diff --name-status ...branch-to-be-merged(три крапки важливі, тому введіть їх як є)
Lu55

Одного цього відсутнє: він не показує, які файли мали б конфлікт - вони мають той самий маркер "M", що і файли, які були змінені на гілці, але їх можна об'єднати без будь-яких конфліктів.
peterflynn

Можливо, у 2012 році все було інакше, але в цей час переривання злиття здається досить надійним, тому я не думаю, що зараз справедливо характеризувати це як "набагато простіше і менш схильне до помилок".
David Z

8

Більшість відповідей тут або вимагають чистого робочого каталогу та декількох інтерактивних кроків (погано для сценаріїв), або не працюють у всіх випадках, наприклад, минулі злиття, які вже вносять деякі видатні зміни у вашу цільову гілку, або вишні, які роблять те саме.

Щоб по-справжньому побачити, що зміниться у masterгілці, якби ви об’єдналися developв неї, прямо зараз:

git merge-tree $(git merge-base master develop) master develop

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

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

- https://git.seveas.net/previewing-a-merge-result.html

(дякую Девіду Нормінгтону за посилання)

PS:

Якщо у вас з'являться конфлікти злиття, вони відображатимуться зі звичайними маркерами конфліктів у висновку, наприклад:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

Користувач @dreftymac робить хороший момент: це робить його непридатним для сценаріїв, тому що ви не можете легко зрозуміти це з коду статусу. Маркери конфлікту можуть бути дуже різними залежно від обставин (видалено проти модифікованих тощо), що також важко сприймає. Остерігайся.


1
@hraban Це схоже на правильну відповідь, однак, мабуть, є один недолік. Цей підхід вимагає від користувача «очного яблука» виводу, щоб побачити, чи є маркери конфлікту. Чи є у вас підхід, який просто повертається, trueякщо є конфлікти і falseякщо немає конфліктів (наприклад, булева цінність, яка не вимагає тесту «очного яблука» чи будь-якого втручання людини).
dreftymac

1
@dreftymac нічого не може знайти для цього. ви можете використовувати щось на кшталт, git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergeале це вибагливо; Я, мабуть, забуваю випадок. можливо, ви хочете замість цього перевірити маркери конфлікту? наприклад, це, ймовірно, не сприймає конфлікти стилів "їх видалено, наші змінили". (Я щойно перевірив, і це навіть не показує маркери конфлікту, тому вам потрібен ретельний вираз, щоб бути тут безпечним)
hraban

1
Використовуйте less -Rдля обробки кольорового виводу без зміни вашої конфігурації.
Джакомо Альзетта

Дякую @GiacomoAlzetta, я оновив його.
hraban

6

Якщо ви вже знайшли зміни, моя улюблена:

git log ...@{u}

Для цього потрібен git 1.7.x Я все ж вважаю. @{u}Позначення є «скорочена» для висхідного потоку гілки , так що це трохи більш універсальний , ніж git log ...origin/master.

Примітка. Якщо ви використовуєте zsh та розширений glog, вам, ймовірно, доведеться зробити щось на кшталт:

git log ...@\{u\}

6

Додаючи до існуючих відповідей, псевдонім може бути створений для показу розрізнення та / або журналу перед об'єднанням. Багато відповідей опускають те, fetchщо потрібно зробити спочатку перед "попереднім переглядом" об'єднання; це псевдонім, який поєднує ці два кроки в один (емілюючи щось подібне до mercurial's hg incoming/ outgoing)

Отже, спираючись на " git log ..otherbranch", ви можете додати таке ~/.gitconfig:

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

Для симетрії можна використовувати наступний псевдонім, щоб показати, що зроблено і що було б натиснуто, перед натисканням:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

І тоді ви можете запустити " git incoming", щоб показати багато змін, або " git incoming -p" показати патч (тобто "diff"), " git incoming --pretty=oneline", щоб отримати короткий підсумок тощо. Потім ви можете (необов'язково) запустити "git pull " насправді зливаються. (Хоча, оскільки ви вже зібрали, злиття можна зробити безпосередньо.)

Так само " git outgoing" показує, що було б натиснуто, якби ви бігали " git push".


3

git log currentbranch..otherbranchнадасть вам список комітетів, які ввійдуть у поточну гілку, якщо ви зробите об'єднання. Звичайні аргументи для входу в журнал, які дають інформацію про коміти, дадуть вам більше інформації.

git diff currentbranch otherbranchдасть вам різницю між двома зобов'язаннями, які стануть одним. Це буде різниця, яка дає вам усе, що злиється.

Чи допомогли б вони?


2
Власне, неправильно. git log otherbranch..currentbranchдає список комітетів на поточній галузі . Це git diff otherbranch currentbranchдає вам відмінність від версії для злиття до поточної підказки, що настільки ж марно, як це може бути, тому що те, що ви хочете, відрізняється від основи злиття до головки злиття.
Ян Худек,

Дякую. Я змінив назви дерев.
Нуфал Ібрагім

3

Запит на витяг - я використовував більшість вже поданих ідей, але один, який я також часто використовую, - це особливо, якщо це від іншого розробника), виконуючи запит на витягнення, який дає зручний спосіб переглянути всі зміни в об'єднанні, перш ніж він займеться місце. Я знаю, що це GitHub не git, але це впевнено зручно.


2

Окрім того, що насправді виконують злиття у викиданні (див. Відповідь Касапо), здається, це не є надійним способом побачити це.

Сказавши це, ось метод, який гранично близький:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Це дає справедливу вказівку, які коміти перетворять їх на злиття. Щоб побачити відмінності, додайте -p. Щоб побачити імена файлів, додати будь-який з --raw, --stat, --name-only,--name-status .

Проблема з git diff TARGET_BRANCH...SOURCE_BRANCHпідходом (див. Відповідь Яна Гудека) полягає в тому, що ви побачите різницю для змін вже у вашій цільовій гілці, якщо ваша вихідна гілка містить перехресні злиття.


1

Може, це може вам допомогти? git-diff-tree - порівнює вміст і режим крапок, знайдених через два об’єкти дерева


1

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

Ось мій спосіб вирішення, якщо він допомагає комусь іншому:

У цьому сценарії у мене є філія під назвою QA, яка змінила багато змін із часу останнього випуску продукції. Наш останній випуск продукції позначений "15.20.1". У мене є ще одна галузь розвитку під назвою new_stuff, яку я хочу об'єднати у гілку QA. Як QA, так і new_stuff вказують на зобов'язання, які "слідують" (як повідомляє gitk) тег 15.20.1.

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Ось кілька дискусій, які стосуються того, чому мені цікаво орієнтуватися на ці конкретні файли:

Як я можу довірити злиття Git?

/software/199780/how-far-do-you-trust-automerge

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