Каков наиболее эффективный способ объединить вышестоящие изменения в рабочую копию с Git? - PullRequest
0 голосов
/ 29 сентября 2018

Очень распространенный сценарий, возникающий, когда люди пишут код, состоит в том, чтобы привести себя (скажем, ветвь функций, над которой вы работаете) в актуальное состояние.Это может привести к «конфликту» одного и того же файла, который был изменен как в восходящем потоке, так и в вашем рабочем дереве .Мой вопрос: Каков самый прямой способ решить этот тип конфликта с Git .

В частности, я ищу что-то краткое и дающее хорошую видимость (то есть зная, что происходит,потому что иногда конфликты выходят за рамки автоматического разрешения, и хотелось бы знать это до слияния).Что-то лучше, чем это:

# I'm on a branch, have changes in working tree,
  # have overlapping change in remote; for simplicity,
  # assume no local (unpushed) commits have been made (clean HEAD)

git fetch
git difftool origin/<branchName> HEAD   # visually examine incoming changes, to understand them; conclude that the changes are automatically merge-able

#git merge              # fails: "Your local changes to the following files would be overwritten by merge:"
#git merge -s resolve   # fails: same
#git merge -s recursive # fails: same
#git mergetool          # no-op: "No files need merging" ?!

git stash
git pull
git stash pop

git difftool HEAD    # visually examine outcome - it worked, but does stashing really need to be involved?

Другие ответы касались коммитов после выборки, что для меня нет, на этой стадии мне нечего коммитить.Что я хочу, так это привести себя (то есть мое рабочее дерево ) в соответствие с последним.

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018

Если у вас есть изменения - т. Е. Грязное рабочее дерево - , вам нужно что-то зафиксировать .Самое большее, у вас есть что-то, что вы хотите временно временно .

В других системах контроля версий вы можете сделать это, зафиксировав это в ветке.В Git вы тоже можете сделать это: у вас нет для использования ветки, но это может быть и самый удобный способ справиться с этим и в Git.

Вы упомянулиначальный сценарий, для которого у меня есть рабочий шаблон, который я нахожу полезным:

Очень распространенный сценарий, возникающий, когда люди пишут код, состоит в том, чтобы принести себя (скажем, ветвь функций, над которой вы работаете)on) актуальный.

Допустим, вы работаете над feature-X, который в конечном итоге будет помещен в dev (ветка разработки).Другие разработчики работали над функциями Y и Z, и один из них завершен, и dev теперь обновлен, поэтому вы запускаете:

$ git fetch

и видите, что ваш dev теперь отстает от origin/dev,То есть теперь у вас есть:

...--C--D--H   <-- master
         \
          \         I--J   <-- origin/dev
           \       /
            E--F--G   <-- dev, feature-X (HEAD)

в вашем хранилище.У вас также есть некоторые вещи в вашем рабочем дереве, которые отличаются от файлов в коммите G.(Возможно, у вас еще нет ветви с именем feature-X, и вместо нее HEAD присоединен к dev. Если это так, вы можете просто создать его сейчас с помощью git checkout -b feature-X, и теперь вы соответствуете изображению.)

На этом этапе нужно сделать то, над чем вы работаете.Это делает один новый коммит K:

...--C--D--H   <-- master
         \
          \         I--J   <-- origin/dev
           \       /
            E--F--G   <-- dev
                   \
                    K feature-X (HEAD)

Теперь вы можете перемотать свой собственный dev до origin/dev.Основной метод команды:

$ git checkout dev                 # safe, since your work is committed
$ git merge --ff-only origin/dev   # or `git pull` if you really insist

Рисунок теперь выглядит так:

...--C--D--H   <-- master
         \
          \
           \
            E--F--G--I--J   <-- dev (HEAD), origin/dev
                   \
                    K   <-- feature-X (HEAD)

Вот где большинство людей просто запускают git checkout feature-X; git rebase dev, , что хорошо и вы должны смело использовать этот метод.(Я делаю это большую часть времени. Подумайте об этом, следуя описанному ниже приему git reset HEAD^.) Но иногда я просто делаю переименовываю feature-X в feature-X.0, а затем создаю new feature-X с git checkout -b feature-X:

...--C--D--H   <-- master
         \
          \
           \
            E--F--G--I--J   <-- dev, origin/dev, feature-X (HEAD)
                   \
                    K   <-- feature-X.0

Теперь я готов снова начать работу над feature-X, и в этот момент я просто выбираю все feature-X.0 commitits:

$ git cherry-pick dev..feature-X.0

, который производит коммит K', который является копией K:

...--C--D--H   <-- master
         \
          \               K'  <-- feature-X (HEAD)
           \             /
            E--F--G--I--J   <-- dev, origin/dev
                   \
                    K   <-- feature-X.0

Это работает, даже если на feature-X.0 есть несколько коммитов:

...--C--D--H   <-- master
         \
          \               K'-L'  <-- feature-X (HEAD)
           \             /
            E--F--G--I--J   <-- dev, origin/dev
                   \
                    K--L   <-- feature-X.0

Если последний коммит этого нового feature-X (L' в этой версии, K' в том, который имел только один коммит), действительно, серьезно не-готов к принятию, на данный момент я просто использую git reset HEAD^ (можно записать HEAD~, если это проще, как, очевидно, имеет место в Windows), чтобы переместить имя ветви на один шаг назад.Это удаляет самый последний коммит из текущей ветви, давая:

...--C--D--H   <-- master
         \
          \               K'  <-- feature-X (HEAD)
           \             /
            E--F--G--I--J   <-- dev, origin/dev
                   \
                    K--L   <-- feature-X.0

и оставляет «грязное» рабочее дерево таким же, каким оно было до того, как я начал весь этот процесс.(В общем, частичная фиксация - это хорошо, так как я буду использовать git rebase -i позже, чтобы очистить все, когда feature-X в основном готов.)

Если по какой-либо причине мне придется повторить процесс,Я переименовываю текущее состояние feature-X в feature-X.1, или feature-X.2, или как угодно.Я выращиваю небольшую коллекцию feature-X, и иногда выхожу в сад и обрезаю самых слабых. Самая последняя и самая лучшая версия по-прежнему называется feature-X, но у меня есть все мои предыдущие работы, доступные по мере необходимости, до тех пор, пока я их не отсею. Это лучше, чем перебазировка или stash, потому что, если код сложный и я что-то пропустил, у меня все еще есть более старая версия под узнаваемым именем, а не просто какой-то непонятный хэш-идентификатор в журнале ссылок и не тайник, который неотличим от дюжины других тайников.

0 голосов
/ 29 сентября 2018

Я думаю, что отказ от слияния - плохая идея:

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

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

Если у вас огромная ветка, котораяскоро будет очень много конфликтов, я бы предложил закончить патчи, над которыми вы работаете, до слияния, чтобы у вас не было «черновых» патчей в вашей истории, когда вам нужно будет поместить свои вещи в общий gitрепозиторий.

Я лично использую вариант 1, даже если у меня много ожидающих исправлений.Это позволяет мне повторно проверять каждый патч при выполнении ребазинга, а также предотвращает «злые слияния», которые мне не нравятся (сделайте git blama болезненным, ИМХО).

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

...