Обрезка Мерзавца Фиксирует/Раздавит Историю Мерзавца

Я проверяю, что мой код в Мерзавца переходит приблизительно каждые несколько минут, и комментарии заканчивают тем, что были вещами как "Все поврежденный запуск снова" и другая нелепость.

Затем каждые несколько минут/часов/дней я делаю серьезную фиксацию с реальным комментарием как, "Исправленная ошибка № 22.55, в 3-й раз". Как я могу разделить эти два понятия? Я хотел бы смочь удалить все свои частые фиксации и просто оставить серьезные.

66
задан Dan Rosenstark 23 July 2014 в 15:24
поделиться

3 ответа

Используйте git rebase -i, чтобы выбрать и сжать ваши коммиты вместе.

0
ответ дан 24 November 2019 в 14:58
поделиться

Отредактированный ответ с теперь (во второй половине этой записи) новым действием Git1.7 fixup! и опцией --autosquash для быстрого изменения порядка коммитов и редактирования сообщений.


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

Я хотел бы иметь возможность удалить все мои частые проверки и оставить только серьёзные.

Это называется squashing commits.
У вас есть несколько хороших примеров "очистки коммитов" в этой Git ready статье:
(Примечание: интерактивная функция rebase появилась в сентябре 2007 года, и позволяет сминать или разделять, удалять или переупорядочивать коммиты: см. также страницу GitPro)

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

alt text

Последние 4 коммита были бы намного счастливее, если бы их завернули вместе

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

rebase, используя последние четыре коммита с того места, где находится HEAD, с HEAD~4.
Мы просто собираемся сжать всё в один коммит.
Итак, измените первые четыре строки файла на следующие:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

По сути, это говорит Git'у объединить все четыре фиксации в первый коммит в списке. Как только это будет сделано и сохранено, появится ещё один редактор со следующим:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   LICENSE
#   modified:   README.textile
#   modified:   Rakefile
#   modified:   bin/jekyll
#

Поскольку мы объединяем так много коммитов, Git позволяет вам изменять сообщение нового коммита на основе остальных коммитов, участвующих в процессе. Отредактируйте сообщение по своему усмотрению, затем сохраните и выйдите.
Как только это будет сделано, ваши коммиты будут успешно удалены!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

И если мы снова посмотрим на историю...

alt text


Примечание: для целей "раздавливания коммитов", Git1. 7 (февраль 2010) появились 2 новых элемента (как упомянул Dustin в комментарии):

  • "git rebase -i" научился новому действию "fixup", которое сминает изменение, но не влияет на существующее сообщение журнала.
  • "git rebase -i" также узнал опцию --autosquash, которая полезна вместе с новым действием "fixup".

Обе функции (действие fixup и опция --autosquash) показаны в этой записи блога Thechnosorcery Networks. Эти возможности готовились с июня 2009 года и обсуждались в декабре прошлого года.

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

  # s, squash = use commit, but meld into previous commit
  # f, fixup = like "squash", but discard this commit's log message

Опция --autosquash предназначена для того, чтобы сделать процесс переупорядочивания коммитов автоматически за вас:

Если вы знаете, в каком коммите вы хотите что-то раздавить, вы можете зафиксировать это с сообщением "squash! $other_commit_subject”. Тогда, если вы выполните @git rebase --interactive --autosquash commitish@, строка будет автоматически установлена как squash и помещена ниже коммита с темой $other_commit_subject.

(На самом деле, squash! можно использовать только в начале сообщения другого коммита)

$ vim Foo.txt
$ git commit -am "Change all the 'Bar's to 'Foo's"
[topic 8374d8e] Change all the 'Bar's to 'Foo's
 1 files changed, 2 insertions(+), 2 deletions(-)
$ vim Bar.txt
$ git commit -am "Change all the 'Foo's to 'Bar's"
[topic 2d12ce8] Change all the 'Foo's to 'Bar's
 1 files changed, 1 insertions(+), 1 deletions(-)

$ vim Foo.txt
$ git commit -am "squash! Change all the 'Bar's"
[topic 259a7e6] squash! Change all the 'Bar's
 1 files changed, 2 insertions(+), 1 deletions(-)

Видите? Здесь третий коммит использует только начало первого сообщения коммита.
rebase --interactive --autosquash переместит сплющенный коммит ниже соответствующего:

pick 8374d8e Change all the 'Bar's to 'Foo's
squash 259a7e6 squash! Change all the 'Bar's
pick 2d12ce8 Change all the 'Foo's to 'Bar's

Редакция сообщения будет такой:

# This is a combination of 2 commits.
# The first commit's message is:

Change all the 'Bar's to 'Foo's

# This is the 2nd commit message:

squash! Change all the 'Bar's

Это означает, что по умолчанию вы сохраните операцию сплющивания, записанную в сообщении коммита.
Но с помощью директивы fixup! вы можете сохранить это сминание "невидимым" в сообщении о фиксации, получая при этом преимущества от автоматического упорядочивания фиксации с помощью опции --autosquash (и того факта, что ваше второе сообщение о фиксации основано на первой фиксации, с которой вы хотите быть сминаемым).

