git rebase это отличный способ сделать историю линейной и визуально красивой. Но для каждого коммита, у которого возникает конфликт, приходится его исправлять и делать git rebase --continue. В случае длинных веток таких остановок для исправления конфликтов может быть довольно много. В этой статье я расскажу про нестандартный метод, как можно исправить все эти конфликты разом, что позволяет сделать git rebase быстро и чисто механически.

Пример "до"
Пример "до"
Пример "после"
Пример "после"

Метод "rebase via merge"

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

Стандартный "merge"

Плюсы

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

  • Все конфликты видны сразу и в минимальном объеме.

  • Конфликты нужно исправить только один раз.

Минусы

  • Каждый раз добавляется merge-коммит.

  • История изменений становится нелинейной.

  • Репозиторий становится более сложным для восприятия и работы.

Стандартный "rebase"

Плюсы

  • Простая, линейная история.

  • Легко отслеживать изменения визуально.

Минусы

  • Конфликты исправляются на уровне отдельных коммитов, с остановкой процесса.

  • В некоторых случаях это даже увеличивает суммарный объем конфликтов.

  • Переписывает историю, поэтому не подходит для совместной работы над веткой.

Метод "rebase via merge"

Плюсы

  • Сразу показывает все конфликты.

  • Объем конфликтов и работа по исправлению минимальны, как в случае "merge".

  • Процесс "rebase" полностью автоматический, конфликты исправляются механически.

  • История линейная как и у "rebase".

Минусы

  • Промежуточные коммиты могут не компилироваться, над ними нет ручного контроля.

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

  • Переписывает историю (аналогично "rebase").

Идея метода и алгоритм

Коммит в git-е описывает не изменения, а состояние проекта целиком, то есть, зная хэш коммита, можно в точности восстановить проект. И если форсировать merge, можно сразу увидеть все конфликты, а исправив их, получить хэш нужного состояния проекта, с учетом всех изменений в обоих ветках. Далее, если запустить rebase c флагом механического разрешения конфликтов в "нашу" пользу, то он гарантировано завершится очень быстро. И останется только сравнить состояние проекта, чтобы оно было правильным.

Скрипт реализует следующий алгоритм:

  • Показывает название веток и последний коммит на обоих. Проверяет, что rebase возможен. Ждет подтверждения от пользователя прежде чем начать действовать.

  • Переключает с текущей ветки на сам коммит (режим detached head).

  • Запускает скрытый merge из базовой ветки относительно текущего коммита.

  • Если есть конфликты, то они вручную исправляются на этом шаге.

  • Скрипт запоминает результат merge-а.

  • Скрипт возвращается на ветку и запускает для нее полностью автоматический rebase.

  • Форсируется выбор "наших" изменений вместо "их" (что не всегда логически корректно).

  • Сравнивает результат rebase-a с тем, как конфликты были исправлены вручную.

  • Если есть разница, то добавляет один коммит с корректным состоянием проекта.

Стоит отметить:

  • Если нет конфликтов, то не будет и никакого ручного исправления.

  • Конечный результат гарантировано повторяет результат ручного исправления конфликтов.

  • Все "наши" уникальные изменения остаются в истории ветки.

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

Как скачать и запустить

Скачиваем скрипт и делаем его исполняемым. Эти команды работают универсально для macOS / Linux / Windows (git-bash).

curl https://raw.githubusercontent.com/capslocky/git-rebase-via-merge/master/git-rebase-via-merge.sh -o ~/git-rebase-via-merge.sh

chmod +x ~/git-rebase-via-merge.sh

И используем этот скрипт:

~/git-rebase-via-merge.sh

Вместо обычного rebase:

git rebase origin/develop

Вообще, более удобно, если создать алиас:

git config --global alias.rvm '!bash ~/git-rebase-via-merge.sh'

Тогда достаточно ввести:

git rvm

По умолчанию базовая ветка origin/develop, но это можно исправить в скрипте или указать динамически:

