Git: squash/fixup ранее совершить

Предположим, что у вас есть:

A-B-C

Теперь ваша сборка/тестирование не удается. Исправление должно быть объединено в A. Мой текущий рабочий поток выглядит следующим образом:

$ git commit -m "fixA"

A-B-C-fixA

$ git rebase -i A~1

И squash fixA в A, результат:

A'-B-C

Есть ли команда сделать что-то вроде:

A-B-C + (index with fix for A)

$ git commit -supperdupper A 

Результат:

A'-B-C

Ответ 1

Если вы просто ищете простое решение для исправления предыдущих коммитов, прочитайте вопрос! Это все объясняет. Но так как Эльмарко просил щепотку, мы пойдем:

Как и в случае с Git 1.7.0, существует опция --autosquash для rebase, которая делает то, что вы хотите. Существует также опции --fixup и --squash для commit, чтобы упростить задачу. С некоторым псевдонимом вы, вероятно, можете даже получить все это в одну команду.

Я предлагаю обновить до новейшего Git для максимальной awesomeness:

git/Documentation/RelNotes $ grep -i -A1 autosquash\\\|fixup *
1.7.0.txt: * "git rebase -i" learned new action "fixup" that squashes the change
1.7.0.txt-   but does not affect existing log message.
--
1.7.0.txt: * "git rebase -i" also learned --autosquash option that is useful
1.7.0.txt:   together with the new "fixup" action.
1.7.0.txt-
--
1.7.3.txt: * "git rebase -i" peeks into rebase.autosquash configuration and acts as
1.7.3.txt:   if you gave --autosquash from the command line.
1.7.3.txt-
--
1.7.4.txt: * "git commit" learned --fixup and --squash options to help later invocation
1.7.4.txt-   of the interactive rebase.
--
1.7.4.txt: * "git rebase --autosquash" can use SHA-1 object names to name which
1.7.4.txt:   commit to fix up (e.g. "fixup! e83c5163").
1.7.4.txt-

Ответ 2

Мой текущий git рабочий поток настолько интенсивен --fixup/--squash, что я написал новую команду git-fixup, которая автоматически обрабатывает большинство раздражающих битов:

  • git fixup показывает измененные файлы, сгруппированные по последним данным, которые касаются тех же файлов
  • git fixup -a фиксирует все эти изменения, поскольку изменения --fixup с соответствующими "родительскими" коммитами
  • git fixup -r выполняется автоматическое git rebase --autosquash для всех исправлений

Множество изменений таково, что для выполнения этой работы достаточно только трех приведенных выше команд, без копирования вставки кода фиксации или чтения через git log для поиска правильных целей --fixup.

Источник: https://github.com/ohmu/git-crust

Ответ 3

Если вы хотите сквоить последние два коммита, вам нужно вызвать

git rebase --interactive <3rd last commit>

Затем вам нужно выбрать последнюю фиксацию и раздавить второе-последнее коммит. Вы не можете раздавить самую верхнюю фиксацию истории.

Ответ 4

I создал некоторые псевдонимы, чтобы упростить использование команд git commit --fixup и git commit --squash, добавленных в git 1.7. Добавьте их в свой ~/.gitconfig:

[alias]
  fixup = !sh -c 'REV=$(git rev-parse $1) && git commit --fixup [email protected] && git rebase -i --autosquash $REV^' -
  squash = !sh -c 'REV=$(git rev-parse $1) && git commit --squash [email protected] && git rebase -i --autosquash $REV^' -

Использование:

$ git commit -am 'bad commit'
$ git commit -am 'good commit'

$ git add .          # Stage changes to correct the bad commit
$ git fixup HEAD^    # HEAD^ can be replaced by the SHA of the bad commit

Плохая фиксация может быть несколько коммитов назад.

Ответ 5

То, что вы делаете, опасно, если вы делитесь веткой, в которой вы вносите изменения с другими людьми. В вашем случае вы переписываете commit A и перезаписываете B и C поверх нового A, который является совершенно новым объектом. Любой, кто уже поместил старый A в свои репозитории, может привести к разложению своего репозитория, поскольку история в вашем репозитории будет "волшебным образом" изменена. Их git не мог бы знать, что история была переписана.

Из-за этого разработчики git намеренно не сделали это легко, так как вам нужно знать о последствиях такой операции.

Ответ 6

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

У меня нет такого решения, но я написал Perl script, чтобы помочь автоматизировать процесс перезаписи истории. Он похож на Python script @MikaEloranta, которого я не видел, когда писал его.

commit --fixup и rebase --autosquash велики, но их недостаточно. Когда у меня есть последовательность коммитов A-B-C, и я пишу еще несколько изменений в моем рабочем дереве, которые принадлежат одному или нескольким из существующих коммитов, мне приходится вручную смотреть на историю, решать, какие изменения принадлежат, в которой они совершают, сценить их и создайте фиксацию fixup!. Но git уже имеет доступ к достаточной информации, чтобы иметь возможность сделать все, что для меня.

Для каждого столбца в git diff script используется git blame, чтобы найти фиксацию, которая последний раз коснулась соответствующих строк, и вызывает git commit --fixup для записи соответствующих fixup! коммиттов, по существу делающих то же самое, что и я прежде чем делать.

Если script не может разрешить кусок для одного однозначного коммита, он сообщит об этом как об отказе, и вам придется вернуться к ручному подходу для этого. Если вы дважды изменили строку в двух отдельных коммитах, script разрешит изменение этой строки до последней из этих коммитов, что может не всегда быть правильным разрешением. ИМХО в ветки функции "нормальной формы" вы не должны менять строку дважды в двух разных коммитах, каждая фиксация должна представлять финальную версию линий, к которой она прикасается, чтобы помочь рецензентам. Тем не менее, это может произойти в ветке bugfix, чтобы придумать пример, чтобы линия foo(bar()); могла быть затронута commit A (переименовать foo в fox) и зафиксировать B (переименовать bar в baz).

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