Я только что прочитал изменение одного файла в прошлом коммите в git, но, к сожалению, принятое решение «переупорядочивает» коммиты, чего я не хочу. Итак, вот мой вопрос:
Время от времени я замечаю ошибку в своем коде во время работы над (несвязанной) функцией. Затем быстро git blame
выясняется, что ошибка была введена несколько коммитов назад (я совершаю довольно много, поэтому обычно это не самая последняя фиксация, которая внесла ошибку). На этом этапе я обычно делаю так:
git stash # temporarily put my work aside
git rebase -i <bad_commit>~1 # rebase one step before the bad commit
# mark broken commit for editing
vim <affected_sources> # fix the bug
git add <affected_sources> # stage fixes
git commit -C <bad_commit> # commit fixes using same log message as before
git rebase --continue # base all later changes onto this
Однако это происходит так часто, что приведенная выше последовательность действий становится надоедливой. Особенно скучна "интерактивная перебазировка". Есть ли какой-либо ярлык для приведенной выше последовательности, который позволяет мне исправить произвольный коммит в прошлом с помощью поэтапных изменений? Я прекрасно понимаю, что это меняет историю, но я так часто делаю ошибки, что мне очень хотелось бы иметь что-нибудь вроде
vim <affected_sources> # fix bug
git add -p <affected_sources> # Mark my 'fixup' hungs for staging
git fixup <bad_commit> # amend the specified commit with staged changes,
# rebase any successors of bad commit on rewritten
# commit.
Может быть, умный скрипт, который может переписывать коммиты с помощью сантехнических инструментов?
rebase -i
?rebase --onto tmp bad-commit master
. Как написано, он попытается применить плохую фиксацию к фиксированному состоянию фиксации.Ответы:
ОБНОВЛЕННЫЙ ОТВЕТ
Некоторое время назад
--fixup
был добавлен новый аргумент,git commit
который можно использовать для создания фиксации с сообщением журнала, подходящим дляgit rebase --interactive --autosquash
. Итак, самый простой способ исправить предыдущую фиксацию сейчас:ОРИГИНАЛЬНЫЙ ОТВЕТ
Вот небольшой сценарий Python, который я написал некоторое время назад, который реализует эту
git fixup
логику, на которую я надеялся в своем первоначальном вопросе. Сценарий предполагает, что вы внесли некоторые изменения, а затем применяет эти изменения к данной фиксации.ПРИМЕЧАНИЕ . Этот сценарий специфичен для Windows; он ищет
git.exe
и устанавливаетGIT_EDITOR
переменную среды, используяset
. При необходимости отрегулируйте это для других операционных систем.Используя этот скрипт, я могу реализовать именно тот рабочий процесс, который я просил: «исправить неработающие источники, исправить этапы, запустить git fixup»:
источник
git stash
иgit stash pop
вокруг своей переустановки, чтобы больше не требовался чистый рабочий каталогgit stash
иgit stash pop
: вы правы, но, к сожалениюgit stash
, в Windows он работает намного медленнее, чем в Linux или OS / X. Поскольку мой рабочий каталог обычно чистый, я пропустил этот шаг, чтобы не замедлить выполнение команды.git rebase -i --fixup
, и он переместился из фиксированного коммита в качестве отправной точки, поэтому аргумент sha в моем случае не нужен.git config --global rebase.autosquash true
Что я делаю:
Ваш редактор откроется со списком последних 5 коммитов, готовых к вмешательству. Изменить:
... чтобы:
Сохраните и выйдите из редактора, и исправление будет возвращено в коммит, которому оно принадлежит.
Сделав это несколько раз, вы сделаете это за секунды во сне. Интерактивное ребазирование - это функция, которая действительно меня продала на git. Это невероятно полезно для этого и не только ...
источник
--autosquash
переключатель дляgit rebase
, который автоматически меняет порядок шагов в редакторе для вас. См. Мой ответ на сценарий, который использует это для реализацииgit fixup
команды.Немного поздно для вечеринки, но вот решение, которое работает так, как задумал автор.
Добавьте это в свой .gitconfig:
Пример использования:
Однако, если у вас есть неустановленные изменения, вы должны спрятать их перед перебазированием.
Вы можете изменить псевдоним так, чтобы он сохранялся автоматически, вместо того, чтобы выдавать предупреждение. Однако, если исправление не применимо чисто, вам нужно будет вручную открыть тайник после устранения конфликтов. Выполнение как сохранения, так и открытия вручную кажется более последовательным и менее запутанным.
источник
git fixup HEAD
я создал псевдоним для этого. Полагаю, я мог бы также использовать поправку для этого.amend = commit --amend --reuse-message=HEAD
Затем вы можете просто ввестиgit amend
илиgit amend -a
и пропустить редактор сообщения о фиксации.Чтобы исправить одну фиксацию:
где a0b1c2d3 - это фиксация, которую вы хотите исправить, и где 2 - это количество коммитов +1, вставленных, которые вы хотите изменить.
Примечание: git rebase --autosquash без -i не работает, но с -i работает, что странно.
источник
--autosquash
без него по--i
прежнему не работает.EDITOR=true git rebase --autosquash -i
ОБНОВЛЕНИЕ: более чистую версию скрипта теперь можно найти здесь: https://github.com/deiwin/git-dotfiles/blob/docs/bin/git-fixup .
Я давно искал нечто подобное. Однако этот скрипт Python кажется слишком сложным, поэтому я сколотил собственное решение:
Во-первых, мои псевдонимы git выглядят так (заимствованы отсюда ):
Теперь функция bash становится довольно простой:
Этот код сначала обрабатывает все текущие изменения (вы можете удалить эту часть, если хотите сами обработать файлы). Затем создает фиксацию (также можно использовать сквош, если это то, что вам нужно). После этого он запускает интерактивную перебазировку с
--autosquash
флагом на родительском коммите, который вы указываете в качестве аргумента. Это откроет ваш настроенный текстовый редактор, чтобы вы могли убедиться, что все в порядке, и простое закрытие редактора завершит процесс.Используется
if [[ "$1" == HEAD* ]]
часть (заимствованная отсюда ), потому что, если вы используете, например, HEAD ~ 2 в качестве ссылки на фиксацию (фиксацию, которую вы хотите исправить текущие изменения), то HEAD будет перемещен после того, как фиксация фиксации была создана. и вам нужно будет использовать HEAD ~ 3 для ссылки на тот же коммит.источник
Вы можете избежать интерактивного этапа, используя «нулевой» редактор:
Он будет использоваться
/bin/true
в качестве редактора вместо/usr/bin/vim
. Он всегда принимает все, что предлагает git, без запроса.источник
call(["set", "GIT_EDITOR=true", "&&", git, "rebase", "-i" ...
).Что действительно беспокоило меня в рабочем процессе исправления, так это то, что мне приходилось самому выяснять, в какую фиксацию я хочу каждый раз вносить изменения. Я создал команду "git fixup", которая помогает в этом.
Эта команда создает фиксации фиксации с добавленной магией, заключающейся в том, что она использует git-deps для автоматического поиска соответствующей фиксации, поэтому рабочий процесс часто сводится к:
Это работает только в том случае, если поэтапные изменения могут быть однозначно отнесены к определенной фиксации в рабочем дереве (между мастером и HEAD). Я обнаружил, что это очень часто случается с типом небольших изменений, для которых я использую это, например, опечатки в комментариях или названия недавно введенных (или переименованных) методов. Если это не так, он, по крайней мере, отобразит список коммитов кандидатов.
Я использую это много в моем повседневном рабочем процессе, чтобы быстро интегрировать небольшие изменения в ранее измененных линии в фиксации на моей рабочей ветви. Сценарий не так красив, как мог бы быть, и он написан на zsh, но он уже достаточно хорошо выполняет свою работу за меня, и я никогда не чувствовал необходимости его переписывать:
https://github.com/Valodim/git-fixup
источник
Вы можете создать исправление для конкретного файла, используя этот псевдоним.
Если вы внесли некоторые изменения,
myfile.txt
но не хотите вносить их в новую фиксацию,git fixup-file myfile.txt
создастfixup!
для фиксации, котораяmyfile.txt
была изменена в последний раз, и тогда это произойдетrebase --autosquash
.источник
git rebase
это не производилось автоматически.commit --fixup
иrebase --autosquash
они великолепны, но они не делают достаточно. Когда у меня есть последовательность коммитов,A-B-C
и я пишу еще несколько изменений в моем рабочем дереве, которые принадлежат одному или нескольким из этих существующих коммитов, мне приходится вручную просматривать историю, решать, какие изменения принадлежат каким коммитам, выполнять их и создаватьfixup!
совершает. Но у git уже есть доступ к достаточно информации, чтобы сделать все это за меня, поэтому я написал сценарий Perl, который делает именно это.Для каждого фрагмента в
git diff
скрипте используется,git blame
чтобы найти фиксацию, которая последней коснулась соответствующих строк, и вызываетgit commit --fixup
запись соответствующихfixup!
коммитов, по сути делая то же самое, что я делал раньше вручную.Если вы сочтете это полезным, пожалуйста, не стесняйтесь улучшать и повторять его, и, возможно, однажды мы получим такую функцию
git
должным образом. Мне бы хотелось увидеть инструмент, который может понять, как разрешать конфликт слияния, если он был введен посредством интерактивного ребазирования.источник
Я написал небольшую функцию оболочки,
gcf
которая вызывается для автоматического выполнения фиксации фиксации и перебазирования:Например, вы можете исправить вторую фиксацию перед последней с помощью:
gcf HEAD~~
Вот функция . Вы можете вставить его в свой
~/.bashrc
Он используется
--autostash
для сохранения и извлечения любых незафиксированных изменений при необходимости.--autosquash
требует--interactive
перебазирования, но мы избегаем взаимодействия, используя фиктивный объектEDITOR
.--no-fork-point
защищает коммиты от молчаливого сброса в редких ситуациях (когда вы создали новую ветку, и кто-то уже перебазировал предыдущие коммиты).источник
Я не знаю об автоматическом способе, но вот решение, которое может быть проще использовать человеком:
источник
git fixup
команды.--autosquash
Я бы рекомендовал https://github.com/tummychow/git-absorb :
источник