git rvm origin/main

Демо репозиторий

Проблема будет хорошо видна на примере следующего небольшого репозитория на github. Две ветки develop и feature вносят разные изменения в одни и те же файлы. Причем тут два типа конфликтов: только содержимое (Linus.txt, Margaret.txt) и на уровне файловой структуры (Ken.txt, Dennis.txt).

Файл

Ветка develop (John)

Ветка feature (Alex)

Linus.txt

изменён

изменён

Margaret.txt

добавлен

добавлен

Ken.txt

перемещен в папку "engineers"

перемещен в папку "scientists"

Dennis.txt

удален

изменён

Демо репозиторий
Демо репозиторий

Если делать обычный rebase, то он остановится 5 раз и каждый раз нужно будет исправлять конфликт и идти дальше с помощью git rebase --continue.

git checkout feature
git rebase develop

Тогда как, используя данный метод, будет так:

  • Все конфликты решаются за один раз, в самом начале.

  • rebase запускается и завершается автоматически.

  • Результат это обычная прямолинейная топология.

  • Конечный код полностью отражает то, как были исправлены конфликты.

git checkout feature
~/git-rebase-via-merge.sh

В начале скрипт покажет сами ветки и запрос на продолжение:

This script will perform a rebase via merge.

Current branch:
feature (ce0ef5b)
Alex                 | 2 weeks ago    | Moved Ken to scientists

Base branch:
origin/develop (04a5062)
John                 | 2 weeks ago    | Removed Dennis

Continue (c) / Abort (a)

Выбираем c чтобы продолжить, и сразу увидем все конфликты. Необходимо исправить их вручную, сделать stage всех изменений, не коммитить, и продолжить.

CONFLICT (modify/delete): Dennis.txt deleted in origin/develop and modified in HEAD.  Version HEAD of Dennis.txt left in tree.
CONFLICT (rename/rename): Ken.txt renamed to scientists/Ken.txt in HEAD and to engineers/Ken.txt in origin/develop.
Auto-merging Linus.txt
CONFLICT (content): Merge conflict in Linus.txt
Auto-merging Margaret.txt
CONFLICT (add/add): Merge conflict in Margaret.txt
Automatic merge failed; fix conflicts and then commit the result.

Fix all conflicts in the following files, stage all changes, do not commit, and type 'c':
Dennis.txt
Ken.txt
Linus.txt
Margaret.txt
engineers/Ken.txt
scientists/Ken.txt

Continue merge (c) / Abort merge (a)

Далее скрипт сам завершает merge и делает форсированный rebase.

[detached HEAD 83b1545] Hidden orphaned commit with merge result.
Merge succeeded. The target state is: 83b1545
Starting rebase. Any conflicts will be resolved automatically.

CONFLICT (modify/delete): Dennis.txt deleted in HEAD and modified in 8d48e53 (Changed Dennis).  Version 8d48e53 (Changed Dennis) of Dennis.txt left in tree.
File-level conflict detected. Removing their file, keeping ours.
DU Dennis.txt

[detached HEAD ec7a42f] Changed Dennis
 Author: Alex <alex.t@mail.org>
 1 file changed, 5 insertions(+)
 create mode 100644 Dennis.txt

CONFLICT (rename/rename): Ken.txt renamed to engineers/Ken.txt in HEAD and to scientists/Ken.txt in ce0ef5b (Moved Ken to scientists).
File-level conflict detected. Removing their file, keeping ours.
DD Ken.txt
AU engineers/Ken.txt
UA scientists/Ken.txt
rm 'Ken.txt'
rm 'engineers/Ken.txt'

[detached HEAD 3b0e034] Moved Ken to scientists
 Author: Alex <alex.t@mail.org>
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename {engineers => scientists}/Ken.txt (100%)
Restoring the project state from the hidden result with one additional commit.

Updating 3b0e034..109d7a3
Fast-forward
 Linus.txt | 1 +
 1 file changed, 1 insertion(+)

