Git - сквош всей ветви - команда сквоша на одну линию

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

Как раздавить всю ветку без использования git rebase --interactive а затем меняется pick в squash для всех коммитов?

8 ответов

Это идеальный вариант использования git reset --soft.

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

D   Your latest patch
C   Your second patch
B   Your first patch
A   Someone else's work

у вас нет поэтапных изменений, иgit status, git log или git show сказать, что вы сейчас на фиксации D.

потом git reset --soft B примет совокупные изменения коммитов C а также D и подготовьте их для фиксации. git commit --amend затем "объединит" эти изменения в коммит B.

Используйте следующим образом:

git reset --soft B
git commit --amend

Вторая команда вызовет ваш редактор с возможностью отредактировать сообщение фиксации.

Обратите внимание, что если вы внесли изменения перед началом этого процесса (т.е. вы сделалиgit add XXX но не последовало git commit), то эти поэтапные изменения также будут объединены в коммит.

Мой предпочтительный метод - двухслойный (исключая шаги 1 и 4 ниже). Преимущества в том, что вам не нужно знать / записывать какие-либо идентификаторы коммитов, вы можете написать простой псевдоним для выполнения всех необходимых шагов, и вы фактически переместите всю свою ветвь на origin/ master, чтобы фактическое слияние с master могло быть быстрым. - вперед и не может быть никаких конфликтов.

Во-первых, мои предположения:

  • Вы работаете над веткой под названием my-feature-branch, Эта ветвь отошла от master несколькими коммитами; это проверенная ветка.
  • Ваш местный master отслеживает удаленную ветку origin/master
  • Вы хотите раздавить все свои коммиты от my-feature-branch в один коммит поверх текущего состояния происхождения / мастера (не вашего локального masterчто может быть устаревшим)
  • Все ваши изменения зафиксированы, у вас нет нетронутых изменений (они будут потеряны во время git reset --hard)

Мой процесс выглядит следующим образом:

  1. Принести, так origin/master текущий:

    $ git fetch
    
  2. Удалите все коммиты в вашей локальной ветке, сбросив его так, чтобы он указывал на origin/master

    $ git reset --mixed origin/master
    
  3. Объединить все ваши старые изменения из предыдущего состояния вашей ветви в индекс

    $ git merge --squash HEAD@{1}
    
  4. Зафиксируйте ваши изменения - Git предварительно заполнит ваш редактор сообщением о коммите, содержащим все сообщения о коммитах из сжатых коммитов

Я упомянул простой псевдоним:

alias squash="git fetch; git reset --mixed origin/master; git merge --squash HEAD@{1}"

Вероятно, лучшим вариантом для этого будет использовать git merge --squash во время слияния. Это оставит вашу ветку в том виде, в каком она была разработана, и с ней довольно часто будет проще устранять неполадки, потому что у вас будет некоторое представление о том, что "я изменял эту конкретную функциональность в коммите Z", и, глядя на этот конкретный коммит, у вас контекст любых изменений, которые вы внесли в несколько файлов - просмотр одного коммита, который представляет собой сжатые результаты вашего пути разработки, делает его довольно трудным для запоминания: "О, да, мне пришлось изменить эту еще одну вещь в другом файле, тоже...". У вас также есть преимущество использования git bisect когда у вас есть весь доступный путь - все, что он может сказать вам в разбитом случае, это "этот огромный коммит здесь что-то сломал".

Результат использования git merge --squash это единственный коммит в ветви, в который вы "сливаетесь", который содержит кумулятивные изменения из вашей ветки, но он оставляет вашу оригинальную ветку в покое.

Найдите хэш для фиксации непосредственно перед тем, как вы запустите ветку, и скопируйте ее в буфер обмена. Затем выполните сброс к этому хешу.

$ git reset [hash]

Затем просто добавьте и зафиксируйте изменения в одном сообщении.

$ git add -A
$ git commit -m 'EVERYTHING SQUASHED'

Отредактируйте свой файл конфигурации git ~/.gitconfig и добавьте следующее в раздел псевдонимов

[alias]
    squash = "!f(){ CUR=`git rev-parse HEAD` && git reset --soft ${1} && git commit -m \"$(git log --format=%B ${1}..${CUR})\"; };f"

Этот псевдоним получает текущий хеш-коммит HEAD, сбрасывает обратно указанный вами коммит и создает новый коммит, сохраняющий все сообщения коммита.

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

git squash <refspec>

refspec может быть любой допустимой ссылкой на коммит, такой как хеш коммита, имя ветки, имя тега, HEAD^HEAD~3

Лучше всего сделать полный сброс и объединить предыдущую ГОЛОВКУ с сквошем. Вот псевдоним:

[alias]
  squash = "!f() { git reset --hard $1; git merge --squash HEAD@{1}; git commit; }; f"

Таким образом, вы можете назвать это так:

git squash master

Или раздавить из другой ветки, как dev:

git squash dev

Просто раздавить из исходной точки в основной ветке

Способ, которым я люблю раздавливать, — это перегруппировка коммитов без перебазирования, поэтому я могу перебазировать только после этого.

      # Squash current branch from its departure point in main branch. You must run
# this command when on your branch's last commit.
git-squash() {
    # https://stackoverflow.com/a/48524405/6320039
    local main_commit="$(git merge-base HEAD main)"
    local last_branch_commit="$(git rev-parse HEAD)"
    git reset --soft "$main_commit"
    # Preserve commits
    git commit -em "$(git log --reverse --format=%B ${main_commit}..${last_branch_commit})"
}

Исходник (и интеграция в dotfiles). Вдохновленный этим другим ответом troymass.

Конечно, теперь вы можете просто перебазировать с помощьюgit rebase main.

ПРИМЕЧАНИЕ: вы можете заменитьmainздесь сgit_main_branchесли вы пользователь zsh. Это выберет либо main, либо master.

Я не думаю, что это правильный ответ на этот вопрос.

Но я обычно сдавливаю свою ветку перед тем, как сделать Pull Request удаленному ведущему мастеру, используя следующую команду:

git rebase -i master

Но тогда вам все равно придется выбирать, что выбрать и раздавить.

Другие вопросы по тегам