Задать вопрос
Ответы пользователя по тегу Git
  • Как вернуть коммиты после rebase?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Почему «пропали» коммиты?

    Главная ошибка — использование --amend во время rebase.
    Команда git commit --amend не создает новый коммит, а перезаписывает предыдущий.

    Когда вы время интерактивного rebase на каждом шаге делаете --amend, вы по сути всё время заменяете один и тот же коммит. Остальные коммиты, которые Git должен был «применить» в процессе ребейза, просто исчезают, потому что их заменили.

    Как делать правильно?

    Во время rebase -i вместо amend нужно:

    git add <файлы> #  главное проиндексировать правки файлов
    git rebase --continue # тут гит уже сам сделает git commit --no-edit
    Вручную делать git commit перед continue имеет смысл только если вы хотите поменять ещё и сообщение коммита.

    Как восстановить утерянные коммиты

    Git не удаляет коммиты сразу. Они остаются в репозитории и доступны в reflog — журнале ссылок.

    Их можно найти так: git reflog

    Затем восстановить ветку: git reset --hard <хеш_из_reflog>

    Вывод

    Это не баг Git, а ожидаемое поведение. Просто rebase + amend — взрывоопасная смесь, особенно если не до конца понимать, что происходит.
    Ответ написан
    Комментировать
  • Как изменить дату создания commit-ов?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Используй простой скрипт
    #!/bin/bash
    
    # === Настройки ===
    COUNT=10
    NEW_DATE="2025-03-27T17:00:00"
    
    # === Автоматическая замена pick на edit ===
    export GIT_SEQUENCE_EDITOR="sed -i 's/^pick /edit /'"
    
    # === Старт интерактивного rebase ===
    git rebase -i HEAD~$COUNT
    
    # === Цикл по каждому коммиту с изменением даты ===
    while ! git rebase --continue 2>/dev/null; do
      GIT_COMMITTER_DATE="$NEW_DATE" git commit --amend --no-edit --date "$NEW_DATE"
    done
    
    echo
    echo "✅ Все $COUNT коммитов переписаны с новой датой: $NEW_DATE"
    echo " Не забудь сделать принудительный push: git push --force"

    Будут заменены обе даты: и author, и committer
    Ответ написан
    Комментировать
  • Как оптимально переносить состояние таблиц и объектов PL/SQL из БД в Git?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Можно попробовать подойти к задаче через автоматическую генерацию миграций из базы, чтобы не переносить данные вручную в CSV и SQL.

    Вот несколько подходов, которые могут помочь:

    1. Liquibase diff

      Liquibase умеет сравнивать текущее состояние базы с эталонным snapshot или changelog (команды liquibase diff, generateChangeLog). Это может автоматически сгенерировать changesets. Не всегда идеально, особенно для данных, но может служить хорошей стартовой точкой.

    2. Скрипт дампа и автоформатирования

      Написать утилиту, которая:
      • выгружает актуальные записи (по дате или через служебную метку),
      • форматирует результат построчно (для удобных диффов в Git),
      • сохраняет в SQL или CSV с нужным форматированием,
      • проверяет ошибки: зависимости, ключи, синтаксис и т. п.

    3. Служебное поле change_id

      Добавление такого поля в ключевые таблицы упростит группировку и экспорт связанных изменений. Это также упростит отладку и проверку связей.

    4. Проверки перед мержем

      Автоматический pre-merge скрипт может:
      • проверять, что ветка актуальна относительно master,
      • валидировать синтаксис SQL и CSV,
      • выявлять ошибки в зависимостях (foreign keys, отсутствие spec при наличии body и т. п.),
      • проверять потенциальные конфликты по ключам в changesets.

    5. Dolt и Bytebase

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


    Если кратко: можно улучшить текущую схему с помощью автоматизации и валидации, либо двигаться в сторону Git-ориентированных решений, где изменения фиксируются на уровне базы, а не вручную.
    Ответ написан
    Комментировать
  • Как сбросить состояние ветки develop к master непосредственно в репозитории (origin)?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Самый безопасный способ — создать синтетический коммит слияния, вливающий текущее актуальное состояние ветки master в ветку develop. Так у вас не будет проблем с отправкой исправления в общий репо и не будет конфликта с коллегами.

    git checkout develop # удостовериться что мы в нужной ветке
    git merge --ff $(git commit-tree -p develop -p master -m "Reset develop to master" master^{tree})

    Подробное объяснение

    По мотивам аналогичного вопроса
    • Конструкция master^{tree} — это ссылка на текущее состояние файлов из ветки master.
    • Команда git commit-tree — создаёт новый коммит, который:
    • Использует файлы из master.
    • Имеет двух «родителей»: текущий develop и master.
    • Устанавливает сообщение коммита: Reset develop to master.
    • Таким образом, создаётся «мостик» между develop и master, чтобы история изменений выглядела непрерывно.
    • git commit-tree -p develop -p master -m "Reset develop to master" master^{tree}
      — эта команда не просто создаст новый коммит, но ещё вернёт его хеш.
    • Обновляем develop, чтобы она просто «перескочила» на новый коммит.
      git merge --ff $(...)
    • --ff (fast-forward) говорит гиту просто передвинуть указатель develop вперёд на этот новый коммит, если это возможно без создания нового коммита слияния.
    • $(...) — это подстановка команды в bash, то есть git merge --ff получит на вход хеш коммита из предыдущего шага.

    Ответ написан
    Комментировать
  • Может ли удаленный репозиторий быть сразу и рабочей директорией проекта?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Вы некорректно поставили вопрос. Никакой репозиторий не может быть рабочим каталогом. Рабочий каталог репозитория и сам репозиторий это разные сущности и лежат в разных местах. Обычно репозиторий лежит в подкаталоге .git основного рабочего каталога проекта.

    Вы наверное хотели спросить — может ли во внешнем общем репозитории тоже быть свой рабочий каталог?

    Да, может, но с некоторыми ограничениями. Например нельзя пушить в ветку вышестоящего репозитория, если она в данный момент там активна и распакована в рабочий каталог. Если в общем репо HEAD стоит на ветке main, то вы легко сможете другие ветки отправить, но main не сможете и получите ошибку. И это логично.

    Забирать коммиты вы сможете из любой ветки, даже из активной.

    И у вас изначально ошибка вот тут:
    Создаю на сервере репозиторий git init. Создаю у себя репозиторий
    Для чего? Вы создали две отдельные истории. Даже если в обоих случаях получилась ветка с названием main, это всё равно будут разные ветки без общей истории. Не нужно так делать. Репозиторий следует создавать в одном месте, а затем уже клонировать в другие.

    Очень многие наступают на эти же грабли, когда инициализируют репозиторий локально, а затем создают НЕ ПУСТОЙ репозиторий на гитхабе. Потом удивляются, почему не получается их связать. ))

    Ни пуш ни пулл не работают.

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

    Поэтому общие репозитории проще делать без рабочего каталога, зачем он там?
    Но теоретически можно работать децентрализованно. Допустим если вы все сидите в одном офисе, то можно некоторых коллег добавить как remote со ссылками в локальной сети и спокойно обмениваться коммитами в любую сторону. Почему бы и нет? Вы только не сможете пушить ветки, над которыми коллеги у себя в данный момент работают и не сможете сломать им код.
    Ответ написан
    Комментировать
  • Что значит "Merge remote-tracking branch"?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Если при git pull возникает конфликт, это означает, что история ветки разошлась. Пока вы работали в локальной ветке, кто-то другой внёс изменения и отправил их во внешний репозиторий. Теперь Git не может просто передвинуть указатель ветки на новый коммит — ему нужно объединить две разные версии в одну.

    Вместо простого скачивания (fetch) и обновления указателя (fast-forward), Git создаёт коммит слияния (merge commit). Именно об этом говорит сообщение:

    Merge remote-tracking branch 'refs/remotes/origin/' into


    моя ветка приняла все изменения с удаленного репозитория и происходит слияние в моей ветке?

    Да, этот коммит объединяет локальные и внешние изменения.

    моя ветка поглащает origin и станет основной

    Да, в вашем репозитории. Но вы же собираетесь продолжать совместную работу над проектом? Значит после завершения слияния (merge) вы отправите обновленное состояние ветки в вышестоящий репозиторий с помощью git push, и ваша версия ветки станет там «основной», иначе у вас будет локальная версия ветки, отличная от вышестоящей.

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

    Что значит «я их принял»?
    Конфликты нельзя просто «принять». Их нужно разрешить — вручную объединить изменения. Если вы просто удалили свои или чужие правки, то фактически потеряли часть кода. Будьте внимательны: важно не просто устранить конфликт, а сохранить все нужные изменения.
    Ответ написан
    Комментировать
  • Как исправить ошибку: не удалось перенести некоторые рефсы в ветку?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Сделав amend вы фактически убрали этот коммит f97331c1c из ветки vlad-account в локальном репозитории и начали строить альтернативную версию этой ветки от предыдущего коммита. Так как старый коммит никуда не исчез из дерева (на него по прежнему указывает ветка origin/vlad-account), получается, что вы создали разветвление, а ветки vlad-account и origin/vlad-account теперь стали разными ветками, поэтому гит не знает что делать если быстрая перемотка невозможна (non-fast-forward).

    В данной конкретной ситуации, думаю, проще удалить старую историю, отправив локальную версию принудительно, указав ключ force.

    git push --force

    Гит вам советует склеить ветки обратно перед отправкой через pull
    Это тоже вариант, но получатся дубли коммитов в истории и, возможно, конфликты.
    Лучше просто перезаписать вторую ветку.
    Ответ написан
    8 комментариев
  • Как правильно работать с гит, если у тебя 2 фронтендера?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Git — это система контроля версий, которая помогает работать над проектами параллельно, не мешая друг другу. А то, что вы называете «залить на гит», скорее всего, значит «отправить изменения на GitHub» (или другую платформу). Эти понятия важно различать.

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

    Что касается описаний изменений. Ваш друг прав: нужно объяснять, что сделано, но вручную перечислять каждую строку не требуется. Git сам показывает разницу между версиями, а платформы вроде GitHub делают это наглядно.

    Вам стоит пройти курс по основам Git, чтобы понять, как он работает, зачем нужны ветки и как решать конфликты. Тогда таких споров не будет, и работа пойдёт быстрее.
    Ответ написан
    Комментировать
  • Как скачать все ветки если Git их не видит?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Вы сами попросили гит не скачивать весь репо, а скачать только 900 коммитов основной ветки. (параметром --depth 900). Это называется поверхностная копия shallow clone.

    Сейчас вы можете докачать всё с помощью команды
    git fetch --unshallow
    либо
    git fetch --all

    Если интернет ограничен, вы можете скачать например только последний коммит нужной ветки
    git fetch origin updater --depth=1
    И распаковать в рабочий каталог его
    git checkout updater
    Ответ написан
    Комментировать
  • Не получается подключиться к GitHub. Как решить проблему?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Проблема не в URL-адресе (/ в конце пути не влияет на работу).

    Permission to kirill-pereshyvalov-13/laravel-docker.git denied to KirillPereshyvalov13
    — вероятно, вы вошли не под тем аккаунтом, который имеет доступ к репозиторию.

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

    Удалите неправильные учетные данные из кэша:
    echo "url=https://github.com" | git credential reject

    При следующей попытке git push залогиньтесь как kirill-pereshyvalov-13 а не как KirillPereshyvalov13
    Ответ написан
    Комментировать
  • Какие ветки необходимо хранить на удаленном сервере?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Если проект небольшой, то Gitflow вам, скорее всего, не нужен. Достаточно одной главной ветки (main), куда изменения вносятся через pull request. Для каждой задачи создаёте короткие ветки (например, feature/task-name), работаете в них и после завершения слияния с main удаляете. Саму ветку main закрывайте от прямых изменений. Никто не должен коммитить напрямую в main.

    Что касается веток на сервере: храним как минимум те ветки, с которыми совместно работаем. Иначе как коллеги их получат к себе? Это могут быть главная ветка, стабильные версии или временные ветки задач, если нужно поделиться ими с коллегами. Всё остальное — локально.

    Ветки с номерами версий (например, 2.3.X) используются в крупных проектах для поддержки старых релизов и выпуска патчей. Если у вас нет таких требований, можно обойтись одной актуальной веткой.
    Ответ написан
    1 комментарий
  • Почему не удаляет __pycache__ из отслеживания?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Тут возможна путаница в терминологии.

    Гитигнор не удаляет файлы из отслеживания, а скорее наоборот — игнор убирает файлы из списка неотслеживаемых (Untracked). Чтобы случайно не начать их отслеживать (случайно не добавить файлы в репозиторий).

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

    Ну и ваше правило избыточно. Достаточно просто
    __pycache__/
    Ответ написан
    Комментировать
  • Как иициализировать 2 репы в одном проекте?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    у меня не связывается папка B2 c репозиторием с гитхаба

    Папка B2 автоматически связывается с гитхабом уже в момент клонирования туда репозитория.

    Но вы это не видите, так как инициализировали в папке packages пустой репозиторий и именно для него VSCode и показывает кнопку Publish Branch.
    .
    └───yyy.loc
        ├───.git 
        └───packages
            ├───.git # пустой репо созданный git init
            └───B2
                └───.git

    А чтобы VSCode увидел вложенный репо, лежащий в папке packages/B2 вам надо в папке packages тоже создать .gitignore и прописать в нем /B2/
    Ответ написан
    7 комментариев
  • Почему 2 ветки Git не сливаются?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Вы же сами увидели в vscode — что произошло. Вы забыли обновить ветку и начали строить вторую цепочку коммитов. Ваша ветка раздвоилась (diverged).

    Гит вам тоже всё подробно пояснил, что нельзя пушить в другую ветку и предлагает вам сначала объединить разные ветки в одну используя pull.

    Но тут вылезла другая проблема, что у вас немного недонастроен гит. В новых версиях он просит вас уточнить, каким методом вы хотите объединять ветки? Можно путем создания коммита слияния, а можно путем пересаживания вашей текущей ветки main на вершину вышестоящей ветки origin/main, чтобы история осталась простой и линейной, без этих разветвлений и слияний.

    Первая стратегия задается командой
    git config pull.rebase false # merge
    И это поведение по-умолчанию которое было раньше. Рекоменду вам его и выбрать. Эта команда выполняется один раз и больше вам не потребуется.

    А затем просто повторите git pull и всё сработает. Разве что могут возникнуть конфликт, но это уже другая тема.

    Если хотите сохранить линейную историю то можно принудительно вызвать вторую стратегию только для одного раза
    git pull --rebase
    Ответ написан
    3 комментария
  • Как устранить ошибку: LFS...failed to push?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Гуглить фразу failed to push (не удалось отправить) бесполезно. Это слишком абстрактное описание проблемы. Причины могут быть самые разные.

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

    На данном этапе вам проще удалить репозиторий
    rm -rf ".git"
    И начать заново. Но не пихать в коммит что попало, git add . а индексировать только нужные файлы.
    Ответ написан
    Комментировать
  • Как копировать не все файлы из репозитория?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Ваша задача имеет простое решение, так как в гите появилась поддержка работы с моно-репозиториями.

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

    Git теперь поддерживает так называемое выборочное скачивание содержимого через механизм sparse-checkout. Это позволяет вам работать только с нужными файлами или каталогами, исключая остальные, такие как node_modules.
    # Клонировать репозиторий с фильтром, чтобы не загружать все файлы сразу
    git clone --filter=blob:none --sparse https://example.com/repo.git
    cd repo
    # Инициализировать выборочную загрузку
    git sparse-checkout init --no-cone


    Нужно отредактировать файл .git/info/sparse-checkout:
    # включить все файлы
    /*
    # кроме одной папки
    !/node_modules/

    Применить настройки
    # Докачать всё, кроме папки node_modules
    git sparse-checkout reapply

    После выполнения этих команд Git скачает весь репозиторий, исключая указанный каталог node_modules. Вы сможете работать с репозиторием, не загружая лишние данные. Если потребуется вернуть node_modules, достаточно удалить соответствующее правило из файла sparse-checkout и снова выполнить git sparse-checkout reapply
    Ответ написан
    Комментировать
  • Почему гит видит не отслеживаемые файлы в игнорируемой папке, но не видит их?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    по мнению status никаких неотслеживаемых файлов нет, а по мнению pull есть неотслеживаемые файлы которые будут перезаписаны. Как так?

    Легко! В вышестояшем репозитории эта папка закоммичена. При pull возникает конфликт.

    А вот кстати и коммит который пытаюсь спулить:
    [htdocs]$ git status

    Коммит то где? Статус рабочего каталога это не коммит.

    Что может быть не так?

    Забудьте про команды типа
    git add --all .
    git commit -am "..."

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

    И покажите свой .gitignore
    Ответ написан
    Комментировать
  • Почему запрашивается пароль при git push если авторизация по ключу настроена?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Если вы хотите аутентификацию по ключу, то вам нужен remote с URL для SSH-протокола, а у вас тут HTTPS-протокол, на который ваши SSH-ключи никак не влияют — там аутентификация своя — по паролю, либо токену.

    Скорее всего вам надо поменять ссылку на правильную.
    git remote set-url origin git@gitlab.com:malashko/bla-bla-bla.git
    Ответ написан
    1 комментарий
  • Как откатить состояние папки в Git?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Отменить все незакоммиченные изменения в рабочем каталоге поможет команда
    git reset --hard

    PS. Немного подумав мне теперь нравится такой универсальный и более корректный способ.
    git restore --source=хеш_коммита --staged --worktree .

    Затем не забудьте закоммитить новые изменения.

    Указывая --source=хеш_коммита, вы говорите Git использовать содержимое файлов из этого коммита.

    Флаг --staged значит, что изменения будут сразу проиндексированы, как если бы вы их добавили с помощью git add. Этот флаг особенно полезен, если вы хотите сбросить изменения, которые уже были добавлены в индекс, но ещё не закоммичены.

    Флаг --worktree указывает Git восстановить файлы в рабочем каталоге до состояния указанного коммита. Это означает, что любые незакоммиченные изменения в рабочих файлах будут сброшены, и файлы будут восстановлены до состояния, соответствующего указанному коммиту.

    Точка в конце команды указывает, что операция восстановления должна быть применена ко всем файлам в текущем каталоге и его подкаталогах. Это значит, что все файлы в проекте будут восстановлены до состояния, соответствующего указанному коммиту.
    Ответ написан
    5 комментариев
  • Как удалить отслеживание версий в случайно созданном репозитории Git?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Чтобы прекратить отслеживание версий в случайно созданном репозитории в каталоге C:\Users\<МойПользователь>, можно воспользоваться командой в Git Bash:

    rm -r "~/.git"

    Команда удалит каталог .git и все его содержимое (рекурсивно) из указанного пути. В данном случае, путь указывает на домашний каталог пользователя (обозначенный как ~)
    .git — это скрытый каталог, используемый Git для хранения всех данных о репозитории (коммиты, история, конфигурация и т. д.). Удаление этого каталога приведет к удалению всей информации о репозитории, фактически «разгитив» проект.
    Ответ написан
    Комментировать