Done. Current branch:
feature (109d7a3)
Alex                 | 0 seconds ago  | Rebase via merge. 'feature' rebased on 'origin/develop'.

Технические детали

Вот так запускается merge. Он проходит полностью в режиме detached head, то есть без активной ветки.

  git checkout "$current_branch_hash"
  git merge "$base_branch" -m "Hidden orphaned commit with merge result."

Возврат на ветку и запуск rebase, с автоматическим выбором "наших" изменений при конфликтах. В отличие от merge, этот флаг у rebase действует наоборот: "theirs" это "наш" вариант, "ours" это "их" вариант.

git checkout "$current_branch"
git rebase "$base_branch" -X theirs

В случае конфликта на уровне файловой системы, удаляем "их" файлы, добавляем все остальное и идем дальше.

git status --porcelain | grep -E "^(DD|AU|UD) " | cut -c4- | xargs -r git rm --
git add -A
git rebase --continue

Команда git status --porcelain помогает определить роль файла в конфликте и механическое действие

Флаг в конфликте

Действие

Их изменения

Наши изменения

DU Dennis.txt

git add

Файл удален

Файл изменен

DD Ken.txt

git rm

Файл удален

Файл удален

AU engineers/Ken.txt

git rm

Новое имя или локация

Файл отсутствует

UA scientists/Ken.txt

git add

Файл отсутствует

Новое имя или локация

AA Margaret.txt

git add

Файл добавлен

Файл добавлен

UD File.txt

git rm

Файл изменен

Файл удален

UU File.txt

git add

Файл изменен

Файл изменен

Извлекаем состояние проекта из коммитов. Про это есть отдельная статья на Хабре.

current_tree=$(git cat-file -p HEAD | grep "^tree")
result_tree=$(git cat-file -p "$hidden_result_hash" | grep "^tree")

И если они не совпадают, то создаем коммит с нужным состоянием проекта.

git commit-tree $hidden_result_hash^{tree} -p HEAD -m "$additional_commit_message"
git merge --ff "$additional_commit_hash"

Критика

Почему не 'rerere'?

Функция rerere помогает автоматически исправить повторяющийся конфликт, когда он совпадает с тем, что когда-то раньше было исправлено вручную. Однако rerere всегда добавляет определенный риск, так как эта функция скрывает конфликты.

Коммиты будут показывать неправильное исправление конфликта.

Да, так может быть, потому что иногда логически корректно выбрать "их" вариант или объединить оба варианта. В таком случае дополнительный финальный коммит гарантировано вернет корректное исправление конфликта. Важно также то, что в истории останется изначальный "наш" вариант кода, и его даже можно cherry-pick-нуть.

Дополнительный коммит выглядит ужасно

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

git reset --soft HEAD~1
git commit --amend --no-edit

Полный текст скрипта

Файл git-rebase-via-merge.sh

Содержимое скрипта
#!/usr/bin/env bash
#
# https://github.com/capslocky/git-rebase-via-merge

default_base_branch="origin/develop"
base_branch=${1:-$default_base_branch}
export GIT_ADVICE=0
set -e

main() {
  echo "This script will perform a rebase via merge."
  echo
  init
  
  git checkout --quiet "$current_branch_hash" # checkout to detached head (no branch, only commit)
  git merge "$base_branch" -m "Hidden orphaned commit with merge result." || true
  echo

  if [ -n "$(get_unstaged_files)" ]; then
    prompt_user_to_fix_conflicts
  fi

  hidden_result_hash=$(get_hash HEAD)

  echo "Merge succeeded. The target state is: $hidden_result_hash"
  echo "Starting rebase. Any conflicts will be resolved automatically."
  echo

  git checkout --quiet "$current_branch"
  git rebase "$base_branch" -X theirs 2>/dev/null || true # here option 'theirs' means choosing our changes.

  while [ -n "$(get_unstaged_files)" ]; do
    echo "File-level conflict detected. Removing their file, keeping ours." # e.g. parallel file rename
    git status --porcelain
    git status --porcelain | grep -E "^(DD|AU|UD) " | cut -c4- | xargs -r git rm --
    git add -A
    echo
    git -c core.editor=true rebase --continue 2>/dev/null || true # suppressing opening commit message editor
  done

  current_tree=$(git cat-file -p HEAD | grep "^tree")
  result_tree=$(git cat-file -p "$hidden_result_hash" | grep "^tree")

  if [ "$current_tree" != "$result_tree" ]; then
    echo "Restoring the project state from the hidden result with one additional commit."
    echo

    additional_commit_message="Rebase via merge. '$current_branch' rebased on '$base_branch'."
    additional_commit_hash=$(git commit-tree $hidden_result_hash^{tree} -p HEAD -m "$additional_commit_message")

    git merge --ff "$additional_commit_hash"
    
    # uncomment if you want to exclude additional commits completely:
    # git reset --soft HEAD~1
    # git commit --amend --no-edit
    echo
  fi

  echo "Done. Current branch:"
  echo "$(git branch --show-current) ($(get_hash HEAD))"
  show_commit HEAD
  exit 0
}

init() {
  if [ -d "$(git rev-parse --git-path rebase-merge)" ]; then
    echo "Can't rebase. Rebase in progress detected. Continue or abort existing rebase."
    exit 1
  fi

  if [ -f "$(git rev-parse --git-path MERGE_HEAD)" ]; then
    echo "Can't rebase. Merge in progress detected. Continue or abort existing merge."
    exit 1
  fi

  current_branch=$(git branch --show-current)
  current_branch_hash=$(get_hash "$current_branch")
  base_branch_hash=$(get_hash "$base_branch")

  if [ -z "$current_branch" ]; then
    echo "Can't rebase. There is no current branch: detached head."
    exit 1
  fi

  if [ -z "$base_branch_hash" ]; then
    echo "Can't rebase. Base branch '$base_branch' not found."
    exit 1
  fi

  echo "Current branch:"
  echo "$current_branch ($current_branch_hash)"
  show_commit "$current_branch_hash"
  echo

  echo "Base branch:"
  echo "$base_branch ($base_branch_hash)"
  show_commit "$base_branch_hash"
  echo

  if [ -n "$(get_any_changed_files)" ]; then
    echo "Can't rebase. You need to commit changes in the following files:"
    echo
    get_any_changed_files
    exit 1
  fi

  if [ "$base_branch_hash" = "$current_branch_hash" ]; then
    echo "Can't rebase. Current branch is equal to the base branch."
    exit 1
  fi

  if [ -z "$(git rev-list "$base_branch" ^"$current_branch")" ]; then
    echo "Can't rebase. Current branch is already rebased."
    exit 1
  fi

  if [ -z "$(git rev-list ^"$base_branch" "$current_branch")" ]; then
    echo "Can't rebase. Current branch has no any unique commits. You can do fast-forward merge."
    exit 1
  fi

  echo "Continue (c) / Abort (a)"
  read input

  if [ "$input" != "c" ]; then
    echo "Aborted."
    exit 1
  fi
}

prompt_user_to_fix_conflicts() {
  echo "Fix all conflicts in the following files, stage all changes, do not commit, and type 'c':"
  get_unstaged_files
  echo

  while true; do
    echo "Continue merge (c) / Abort merge (a)"
    read input
    echo

    if [ "$input" = "c" ]; then
      if [ -n "$(get_unstaged_files)" ]; then
        echo "There are still unstaged files:"
        get_unstaged_files
        echo
      else
        git -c core.editor=true merge --continue # suppressing opening commit message editor
        break
      fi
    elif [ "$input" = "a" ]; then
      echo "Aborting merge."
      git merge --abort
      git checkout "$current_branch"
      exit 2
    else
      echo "Invalid option: $input"
    fi
  done
}

get_any_changed_files() {
  git status --porcelain --ignore-submodules=dirty | cut -c4-
}

get_unstaged_files() {
  git status --porcelain --ignore-submodules=dirty | grep -v "^. " | cut -c4-
}

get_hash() {
  git rev-parse --short "$1" 2>/dev/null || true
}

show_commit() {
  git log -n 1 --pretty=format:"%<(20)%an | %<(14)%ar | %s" "$1"
}

main

Кому этот метод не подходит

В следующих случаях лучше его не применять:

  • Нужно билдить каждый промежуточный коммит, или чтобы он всегда показывал правильное ручное исправление конфликта.

  • Дополнительный коммит не допустим (пример на картинке ниже). Но его можно полностью исключить.

Дополнительный коммит
Дополнительный коммит

Итог

Я опубликовал этот скрипт несколько лет назад, но только недавно добавил автоматическое исправление конфликтов файловой системы, а также обновил README. Если есть фидбек или вопрос, я отвечу в комментариях.

Ссылка на гитхаб

Комментарии (13)


  1. Advixum
    20.02.2026 05:36

    Сейчас в народе насколько распространено использование команд git через терминал? Пользовался ими, когда изучал документацию гита. Давно уже всё забыто, поскольку как-то быстро перешёл к использованию средств IDE, а потом на работе lazygit + kdiff3. Часто встречаю утверждения, что тру программист должен рулить гитом только через терминал.


    1. capslocky Автор
      20.02.2026 05:36

      Мне кажется, что это дело вкуса и привычки. Я тоже раньше думал, что тру программист должен выбирать терминал.


    1. positroid
      20.02.2026 05:36

      Использую терминал для всего, что связано с ветками и коммитами. Есть исключения, которые проще сделать в GUI:

      - разрешение конфликтов,
      - просмотр графа репозитория,
      - diff по коммитам,
      - иногда cherry-pick тоже удобнее из интерфейса дернуть.

      Рядовые git add / commit / branch / checkout / merge / rebase - тольки из cli. Благо, что в Jetbrains появились автодополнения названий веток, например. Жаль, что не работают с кастомными баш алиасами (gb = git branch), ну да ладно.


  1. NightShad0w
    20.02.2026 05:36

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

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

    Ребейзы делают с какой-то конкретной целью. Чаще всего аккуратно и воспроизводимо слить атомарные изменения, чтобы сохранить историю. Это очень веская причина не создавать сломанные состояния проекта по дороге, которые починены последним искусственным обратным-дифф коммитом.

    Если на каждом коммите конфликт - ну так можно сквошнуть ветку при ребейзе самой себя, или поребейзить несколько раз на свой рут, переставляя и редактируя контент для решения конфликтов правильно, и потом эту новую, но все еще полезную историю и пересадить, разрешив конфликты один раз в начале и оставив осмысленные коммиты.

    P.S. Да не оскорбятся хранители чистоты языка за использование заимствований...


    1. capslocky Автор
      20.02.2026 05:36

      Есть несколько моментов. Допустим, на ветке 15 коммитов и она готова для merge-а. В общем случае, заранее неизвестно будут ли конфликты и в каком объеме. Если история коммитов не важна, то да, можно просто сквошить все 15 коммитов в один большой коммит, и там уже не важно merge или rebase, это будет один и тот же большой конфликт.

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

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

      Обратный дифф не вычисляется, точнее после безусловного ребейза проект полностью заменяется корректным состоянием после сделанного merge-a, поэтому возникает дополнительный коммит. Но его легко убрать, соединив с предыдущим коммитом.


      1. nikolay-ermolenko
        20.02.2026 05:36

        и там уже не важно merge или rebase

        Как это не важно? Пока вы делали свою фичу, целевая ветка уже уехала: в неё влили пяток или десяток МРов. Если сделать merge, то история будет нелинейна. Откуда-то из небытия вдруг прилетает ветка. В то время, как все вливания веток должны идти строго друг за другом.

        Если вы месяц делали фичу и вдруг возникла необходимость влить, а тут конфликты, то у кого вы будете выяснять что там имелось в виду? Кто-то забыл уже, кто-то в отпуске, кто-то в больничке, кто-то уволился. Проще будет начать новую ветку от develop и попытаться что-то черипикнуть, а что-то заново реализовать.

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

        Утро начинается с ребэйза )


        1. capslocky Автор
          20.02.2026 05:36

          Я имел в виду, что работа по исправлению конфликтов становится одинаковой между merge и rebase в предельном случае, когда в ветке всего один коммит.


      1. NightShad0w
        20.02.2026 05:36

        К слову - я сторонник ребейзов. И полезность мерджей в повседневной работе для меня сомнительна. Есть там специальные случаи, но в дев ветку - ребейз ван лав.

         Получается, что описание диффа старое, а код в нем новый, но это является нормой в классическом подходе.

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

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

        Вот тут я не понимаю. В чем разница в целях разных ребейзов?

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

        А в при необычном ребейзе предложенным способом - что именно содержит моя история до искусственного коммита после ребейза? Оригинальные коммиты нахлобученные на апстрим как есть - тогда это в моменте ломает апстрим. И сохранив историю, мы оставим непредсказуемо поломанные состояния. Другой участник проекта не будет ожидать что коммиты в апстриме могут в какой-то момент нарушить гарантию качества апстрима с восстановлением гарантии где-то позже по истории отдельным коммитом.

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


        1. capslocky Автор
          20.02.2026 05:36

          Допустим, общая ветка (upstream) это develop, есть три варианта насколько строго требовать корректность коммитов в репозитории на сервере:

          1. develop должен быть корректным в любой момент времени.

          2. develop + feature ветки должны быть корректными в любой момент времени.

          3. все коммиты в истории всех веток должны быть корректными.

          Первый вариант наиболее распространенный, дает больше свободы разработчикам и меньше давит на них.

          Второй вариант имеет смысл если над feature веткой работают два разработчика одновременно, или когда ветка отдельно деплоится для тестирования.

          Третий вариант самый строгий. В общем он естественный если только делать merge. Но в случае rebase всегда гарантировать синтаксическую и логическую корректность каждого rebase-нутого коммита становится очень сложно.

          Мой метод rebase-а подходит для 1 и 2 вариантов: upstream всегда рабочий, все мерджи в upstream несут только корректный дифф, feature ветки тоже корректны в любой момент времени (можно сбилдить и протестировать).

          Минус моего метода в том, что если сделать checkout какого-то промежуточного коммита, то он может не сбилдится, то есть 3 вариант отпадает. Только как правило в этом нет необходимости.


          1. NightShad0w
            20.02.2026 05:36

            Понял, спасибо.


  1. Forigen
    20.02.2026 05:36

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

    Я больше 10 лет работаю с гит исключительно в терминале. И на моей памяти от рибейса больше проблем потому что всегда кто-то умудряется похерить историю. Рибейс подразумевает форс пуш и это громадный минус.

    И зачем в современном производстве с гит хабами, гитлабами , Ишью трекерами и ci, кому-то необходимо лазить в историю гита мне непонятно. Информация и так доступна с избытком .

    Деыолтный конфиг, ff true, merge true, ort стратегия, минимум конфликтов, минимум резолвов при повторных синках.

    На ттм надо ориентироваться в таких вещах с нашими инструментами.


    1. capslocky Автор
      20.02.2026 05:36

      Если разработчик лично предпочитает merge, но на текущем проекте всем нужно делать rebase, то в таком случае данный метод это очень хороший компромисс.

      И я согласен, что rebase требует большей квалификации и понимания, чем merge. И что rebase противоречит оригинальной идеологии git, что все коммиты должны быть иммутабельны.


      1. Forigen
        20.02.2026 05:36

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