pick 8374d8e Change all the 'Bar's to 'Foo's
fixup cfc6e54 fixup! Change all the 'Bar's
pick 2d12ce8 Change all the 'Foo's to 'Bar's

По умолчанию сообщение будет таким:

# This is a combination of 2 commits.
# The first commit's message is:

Change all the 'Bar's to 'Foo's

# The 2nd commit message will be skipped:

#    fixup! Change all the 'Bar's

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

Теперь, если вы хотите исправить или скоммить на основе предыдущего коммита, который вы только что сделали, Джейкоб Хелвиг (автор записи в блоге Technosorcery Networks) рекомендует использовать следующие псевдонимы:

[alias]
    fixup = !sh -c 'git commit -m \"fixup! $(git log -1 --format='\\''%s'\\'' $@)\"' -
    squash = !sh -c 'git commit -m \"squash! $(git log -1 --format='\\''%s'\\'' $@)\"' -

А для выполнения интерактивного rebase, который всегда выиграет от автоматической перестановки коммитов, предназначенных для удаления:

[alias]
    ri = rebase --interactive --autosquash

Обновление для Git 2.18 (Q2 2018): "git rebase -i" иногда оставляет промежуточное сообщение "# This is a combination of N commits", предназначенное для потребления человеком. внутри редактора в конечном результате в некоторых угловых случаях, что было исправлено.

См. commit 15ef693, commit dc4b5bc, commit e12a7ef, commit d5bc6f2 (27 Apr 2018) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit 4a3bf32, 23 May 2018)

rebase --skip: clean up commit message after a failed fixup/squash

Во время серии команд fixup/squash интерактивный rebase строит создает сообщение о фиксации с комментариями. Оно будет представлено пользователю в редакторе, если хотя бы одна из этих команд была squash.

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

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

Этот коммит исправляет такое поведение.

Это исправление гораздо сложнее, чем может показаться на первый взгляд, потому что это не только вопрос о том, что мы делаем: git rebase --skiping исправление или сквош. Речь также идёт об удалении пропущенного исправления/сквоша из сообщение о фиксации из накопленного сообщения о фиксации. И это также касается вопрос о том, должны ли мы позволить пользователю редактировать финальное сообщение о фиксации или нет ("Был ли сквош в цепочке который не был пропущен?").

Например, в этом случае мы захотим исправить сообщение о фиксации, но не открывать его в редакторе:

pick <- succeeds
fixup <- удается
squash <- неудача, будет пропущено

Вот здесь-то и пригодится недавно введенный файл current-fixups. полезным. Быстрый просмотр и мы можем определить, был ли не пропущенный сквош. Нам нужно только следить за тем, чтобы он был в актуальном состоянии в отношении пропущенных команд исправления/сквоша. В качестве бонуса, мы даже можем избежать совершения без необходимости, например, когда был только один fixup, он не сработал и была пропущена.

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


В Git 2.19 (Q3 2018) исправлена ошибка: Когда команде "git rebase -i" даётся команда объединить два или более коммита в один, она помечала сообщение журнала для каждого коммита его номером.
Он правильно назвал первый коммит "1st commit", но следующий был "commit #1", что было не на один(!).

См. commit dd2e36e (15 Aug 2018) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit 36fd1e8, 20 Aug 2018)

rebase -i: исправить нумерацию в сообщении squash

Commit e12a7ef ("rebase -i: Обработать "комбинацию коммитов" с. GETTEXT_POISON", 2018-04-27, Git 2.18) изменил способ, которым отдельные сообщения коммита сообщения маркируются при объединении коммитов.
При этом была введена регрессия, при которой нумерация сообщений не совпадала на единицу. Этот коммит исправляет это и добавляет проверку нумерации.

98
ответ дан 24 November 2019 в 14:58
поделиться

Использование Soft Reset вместо Rebase для уничтожения истории GIT

Я думаю, что длина ответов VonC говорит о том - буквально - насколько сложным является git rebase. Это мое продолжение другого ответа на мой вопрос.

  1. У вас есть ветка ticket-201, которую вы ответвили от master. Вы хотите сделать вид, что все коммиты из ticket-201 никогда не происходили, но что вы сделали всю работу за один раз.
  2. Выполните мягкий сброс в точку ответвления с помощью git reset --soft hash, где hash должен быть хэшем коммита, который находится в журнале ticket-201.
  3. Зафиксируйте изменения, используя add, затем commit. Теперь в истории ветки будет только первый коммит и новый коммит с новым материалом.

Составление истории из произвольных коммитов в разных ветках

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

  1. Проверьте новую ветку по адресу commit0 (представьте, что это хэш): git checkout -b new-history commit0
  2. Теперь вы можете получить файлы из commit5: git reset --hard commit5
  3. Переключитесь обратно на свою индексную точку: git reset --soft commit0
  4. Сделайте коммит, и это будет второй коммит в ветке.

Эта идея проста, эффективна и гибка.

27
ответ дан 24 November 2019 в 14:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: