Git
перебазировка
Поиск…
Синтаксис
-
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
-
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-
git rebase --continue | --skip | --abort | --edit-todo
параметры
параметр | подробности |
---|---|
--Продолжить | Перезапустите процесс перезагрузки после разрешения конфликта слияния. |
--abort | Отмените операцию перезагрузки и сбросьте HEAD в исходную ветвь. Если ветвь была предоставлена при запуске операции переадресации, то HEAD будет сброшен в ветвь. В противном случае HEAD будет сбрасываться до того места, где была начата операция перезагрузки. |
--keep пусто | Держите коммиты, которые ничего не меняют от родителей в результате. |
--пропускать | Перезапустите процесс перезагрузки, пропустив текущий патч. |
-m, --merge | Используйте стратегии объединения для перерасчета. Когда используется рекурсивная (по умолчанию) стратегия слияния, это позволяет переупаковать, чтобы знать о переименованиях на стороне выше по течению. Обратите внимание, что слияние рефаймов работает, переигрывая каждую фиксацию из рабочей ветви поверх верхней ветви. Из-за этого, когда происходит конфликт слиянием, сторона, о которой сообщается, как наша, является так называемой переустановленной серией, начиная с восходящего потока, а их рабочая ветвь. Другими словами, стороны меняются местами. |
--stat | Покажите diffstat того, что изменилось вверх по течению с момента последней перезагрузки. Диффестат также управляется параметром конфигурации rebase.stat. |
-x, --exec command | Выполнять интерактивную перезагрузку, останавливаясь между каждой command фиксации и выполнением command |
замечания
Имейте в виду, что rebase эффективно перезаписывает историю хранилища.
Повторные фиксации, существующие в удаленном репозитории, могут переписывать узлы репозитория, используемые другими разработчиками в качестве базового узла для их разработки. Если вы действительно не знаете, что делаете, лучше переустановить, прежде чем нажимать ваши изменения.
Локальная реинжиниринг
Rebasing повторяет серию коммитов поверх другой фиксации.
Чтобы rebase
ветвь, проверьте ветку, а затем rebase
ее поверх другой ветви.
git checkout topic
git rebase master # rebase current branch onto master branch
Это приведет к:
A---B---C topic
/
D---E---F---G master
Превратиться в:
A'--B'--C' topic
/
D---E---F---G master
Эти операции можно объединить в одну команду, которая проверяет ветвь и немедленно ее переустанавливает:
git rebase master topic # rebase topic branch onto master branch
Важно: после переустановки применяемые коммиты будут иметь другой хеш. Вы не должны переустанавливать фиксацию, которую вы уже нажали на удаленный хост. Следствием может быть неспособность git push
вашу локальную ветвь с переустановкой на удаленный хост, оставив ваш единственный вариант git push --force
.
Rebase: наши и их, местные и удаленные
Базеба переключает значение «наш» и «их»:
git checkout topic
git rebase master # rebase topic branch on top of master branch
Независимо от того, что говорит HEAD, это «наш»,
Первое, что делает rebase, - это сброс HEAD
на master
; до того, как вишневый сбор перейдет из старой ветвиной topic
в новую (каждая фиксация в ветке прежней topic
будет переписана и будет идентифицирована другим хэшем).
Что касается терминологии, используемой средствами слияния (не путать с локальным ref или удаленным ref )
=> local is master ("ours"),
=> remote is topic ("theirs")
Это означает, что инструмент merge / diff будет представлять ветвь восходящего потока как local
( master
: ветвь, поверх которой вы перегружаете), а рабочая ветвь - как remote
( topic
: ветвь переустанавливается)
+-----------------------------------------+
| LOCAL:master | BASE | REMOTE:topic |
+-----------------------------------------+
| MERGED |
+-----------------------------------------+
Показана инверсия
При слиянии:
c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
\
\
\--y--y--y <- other branch to merge
Мы не меняем текущую topic
ветви, поэтому у нас есть то, над чем мы работали (и мы сливаемся с другой веткой)
c--c--x--x--x---------o(*) MERGE, still on branch topic
\ ^ /
\ ours /
\ /
--y--y--y--/
^
theirs
На rebase:
Но при переустановке мы переключаем стороны, потому что первое, что нужно сделать, - это проверить выходную ветвь, чтобы воспроизвести текущую фиксацию поверх нее!
c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
\
\
\--y--y--y <- upstream branch
git rebase upstream
сначала устанавливает HEAD
в верхнюю ветвь, следовательно, переключатель «ours» и «theirs» по сравнению с предыдущей «текущей» рабочей ветвью.
c--c--x--x--x <- former "current" branch, new "theirs"
\
\
\--y--y--y(*) <- set HEAD to this commit, to replay x's on it
^ this will be the new "ours"
|
upstream
После этого rebase повторит «их» фиксацию в новой ветке «нашей» topic
:
c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
\
\
\--y--y--y--x'--x'--x'(*) <- topic once all x's are replayed,
^ point branch topic to this commit
|
upstream branch
Интерактивная ребаза
Этот пример предназначен для описания того, как можно использовать git rebase
в интерактивном режиме. Ожидается, что у вас есть базовое понимание того, что такое git rebase
и что она делает.
Интерактивная перезагрузка начинается с следующей команды:
git rebase -i
Опция -i
относится к интерактивному режиму . Используя интерактивную переустановку, пользователь может изменять сообщения фиксации, а также выполнять переупорядочивание, разделение и / или сквош (в сочетании с одним).
Скажите, что вы хотите изменить свои последние три фиксации. Для этого вы можете запустить:
git rebase -i HEAD~3
После выполнения вышеуказанной инструкции в текстовом редакторе откроется файл, в котором вы сможете выбрать способ переустановки ваших коммитов. Для целей этого примера просто измените порядок своих коммитов, сохраните файл и закройте редактор. Это приведет к переустановке с заказом, который вы применили. Если вы проверите git log
вы увидите свои коммиты в новом указанном вами порядке.
Сообщения о фиксации перезаписи
Теперь вы решили, что одно из сообщений фиксации является неопределенным, и вы хотите, чтобы оно было более наглядным. Давайте рассмотрим последние три коммиты, используя ту же команду.
git rebase -i HEAD~3
Вместо того, чтобы переупорядочить заказ, коммиты будут переустановлены, на этот раз мы изменим pick
, по умолчанию, чтобы reword
на коммит, где вы хотите изменить сообщение.
Когда вы закрываете редактор, rebase будет инициироваться, и он остановится на конкретном сообщении о коммитстве, которое вы хотите переписать. Это позволит вам изменить сообщение фиксации в зависимости от того, что вы хотите. После того как вы изменили сообщение, просто закройте редактор, чтобы продолжить.
Изменение содержимого фиксации
Помимо изменения сообщения о фиксации, вы также можете адаптировать изменения, сделанные фиксацией. Для этого просто измените pick
для edit
для одного коммита. Git остановится, когда он достигнет этого коммита и предоставит исходные изменения фиксации в промежуточной области. Теперь вы можете адаптировать эти изменения, отказавшись от них или добавив новые изменения.
Как только промежуточная область содержит все изменения, которые вы хотите в этом коммите, зафиксируйте изменения. Старое сообщение фиксации будет показано и может быть адаптировано для отражения нового фиксации.
Разделение одного фиксации на несколько
Предположим, что вы совершили коммит, но решили, что позднее этот фиксатор может быть разделен на две или более коммитов. Используя ту же команду , как и прежде, заменить pick
с edit
вместо и нажмите клавишу ВВОД.
Теперь git остановится на фиксации, которую вы отметили для редактирования, и поместите все его содержимое в промежуточную область. С этого момента вы можете запустить git reset HEAD^
чтобы поместить фиксацию в ваш рабочий каталог. Затем вы можете добавлять и фиксировать свои файлы в другой последовательности - в конечном счете, разделяя одну фиксацию на n коммитов вместо этого.
Сжатие нескольких коммитов в один
Скажите, что вы проделали определенную работу и имеете несколько коммитов, которые, по вашему мнению, могут быть единственной фиксацией. Для этого вы можете выполнить git rebase -i HEAD~3
, заменив 3
соответствующим количеством коммитов.
На этот раз заменить pick
с squash
вместо этого. Во время перезагрузки коммит, который вы поручили раздавить, будет раздавлен поверх предыдущего фиксации; вместо этого они превращают их в одну фиксацию.
Прерывание интерактивной ребазы
Вы начали интерактивную перезагрузку. В редакторе, где вы выбираете свои коммиты, вы решаете, что что-то идет не так (например, коммит отсутствует или вы выбрали неправильное назначение переадресации), и вы хотите прервать переустановку.
Для этого просто удалите все коммиты и действия (т.е. все строки, не начинающиеся с знака #
), и rebase будет прерван!
Текст справки в редакторе действительно дает этот намек:
# Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out
Нажатие после перестановки
Иногда вам нужно переписать историю с rebase, но git push
жалуется на это, потому что вы переписали историю.
Это можно решить с помощью git push --force
, но рассмотрите git push --force-with-lease
, что указывает на то, что вы хотите, чтобы нажатие было неудачным, если локальная ветвь удаленного отслеживания отличается от ветки на удаленном компьютере, например, кто-то иначе нажмите на удаленный компьютер после последней выборки. Это позволяет избежать непреднамеренного перезаписи чужих недавних нажатий.
Примечание : git push --force
- и даже --force-with-lease
в этом отношении - может быть опасной командой, поскольку она перезаписывает историю ветки. Если другой человек вытащил ветку до принудительного толчка, у его / ее приведения git pull
или git fetch
будут ошибки, потому что местная история и удаленная история расходятся. Это может привести к непредвиденным ошибкам. При достаточном рассмотрении рефлогов другая работа пользователя может быть восстановлена, но это может привести к большому количеству потраченного впустую времени. Если вы должны принудительно нажать на ветку с другими участниками, попробуйте согласовать с ними, чтобы им не приходилось иметь дело с ошибками.
Перебазируйте до первоначальной фиксации
Так как Git 1.7.12 можно переустановить до корневой фиксации. Корневая фиксация - это первая фиксация, когда-либо сделанная в репозитории, и обычно ее нельзя редактировать. Используйте следующую команду:
git rebase -i --root
Повторное восстановление перед просмотром кода
Резюме
Эта цель состоит в том, чтобы реорганизовать все ваши разрозненные коммиты в более значимые коммиты для более простых обзоров кода. Если слишком много уровней изменений для слишком большого количества файлов одновременно, сложнее выполнить проверку кода. Если вы можете реорганизовать свои хронологически созданные коммиты в актуальные коммиты, то процесс обзора кода будет проще (и, возможно, меньше ошибок проскальзывает процесс проверки кода).
Этот чрезмерно упрощенный пример - не единственная стратегия использования git для улучшения обзора кода. Это то, как я это делаю, и это то, что вдохновляет других на то, чтобы подумать о том, как сделать обзоры кода и историю гитов легче / лучше.
Это также педагогически демонстрирует силу всеобщей ребалансировки.
В этом примере предполагается, что вы знаете об интерактивной перезагрузке.
Предполагая, что:
- вы работаете над ветвью функции мастера
- ваша функция имеет три основных уровня: front-end, back-end, DB
- вы сделали много коммитов во время работы над ветвью функций. Каждая фиксация затрагивает сразу несколько слоев
- вы хотите (в конце концов) только три фиксации в вашей ветке
- один, содержащий все изменения переднего конца
- один, содержащий все задние изменения
- один, содержащий все изменения БД
Стратегия:
- мы собираемся изменить наши хронологические фиксации на «актуальные» коммиты.
- во-первых, расщепить все коммиты на несколько меньших коммитов - каждый из которых содержит только одну тему за раз (в нашем примере темы - это интерфейс, конец, изменения БД)
- Затем переупорядочивайте наши локальные коммиты вместе и «сквоите» их в отдельные актуальные сообщения
Пример:
$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master
Это будет показано в текстовом редакторе:
pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb
Измените его так:
e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb
Затем git будет применять одно сообщение за раз. После каждой фиксации появится приглашение, а затем вы можете сделать следующее:
Stopped at 43b075a92a952faf999e76c4e4d7fa0f44576579... first draft: page.html and db.sql
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
nothing to commit, working directory clean
$ git reset HEAD^ #This 'uncommits' all the changes in this commit.
$ git status -s
M db.sql
M page.html
$ git add db.sql #now we will create the smaller topical commits
$ git commit -m "first draft: db.sql"
$ git add page.html
$ git commit -m "first draft: page.html"
$ git rebase --continue
Затем вы повторите эти шаги для каждой фиксации. В итоге у вас есть следующее:
$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql
Теперь мы запускаем rebase еще раз, чтобы изменить порядок и сквош:
$ git rebase -i master
Это будет показано в текстовом редакторе:
pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb
Измените его так:
pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s 3264de2 adding todo items: page.html
ВНИМАНИЕ: убедитесь, что вы указали git rebase на применение / сквош меньших локальных коммитов в том порядке, в котором они были хронологически зафиксированы . В противном случае у вас могут быть ложные, ненужные конфликты слияния.
Когда эта интерактивная перебаза все сказано и сделано, вы получаете следующее:
$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer
резюмировать
Теперь вы уложили свои хронологические фиксации в актуальные дела. В реальной жизни вам может не понадобиться делать это каждый раз, но когда вы этого хотите или хотите сделать, теперь можете. Плюс, надеюсь, вы узнали больше о git rebase.
Настройка git-pull для автоматического выполнения rebase вместо слияния
Если ваша команда выполняет рабочий процесс на основе базы данных, может быть полезно настроить git, чтобы каждая вновь созданная ветвь выполняла операцию переадресации вместо операции слияния во время git pull
.
Чтобы настроить каждую новую ветвь для автоматической переадресации, добавьте следующее в ваш .gitconfig
или .git/config
:
[branch]
autosetuprebase = always
Командная строка: git config [--global] branch.autosetuprebase always
В качестве альтернативы вы можете настроить команду git pull
чтобы всегда вести себя так, как будто была передана опция --rebase
:
[pull]
rebase = true
Командная строка: git config [--global] pull.rebase true
Тестирование всех коммитов во время rebase
Прежде чем делать запрос на извлечение, полезно убедиться, что компиляция прошла успешно, и тесты проходят для каждой фиксации в ветке. Мы можем сделать это автоматически, используя параметр -x
.
Например:
git rebase -i -x make
будет выполнять интерактивную перезагрузку и останавливаться после каждой фиксации для выполнения make
. В случае сбоя make
, git остановится, чтобы дать вам возможность исправить проблемы и исправить фиксацию, прежде чем приступать к выбору следующего.
Настройка автозапуска
Autostash - очень полезный параметр конфигурации при использовании rebase для локальных изменений. Зачастую вам может потребоваться внести фиксации из ветки вверх по течению, но еще не готовы к фиксации.
Однако Git не разрешает перезагрузку, если рабочий каталог не является чистым. Autostash на помощь:
git config --global rebase.autostash # one time configuration
git rebase @{u} # example rebase on upstream branch
Автозагрузка будет применяться всякий раз, когда будет завершена перезагрузка. Не имеет значения, успешно ли завершена перебаза или если она прервана. В любом случае будет применен автозапуск. Если перебаза была успешной, и поэтому базовая фиксация была изменена, тогда может возникнуть конфликт между автосохранением и новыми коммитами. В этом случае вам придется разрешать конфликты перед совершением. Это ничем не отличается от того, если бы вы вручную спрятали, а затем применили, поэтому нет недостатка в том, чтобы делать это автоматически.