Удалить из коммита файл git: git — Как удалить один файл из последнего коммита
Как в Git убрать файл из подготовки в коммиту?
Deprecated: Function create_function() is deprecated in /home/worldhel/public_html/wp-content/plugins/codecolorer/lib/geshi.php on line 4698
Принято считать, что файл в репозитории, находящемся под версионным контролем SCV GIT, может находится в одном из 4 состояний:
- Неотслеживаемый Untracked
- Отслеживаемый неизмененный Tracked unmodified
- Отслеживаемый с изменениями Tracked modified
- Отслеживаемый подготовленный для фиксации в коммит Tracked staged
Файл со статусом staged — это файл который находится под версионным контролем, в который были внесены изменения, и эти изменения в файле были подготовлены для фиксации в следующем коммите командой git add .
Следующим логическим шагом является фиксация таких файлов staged в коммит с помощью команды $ git commit -m "Комментарий к коммиту"
, но что если Вы захотите один из файлов пока что не включать в следующий коммит?
Для этого нужно перевести файл из состояния tracked staged в состояние tracked modified. Это значит, что git продолжает осуществлять контроль над всеми сделанными в этом файле изменениями, просто файл не будет добавлен в следующий коммит.
Делается это очень просто при помощи команды:
1 | $ git reset HEAD имя_файла |
Рассмотрим все вышесказанное на наглядном примере. У нас есть каталог с тремя измененными файлами, если выполним команду $ git status
, то узнаем состояние репозитория.
Состояние репозитория. Имеются изменения в 3 файлах.
Допустим, что в следующий коммит мы решили добавить все 3 файла с расширением php, и вначале мы добавляем файлы для фиксации в коммит, командой:
Теперь если мы посмотрим статус файлов в репозитории, то увидим, что эти 3 файла теперь в состоянии staged и готовы к фиксации в коммит.
Файлы в состоянии staged.
По каким-то причинам, мы посчитали, что один файл third.php рано включать в следующий коммит, например не подходит под общую логику коммита, и будет включен в более поздний. Тогда воспользуемся коммандой, которая сбросит статус файла на изначальное:
1 | $ git reset HEAD third.php |
Результат работы команды git reset HEAD.
Теперь если сделать коммит изменений, то в него войдут только желаемые файлы.
1 | $ git commit -m «Текст коммита» |
В результате манипуляций у нас должен возникнуть новый коммит, при этом нужный файл в него войти не должен. Убедимся в этом при помощи двух команд:
1 | $ git log -2 |
В качестве резюме отметим, что если файл по ошибке переведен в статус staged, в системе контроля версий GIT очень удобно и быстро перевести в его в предыдущий статус при помощи команды git reset HEAD.
Добавление, удаление и переименование файлов в репозитории
В рамках данного урока рассмотрим вопросы, касающиеся добавления, удаления и переименования файлов в git репозитории.
Добавление файлов в git репозиторий
Добавление файлов в репозиторий – это достаточно простая операция, мало чем отличающаяся от отправки изменений в отслеживаемых файлах в репозиторий. Мы уже не раз выполняли эту операцию в предыдущих уроках, но сделаем это ещё раз. Создадим новый репозиторий, для этого перейдите в каталог, в котором вы хотите его расположить и введите команду git init.
> git init
Создайте в каталоге файл README.md любым удобным для вас способом, мы сделаем это с помощью команды touch.
> touch README.md
Теперь проверим состояние отслеживаемой директории.
> git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) README.md nothing added to commit but untracked files present (use "git add" to track)
Как вы можете видеть: в рабочей директории есть один неотслеживаемый файл README.md. Git нам подсказывает, что нужно сделать для того, чтобы начать отслеживать изменения в файле README.md: необходимо выполнить команду git add, сделаем это.
> git add README.md
Посмотрим ещё раз на состояние.
> git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: README.md
Видно, что информация о появлении нового файла попала в stage. Для того чтобы это изменение зафиксировалось в репозитории необходимо выполнить команду git commit.
> git commit -m "add README.md file" [master (root-commit) 0bb6c94] add README.md file 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md
Теперь в рабочей директории и в stage нет объектов, информацию об изменении которых необходимо внести в репозиторий.
> git status On branch master nothing to commit, working tree clean
В репозиторий был сделан один коммит.
> git log --oneline 0bb6c94 add README.md file
Удаление файлов из git репозитория и из stage
Удаление файла из stage
Вначале разберемся со stage. Создадим ещё один файл.
> touch main.c
“Отправим” файл main.c в stage.
> git add main.c
Внесем изменения в README.md.
> echo "# README" > README.md
Информацию об этом также отправим в stage.
> git add README.md
Посмотрим на состояние stage.
> git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.md new file: main.c
Если нам необходимо убрать из stage, какой-то из этих файлов (main.c или README.md), то для этого можно воспользоваться командой git –rm cashed <filename>, сделаем это для файла main.c.
> git rm --cached main.c rm 'main.c'
Теперь посмотрим на состояние рабочей директории и stage.
> git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.md Untracked files: (use "git add <file>..." to include in what will be committed) main.c
Видно, что изменения в файле README.md готовы для коммита, а вот файл main.c перешел в состояние – неотслеживаемый. Отправим main.c в stage и, после этого, сделаем коммит в репозиторий.
> git add main.c > git commit -m "add main.c and do some changes in README.md" [master 49049bc] add main.c and do some changes in README.md 2 files changed, 1 insertion(+) create mode 100644 main.c
Удаление файлов из git репозитория
Удалить файл из репозитория можно двумя способами: первый – удалить его из рабочей директории и уведомить об этом git; второй – воспользоваться средствами git. Начнем с первого способа. Для начала посмотрим, какие файлы у нас хранятся в репозитории.
> git ls-tree master 100644 blob 7e59600739c96546163833214c36459e324bad0a README.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 main.c
Удалим файл main.c из рабочей директории.
> rm main.c > ls README.md
Уведомим об этом систему git.
> git rm main.c rm 'main.c'
Вместо команды git rm можно использовать git add, но само слово add в данном случае будет звучать несколько неоднозначно, поэтому лучше использовать rm. На данном этапе еще можно вернуть все назад с помощью команды git checkout — <filename>, в результате, в нашу рабочую директорию будет скопирован файл из репозитория. Создадим коммит, фиксирующий удаление файла.
> git commit -m "remove main.c" [master d4e22ae] remove main.c 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 main.c
Теперь в репозитории остался только один файл README.md.
> git ls-tree master 100644 blob 7e59600739c96546163833214c36459e324bad0a README.md
Второй способ – это сразу использовать команду git rm без предварительного удаления файла из директории. Вновь создадим файл main.c и добавим его в репозиторий.
> touch main.c > git add main.c > git commit -m "add main.c file" [master 6d93049] add main.c file 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 main.c > git ls-tree master 100644 blob 7e59600739c96546163833214c36459e324bad0a README.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 main.c
Удалим файл из репозитория.
> git rm main.c rm 'main.c' > git commit -m "deleted: main.c file" [master ba7d027] deleted: main.c file 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 main.c
Файла main.c больше нет в репозитории.
> git ls-tree master 100644 blob 7e59600739c96546163833214c36459e324bad0a README.md
Его также нет и в рабочем каталоге.
> ls README.md
Удалите файл README.md из репозитория самостоятельно.
Переименование файлов в git репозитории
Как и в случае с удалением, переименовать файл в git репозитории можно двумя способами – с использованием и без использования средств операционной системы.
Первый способ. Создадим файл test_main_file.c и добавим его в репозиторий.
> touch test_main_file.c > git add test_main_file.c > git commit -m "add test_main_file.c" [master 6cf53ac] add test_main_file.c 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test_main_file.c
Содержимое репозитория после этого будет выглядеть так.
> git ls-tree master 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test_main_file.c
Переименуем его на test_main.c.
Сделаем это в рабочей директории.
> mv test_main_file.c test_main.c
Теперь отправим изменение в репозиторий.
> git add . > git commit -m "Rename test_main_file.c" [master 79528c4] Rename test_main_file.c 1 file changed, 0 insertions(+), 0 deletions(-) rename test_main_file.c => test_main.c (100%)
В репозитории и в рабочей директории будет находится только файл test_main.c.
> git ls-tree master 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test_main.c > ls test_main.c
Второй способ.
В рамках второго способа рассмотрим работу с командой git mv. Переименуем файл test_main.c в main.c. Текущее содержимое репозитория и рабочего каталога.
> git ls-tree master 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test_main.c > ls test_main.c
Переименуем файл test_main.c на main.c средствами git.
> git mv test_main.c main.c > git commit -m "Rename test_main.c file" [master c566f0e] Rename test_main.c file 1 file changed, 0 insertions(+), 0 deletions(-) rename test_main.c => main.c (100%)
Имя файла изменилось как в репозитории так и в рабочем каталоге.
> git ls-tree master 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 main.c > ls main.c
Отличный курс по git делают ребята из GeekBrains, найдите в разделе “Курсы” курс “Git. Быстрый старт”, он бесплатный!
<<<Часть 7. Поговорим о HEAD и tree-ish Часть 9. Как удалить коммит в git?>>>
Работа с Git репозиторием. Команды: создать ветку, удалить коммит,
Обновлено: 14.04.2019 г.
В данном разделе мы собрали решение типовых задач, которые могут вам при работе с git репозиторием. В своих проектах мы используем обычную сборку git и GitLab. Поэтому в данных примерах могут быть примеры описанные при работе с данными программами.
Генерация и настройка ключей git для деплоя
- Для того чтобы сгенерировать deploy key, нужно подключиться к серверу по ssh. Затем выполнить команду ssh-keygen.
- В консоли появится диалог, в котором нужно будет ввести название файла, где будет сохранен ключ. Этот шаг можно пропустить, тогда ключ будет сохранен в файл с именем по умолчанию (id_rsa).
- После этого будет предложено ввести кодовую фразу для дополнительной защиты, этот шаг можно пропустить (чтобы не вводить фразу каждый раз, когда идет обращение к гиту).
- После этого ключ будет сгенерирован, и будет создано 2 файла с приватным и публичным ключами.Теперь нужно лишь скопировать публичный ключ и добавить его в гит репозиторий. Выполняем команду cd ~/.ssh и переходим в директорию, где сохранен наш ключ. Для того чтобы вывести его в консоль, выполняем команду cat <имя файла> (по умолчанию id_rsa.pub). ОБратите внимание, что нужен именно файл с расширением .pub (публичный ключ). Копируем содержимое файла.
- Далее в GitLab можно настроить репозитория.
- А в разделе настроек выбрать пункт Deploy keys.
- Далее нажимаем “New Deploy Key” и попадаем в форму создания нового ключа. Вставляем ключ в поле Key, заполняем название (Title) ключа (в названии желательно указать имя пользователя и ip сервера, где был сгенерирован ключ).
Обновление проекта на git с сервера
Данная действие требуется, когда на сервере, где установлен проект, вносились правки напрямую (например, через sftp или ssh, а не через git).
Для обновления необходимо проделать следующие операции:
- Подключиться к серверу, на котором уже развернут проект, подключение производим через SSH.
- Убедиться, что мы находимся в нужной ветке, для этого вводим команду — “git branch”. Мы находимся в ветке “master”.
- Далее вводим команду — “git status”.
- Далее нужно убедиться в том, что есть изменения в файлах. Обычно Git помечает их красным цветом.
- Эти файлы необходимо добавить к индексируемым, следовательно вводим команду — “git add .” “Точка” говорит нам о том, что будут добавлены все файлы. Либо можно добавлять файлы через пробел “git add file1.php file2.php”.
- Снова проверяем статус репозитория “git status”, добавленные файлы должны быть быть отмечены зеленым цветом.
- Затем можно создать коммит — “git commit -m ‘your message here’”.
- Далее делаем “git pull origin master”, принимаем изменения из удаленного репозитория той ветки, в которой находимся.
- Далее отправляем наши изменения той ветки, в которой находимся — “git push origin master”.
- Проверяем статус локального репозитория — “git status”, в ответ получаем “On branch master. nothing to commit, working directory clean”.
Какие ветки создавать на новые проекты
Для работы над новым проектом по умолчанию git создаёт ветку master. Если у проекта будет 2 версии (тестовая и боевая), то вам перед началом разработки необходимо создать новую ветку — dev. Для этого нужно:
- Либо создать ветку с именем dev, локально выполнив команду “git checkout -b dev” находясь в ветке master;
- Либо создать новую верстку в репозитории посредством GitLab: Project — Branches — New Branch.
Как залить обновления на сервер с git
Если проект имеет только боевую версию (prod):
- Подключаемся по ssh (вводим логин, пароль, хост).
- Переходим в директорию с проектом cd (обычно cd var/www/site.ru — если не знаете, то уточните у Менеджера).
- Выполняем команду “git pull”.
Если проект имеет 2 версии: dev (тестовую версию) и prod (боевой проект)
Если у нас используется 2 версии проекта, то обновления заливаются в 2 ветки: dev и prod.
- Для выгрузки обновления подключаемся по ssh (вводим логин, пароль, хост).
- Переходим в директорию с тестовым или боевым проектом cd (обычно cd var/www/dev.site.ru или var/www/site.ru — если не знаете, то уточните у Менеджера).
- Далее проверяем, что мы находимся в dev ветке, для этого выполняем команду git branch, в результате получаем master или dev (если увидели не то, то выполняем команду для переключения в нужную ветку “git checkout <ветка>”).
- Если вы находитесь в нужной ветке, то выполняете “git pull”.
Как откатить коммит?
Если требуется отменить изменения в уже созданном коммите, допустим, вы что-то забыли дописать в коде, то нужно выполнить:
- Внимание! Данная операция не затронет внесённых изменений.
- Выполняем команду “git reset —soft HEAD^”.
- Отменяется последний коммит, далее мы вносим изменения в коде.
- Далее создаем новый коммит командой “git commit -m ‘add some code’ ”.
- И отправляем изменения в репозиторий командой “git push origin master”.
Если требуется откатить залитые правки до предыдущего коммита, то нужно выполнить:
- Осторожно! Эта команда безвозвратно удаляет несохраненные текущие изменения.
- Для начала нужно узнать хэш последнего коммита. Для этого выполняем команду “git show-ref —heads —hash master”.
- Далее вводим команду “git revert e882466”, где e882466 — первые 7 символов хэша текущего коммита.
- Далее нужно подтвердить откат коммита. Нужно ввести название коммита или оставить уже введенный автоматически текст Revert “add one more object” (это пример).
- Далее отправляем коммит в репозиторий командой “git push origin master” (если текущая ветка master).
Как перенести новый проект клиента в свой git?
В том случае, если проект редактировался напрямую через ftp или ssh, то требуется обновить версию проекта, размещенного на git. Для этого необходимо выполнить следующие шаги:
- Необходимо получить исходные файлы проекта, путем скачивания через FTP-клиент на свой компьютер.
- Необходимо получить базу данных проекта. Обычно выкачивается через через PhpMyAdmin, через SSH командой mysqldump или с помощью поддержки системного администратора (можно уточнить у Менеджера).
- Далее нужно сообщить Менеджеру, чтобы он создал новый репозиторий в GitLab для данного проекта.
- Далее клонируем пустой репозиторий к себе на локальный компьютер, например, в папку C:\Projects\foobar с помощью команды ‘git clone полный-путь-до-репозитория.git ’.
- Скачанный проект нужно поместить в папку с клонированным пустым репозиторием (который находится, например, в папке C:\Projects\foobar).
- Создать файл .gitignore и указать там необходимые файлы и директории, которые не должны попасть в git.
- Далее нужно отправить в гит файлы проекта, выполнив команду “git push origin master”.
- Далее нужно запросить у Менеджера доступный для это проекта домен (или поддомен) для разработки, а также доступы к SSH сервера, доступы для подключения к СУБД и выделенную базу данных для этого проекта, на котором будет вестись доработка проекта или обычное расположение.
- Необходимо зайти на сервер под полученными доступами SSH
- Начать развертывание проекта из git.
- Перейти в указанную Менеджером папку с поддоменом с помощью команды cd (обычно cd var/www/site.ru).
- Сгенерировать и настроить deploy keys (см. пункт 1).
- Выполнить команду ‘git clone полный-путь-до-репозитория.git ’.
- Заказать на сервер дамп базы данных с помощью команды scp с указанием размещения на сервере пути для дампа БД (она похожа на команду ssh).
- Развернуть дамп БД на сервере выполнить mysql -u USER -pPASSWORD DATABASE < /path/to/dump.sql.
- Если проект основан на фреймворке (Yii2, Symfony ¾, Laravel, Zend или другой), то необходимо подтянуть зависимости PHP пакетов (расширений).
- Нужно установить composer.phar в папку проекта, выполнив команды, указанные по этому адресу https://getcomposer.org/download/.
- Выполнить команду composer.phar update.
- Загрузить файлы и директории, которые ранее добавили в .gitignore.
- Проверить работоспособность проекта, пройдя по поддомену/домену.
Отправка проекта в Git, если будет выполнятся code review
Code review — процесс проверки кода на предмет технических не соответсвий и ошибок.
Для удобного просмотра изменений бновления нужно вгрузить в ветку master через Merge Request (не путать с консольной командой merge) в панели управления репозиторием GitLab.
Для этого выполните следующие действия:
- В разделе Merge Requests в панели управления репозиторием GitLab перейти в раздел “New Merge Request”.
- Далее в качестве Source branch выбрать ветку dev, а в качестве Target branch соответственно master ветку.
- После нажатия на кнопку Compage branches and continue отобразится следующая форма:
В качестве Title необходимо указать ID и наименование задачи из багтрекера, а также необходимо закрепить merge request за проверяющим порграммистом выбрав его в поле Assignee.
После того как проверяющий проверил реализованный код, то необходимо произвести git pull на сервере в продакшн версии проекта.
Шпаргалка по консольным командам Git
Общее
Git — система контроля версий (файлов). Что-то вроде возможности сохраняться в компьютерных играх (в Git эквивалент игрового сохранения — коммит). Важно: добавление файлов к «сохранению» двухступенчатое: сначала добавляем файл в индекс (git add
), потом «сохраняем» (git commit
).
Любой файл в директории существующего репозитория может находиться или не находиться под версионным контролем (отслеживаемые и неотслеживаемые).
Отслеживаемые файлы могут быть в 3-х состояниях: неизменённые, изменённые, проиндексированные (готовые к коммиту).
Концепция GIT
Ключ к пониманию концепции git — знание о «трех деревьях»:
- Рабочая директория — файловая система проекта (те файлы, с которыми вы работаете).
- Индекс — список отслеживаемых git-ом файлов и директорий, промежуточное хранилище изменений (редактирование, удаление отслеживаемых файлов).
- Директория
.git/
— все данные контроля версий этого проекта (вся история разработки: коммиты, ветки, теги и пр.).
Коммит — «сохранение» (хранит набор изменений, сделанный в рабочей директории с момента предыдущего коммита). Коммит неизменен, его нельзя отредактировать.
У всех коммитов (кроме самого первого) есть один или более родительских коммитов, поскольку коммиты хранят изменения от предыдущих состояний.
Простейший цикл работ
- Редактирование, добавление, удаление файлов (собственно, работа).
- Индексация/добавление файлов в индекс (указание для git какие изменения нужно будет закоммитить).
- Коммит (фиксация изменений).
- Возврат к шагу 1 или отход ко сну.
Указатели
HEAD
— указатель на текущий коммит или на текущую ветку (то есть, в любом случае, на коммит). Указывает на родителя коммита, который будет создан следующим.ORIG_HEAD
— указатель на коммит, с которого вы только что переместилиHEAD
(командойgit reset ...
, например).- Ветка (
master
,develop
etc.) — указатель на коммит. При добавлении коммита, указатель ветки перемещается с родительского коммита на новый. - Теги — простые указатели на коммиты. Не перемещаются.
Настройки
Перед началом работы нужно выполнить некоторые настройки:
git config --global user.name "Your Name" # указать имя, которым будут подписаны коммиты
git config --global user.email "[email protected]" # указать электропочту, которая будет в описании коммитера
Если вы в Windows:
git config --global core.autocrlf true # включить преобразование окончаний строк из CRLF в LF
Указание неотслеживаемых файлов3>
Файлы и директории, которые не нужно включать в репозиторий, указываются в файле .gitignore
. Обычно это устанавливаемые зависимости (node_modules/
, bower_components/
), готовая сборка build/
или dist/
и подобные, создаваемые при установке или запуске. Каждый файл или директория указываются с новой строки, возможно использование шаблонов.
Консоль
Как использовать консоль Bash в Windows, основные команды.
Длинный вывод в консоли: Vim
Вызов некоторых консольных команд приводит к необходимости очень длинного вывода в консоль (пример: вывод истории всех изменений в файле командой git log -p fileName.txt
). При этом прямо в консоли запускается редактор Vim. Он работает в нескольких режимах, из которых Вас заинтересуют режим вставки (редактирование текста) и нормальный (командный) режим. Чтобы попасть из Vim обратно в консоль, нужно в командном режиме ввести :q. Переход в командный режим из любого другого: Esc.
Если нужно что-то написать, нажмите i — это переход в режим вставки текста. Если нужно сохранить изменения, перейдите в командный режим и наберите :w.
Vim (некоторые команды)
# Нажатия кнопок ESC — переход в командный режим i — переход в режим редактирования текста ZQ (зажат Shift, поочередное нажатие) — выход без сохранения ZZ (зажат Shift, поочередное нажатие) — сохранить и выйти ```bash # Нажатия кнопок ESC — переход в командный режим i — переход в режим редактирования текста ZQ (зажат Shift, поочередное нажатие) — выход без сохранения ZZ (зажат Shift, поочередное нажатие) — сохранить и выйти # Ввод в командном режиме :q! — выйти без сохранения :wq — сохранить файл и выйти :w filename.txt — сохранить файл как filename.txt
Консольные команды
Создать новый репозиторий
git init # создать новый проект в текущей директории git init folder-name # создать новый проект в указанной директории
Клонирование репозитория
# клонировать удаленный репозиторий в одноименную директорию git clone https://github.com/cyberspacedk/Git-commands.git # клонировать удаленный репозиторий в директорию «FolderName» git clone https://github.com/cyberspacedk/Git-commands.git FolderName # клонировать репозиторий в текущую директорию git clone https://github.com:nicothin/web-design.git .
Просмотр изменений
git status # показать состояние репозитория (отслеживаемые, изменённые, новые файлы и пр.) git diff # сравнить рабочую директорию и индекс (неотслеживаемые файлы ИГНОРИРУЮТСЯ) git diff --color-words # сравнить рабочую директорию и индекс, показать отличия в словах (неотслеживаемые файлы ИГНОРИРУЮТСЯ) git diff index.html # сравнить файл из рабочей директории и индекс git diff HEAD # сравнить рабочую директорию и коммит, на который указывает HEAD (неотслеживаемые файлы ИГНОРИРУЮТСЯ) git diff --staged # сравнить индекс и коммит с HEAD git diff master feature # посмотреть что сделано в ветке feature по сравнению с веткой master git diff --name-only master feature # посмотреть что сделано в ветке feature по сравнению с веткой master, показать только имена файлов git diff master...feature # посмотреть что сделано в ветке feature с момента (коммита) расхождения с master
Добавление изменений в индекс
git add . # добавить в индекс все новые, изменённые, удалённые файлы из текущей директории и её поддиректорий git add text.txt # добавить в индекс указанный файл (был изменён, был удалён или это новый файл) git add -i # запустить интерактивную оболочку для добавления в индекс только выбранных файлов git add -p # показать новые/изменённые файлы по очереди с указанием их изменений и вопросом об отслеживании/индексировании
Удаление изменений из индекса
git reset # убрать из индекса все добавленные в него изменения (в рабочей директории все изменения сохранятся), антипод git add git reset readme.txt # убрать из индекса изменения указанного файла (в рабочей директории изменения сохранятся)
Отмена изменений
git checkout text.txt # ОПАСНО: отменить изменения в файле, вернуть состояние файла, имеющееся в индексе git reset --hard # ОПАСНО: отменить изменения; вернуть то, что в коммите, на который указывает HEAD (незакомиченные изменения удалены из индекса и из рабочей директории, неотслеживаемые файлы останутся на месте) git clean -df # удалить неотслеживаемые файлы и директории
Коммиты
git commit -m "Name of commit" # зафиксировать в коммите проиндексированные изменения (закоммитить), добавить сообщение git commit -a -m "Name of commit" # проиндексировать отслеживаемые файлы (ТОЛЬКО отслеживаемые, но НЕ новые файлы) и закоммитить, добавить сообщение
Отмена коммитов и перемещение по истории
Все коммиты, которые уже были отправлены в удалённый репозиторий, должны отменяться новыми коммитами (git revert
), дабы избежать проблем с историей разработки у других участников проекта.
git revert HEAD --no-edit # создать новый коммит, отменяющий изменения последнего коммита без запуска редактора сообщения git revert b9533bb --no-edit # то же, но отменяются изменения, внесённые коммитом с указанным хешем (b9533bb)
Все команды, приведённые ниже можно выполнять ТОЛЬКО если коммиты еще не были отправлены в удалённый репозиторий.
# ВНИМАНИЕ! Опасные команды, можно потерять незакоммиченные изменения git commit --amend -m "Название" # «перекоммитить» изменения последнего коммита, заменить его новым коммитом с другим сообщением (сдвинуть текущую ветку на один коммит назад, сохранив рабочую директорию и индекс «как есть», создать новый коммит с данными из «отменяемого» коммита, но новым сообщением) git reset --hard @~ # передвинуть HEAD (и ветку) на предыдущий коммит, рабочую директорию и индекс сделать такими, какими они были в момент предыдущего коммита git reset --hard 75e2d51 # передвинуть HEAD (и ветку) на коммит с указанным хешем, рабочую директорию и индекс сделать такими, какими они были в момент указанного коммита git reset --soft @~ # передвинуть HEAD (и ветку) на предыдущий коммит, но в рабочей директории и индексе оставить все изменения git reset --soft @~2 # то же, но передвинуть HEAD (и ветку) на 2 коммита назад git reset @~ # передвинуть HEAD (и ветку) на предыдущий коммит, рабочую директорию оставить как есть, индекс сделать таким, каким он был в момент предыдущего коммита (удобнее, чем git reset --soft @~, если индекс нужно задать заново) # Почти как git reset --hard, но безопаснее: не получится потерять изменения в рабочей директории git reset --keep @~ # передвинуть HEAD (и ветку) на предыдущий коммит, сбросить индекс, но в рабочей директории оставить изменения, если возможно (если файл с изменениями между коммитами менялся, будет выдана ошибка и переключение не произойдёт)
Временно переключиться на другой коммит
git checkout b9533bb # переключиться на коммит с указанным хешем (переместить HEAD на указанный коммит, рабочую директорию вернуть к состоянию, на момент этого коммита) git checkout master # переключиться на коммит, на который указывает master (переместить HEAD на коммит, на который указывает master, рабочую директорию вернуть к состоянию на момент этого коммита)
Переключиться на другой коммит и продолжить работу с него
Потребуется создание новой ветки, начинающейся с указанного коммита.
git checkout -b new-branch 5589877 # создать ветку new-branch, начинающуюся с коммита c хешем 5589877 (переместить HEAD на указанный коммит, рабочую директорию вернуть к состоянию, на момент этого коммита, создать указатель на этот коммит (ветку) с указанным именем)
Восстановление изменений
git checkout 5589877 index.html # восстановить в рабочей директории указанный файл на момент указанного коммита (и добавить это изменение в индекс) (git reset index.html для удаления из индекса, но сохранения изменений в файле)
Копирование коммита (перенос коммитов)
git cherry-pick 5589877 # скопировать на активную ветку изменения из указанного коммита, закоммитить эти изменения git cherry-pick master~2..master # скопировать на активную ветку изменения из master (2 последних коммита) git cherry-pick -n 5589877 # скопировать на активную ветку изменения из указанного коммита, но НЕ КОММИТИТЬ (подразумевается, что мы сами потом закоммитим) git cherry-pick master..feature # скопировать на активную ветку изменения из всех коммитов ветки feature с момента её расхождения с master (похоже на слияние веток, но это копирование изменений, а не слияние), закоммитить эти изменения; это может вызвать конфликт git cherry-pick --abort # прервать конфликтный перенос коммитов git cherry-pick --continue # продолжить конфликтный перенос коммитов (сработает только после решения конфликта)
Удаление файла
git rm text.txt # удалить отслеживаемый неизменённый файл и проиндексировать это изменение git rm -f text.txt # удалить отслеживаемый изменённый файл и проиндексировать это изменение git rm -r log/ # удалить всё содержимое отслеживаемой директории log/ и проиндексировать это изменение git rm ind* # удалить все отслеживаемые файлы с именем, начинающимся на «ind» в текущей директории и проиндексировать это изменение git rm --cached readme.txt # удалить из отслеживаемых индексированный файл (ФАЙЛ ОСТАНЕТСЯ НА МЕСТЕ) (часто используется для нечаянно добавленных в отслеживаемые файлов)
Перемещение/переименование файлов
Для git не существует переименования. Переименование воспринимается как удаление старого файла и создание нового. Факт переименования может быть определен только после индексации изменения.
git mv text.txt test_new.txt # переименовать файл «text.txt» в «test_new.txt» и проиндексировать это изменение git mv readme_new.md folder/ # переместить файл readme_new.md в директорию folder/ (должна существовать) и проиндексировать это изменение
История коммитов
Выход из длинного лога вывода: q
.
git log master # показать коммиты в указанной ветке git log -2 # показать последние 2 коммита в активной ветке git log -2 --stat # показать последние 2 коммита и статистику внесенных ими изменений git log -p -22 # показать последние 22 коммита и внесенную ими разницу на уровне строк git log --graph -10 # показать последние 10 коммитов с ASCII-представлением ветвления git log --since=2.weeks # показать коммиты за последние 2 недели git log --after '2018-06-30' # показать коммиты, сделанные после указанной даты git log index.html # показать историю изменений файла index.html (только коммиты) git log -5 index.html # показать историю изменений файла index.html, последние 5 коммитов (только коммиты) git log -p index.html # показать историю изменений файла index.html (коммиты и изменения) git log -G'myFunction' -p # показать все коммиты, в которых менялись строки с myFunction (в кавычках регулярное выражение) git log -L '//','//':index.html # показать изменения от указанного до указанного регулярных выражений в указанном файле git log --grep fix # показать коммиты, в описании которых есть буквосочетание fix (регистрозависимо, только коммиты текущей ветки) git log --grep fix -i # показать коммиты, в описании которых есть буквосочетание fix (регистроНЕзависимо, только коммиты текущей ветки) git log --grep 'fix(ing|me)' -P # показать коммиты, в описании которых есть совпадения для регулярного выражения (только коммиты текущей ветки) git log --pretty=format:"%h - %an, %ar : %s" -4 # показать последние 4 коммита с форматированием выводимых данных git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short # мой формат вывода, висящий на алиасе оболочки git log master..branch_99 # показать коммиты из ветки branch_99, которые не влиты в master git log branch_99..master # показать коммиты из ветки master, которые не влиты в branch_99 git log master...branch_99 --boundary -- graph # показать коммиты из указанных веток, начиная с их расхождения (коммит расхождения будет показан)
git show 60d6582 # показать изменения из коммита с указанным хешем git show HEAD~ # показать данные о предыдущем коммите в активной ветке git show @~ # аналогично предыдущему git show HEAD~3 # показать данные о коммите, который был 3 коммита назад git show my_branch~2 # показать данные о коммите, который был 2 коммита назад в указанной ветке git show @~:index.html # показать контент указанного файла на момент предыдущего (от HEAD) коммита git show :/"подвал" # показать самый новый коммит, в описании которого есть указанное слово (из любой ветки)
Кто написал строку
git blame README.md --date=short -L 5,8 # показать строки 5-8 указанного файла и коммиты, в которых строки были добавлены
История изменений указателей (веток, HEAD)
git reflog -20 # показать последние 20 изменений положения указателя HEAD
git reflog --format='%C(auto)%h %
Ветки
git branch # показать список веток git branch -v # показать список веток и последний коммит в каждой git branch new_branch # создать новую ветку с указанным именем на текущем коммите git branch new_branch 5589877 # создать новую ветку с указанным именем на указанном коммите git branch -f master 5589877 # переместить ветку master на указанный коммит git branch -f master master~2 # переместить ветку master на 2 коммита назад git checkout new_branch # перейти в указанную ветку git checkout -b new_branch # создать новую ветку с указанным именем и перейти в неё git checkout -B master 5589877 # переместить ветку с указанным именем на указанный коммит и перейти в неё git merge hotfix # влить в ветку, в которой находимся, данные из ветки hotfix git merge hotfix -m "Горячая правка" # влить в ветку, в которой находимся, данные из ветки hotfix (указано сообщение коммита слияния) git merge hotfix --log # влить в ветку, в которой находимся, данные из ветки hotfix, показать редактор описания коммита, добавить в него сообщения вливаемых коммитов git merge hotfix --no-ff # влить в ветку, в которой находимся, данные из ветки hotfix, запретить простой сдвиг указателя, изменения из hotfix «останутся» в ней, а в активной ветке появится только коммит слияния git branch -d hotfix # удалить ветку hotfix (используется, если её изменения уже влиты в главную ветку) git branch --merged # показать ветки, уже слитые с активной git branch --no-merged # показать ветки, не слитые с активной git branch -a # показать все имеющиеся ветки (в т.ч. на удаленных репозиториях) git branch -m old_branch_name new_branch_name # переименовать локально ветку old_branch_name в new_branch_name git branch -m new_branch_name # переименовать локально ТЕКУЩУЮ ветку в new_branch_name git push origin :old_branch_name new_branch_name # применить переименование в удаленном репозитории git branch --unset-upstream # завершить процесс переименования
Теги
git tag v1.0.0 # создать тег с указанным именем на коммите, на который указывает HEAD git tag -a -m 'В продакшен!' v1.0.1 master # создать тег с описанием на том коммите, на который смотрит ветка master git tag -d v1.0.0 # удалить тег с указанным именем(ами) git tag -n # показать все теги, и по 1 строке сообщения коммитов, на которые они указывают git tag -n -l 'v1.*' # показать все теги, которые начинаются с 'v1.*'
Временное сохранение изменений без коммита
git stash # временно сохранить незакоммиченные изменения и убрать их из рабочей директории git stash pop # вернуть сохраненные командой git stash изменения в рабочую директорию
Удалённые репозитории
Есть два распространённых способа привязать удалённый репозиторий к локальному: по HTTPS и по SSH. Если SSH у вас не настроен (или вы не знаете что это), привязывайте удалённый репозиторий по HTTPS (адрес привязываемого репозитория должен начинаться с https://).
git remote -v # показать список удалённых репозиториев, связанных с локальным git remote remove origin # убрать привязку удалённого репозитория с сокр. именем origin git remote add origin https://github.com:nicothin/test.git # добавить удалённый репозиторий (с сокр. именем origin) с указанным URL git remote rm origin # удалить привязку удалённого репозитория git remote show origin # получить данные об удалённом репозитории с сокращенным именем origin git fetch origin # скачать все ветки с удаленного репозитория (с сокр. именем origin), но не сливать со своими ветками git fetch origin master # то же, но скачивается только указанная ветка git checkout --track origin/github_branch # создать локальную ветку github_branch (данные взять из удалённого репозитория с сокр. именем origin, ветка github_branch) и переключиться на неё git push origin master # отправить в удалённый репозиторий (с сокр. именем origin) данные своей ветки master git pull origin # влить изменения с удалённого репозитория (все ветки) git pull origin master # влить изменения с удалённого репозитория (только указанная ветка)
Конфликт слияния
Предполагается ситуация: есть ветка master
и есть ветка feature
. В обеих ветках есть коммиты, сделанные после расхождения веток. В ветку master
пытаемся влить ветку feature
(git merge feature
), получаем конфликт, т.к. в обеих ветках есть изменения одной и той же строки в файле index.html
.
При возникновении конфликта, репозиторий находится в состоянии прерванного слияния. Нужно оставить в конфликтующих местах файлов только нужный код, проиндексировать изменения и закоммитить.
git merge feature # влить в активную ветку изменения из ветки feature git merge-base master feature # показать хеш последнего общего коммита для двух указанных веток git checkout --ours index.html # оставить в конфликтном файле (index.html) состояние ветки, В КОТОРУЮ мы вливаем (в примере — из ветки master) git checkout --theirs index.html # оставить в конфликтном файле (index.html) состояние ветки, ИЗ КОТОРОЙ мы вливаем (в примере — из ветки feature) git checkout --merge index.html # показать в конфликтном файле (index.html) сравнение содержимого сливаемых веток (для ручного редактирования) git checkout --conflict=diff3 --merge index.html # показать в конфликтном файле (index.html) сравнение содержимого сливаемых веток плюс то, что было в месте конфликта в коммите, на котором разошлись сливаемые ветки
git reset --hard # прекратить это прерванное слияние, вернуть рабочую директорию и индекс как было в момент коммита, на который указывает HEAD, а я пойду немного поплачу git reset --merge # прекратить это прерванное слияние, но оставить изменения, не закоммиченные до слияния (для случая, когда слияние делается не на чистом статусе) git reset --abort # то же, что и строкой выше
«Перенос» ветки
Можно «переместить» ответвление какой-либо ветки от основной на произвольный коммит. Это нужно для того, чтобы в «переносимой» ветке появились какие-либо изменения, внесённые в основной ветке (уже после ответвления переносимой).
Нельзя «переносить» ветку, если она уже отправлена на удалённый репозиторий.
git rebase master # перенести все коммиты (создать их копии) активной ветки так, будто активная ветка ответвилась от master на нынешней вершине master (часто вызывает конфликты) git rebase --onto master feature # перенести коммиты активной ветки на master, начиная с того места, в котором активная ветка отделилась от ветки feature git rebase --abort # прервать конфликтный rebase, вернуть рабочую директорию и индекс к состоянию до начала rebase git rebase --continue # продолжить конфликтный rebase (сработает только после разрешения конфликта и индексации такого разрешения)
Как отменить rebase
git reflog feature -2 # смотрим лог перемещений ветки, которой делали rebase (в этом примере — feature), видим последний коммит ПЕРЕД rebase, на него и нужно перенести указатель ветки git reset --hard feature@{1} # переместить указатель ветки feature на один коммит назад, обновить рабочую директорию и индекс
Разное
git archive -o ./project.zip HEAD # создать архив с файловой структурой проекта по указанному пути (состояние репозитория, соответствующее указателю HEAD)
Примеры
Собираем коллекцию простых и сложных примеров работы.
Начало работы
Создание нового репозитория, первый коммит, привязка удалённого репозитория с gthub.com, отправка изменений в удалённый репозиторий.
# указана последовательность действий: # создана директория проекта, мы в ней git init # создаём репозиторий в этой директории touch readme.md # создаем файл readme.md git add readme.md # добавляем файл в индекс git commit -m "Старт" # создаем коммит git remote add origin https://github.com:nicothin/test.git # добавляем предварительно созданный пустой удаленный репозиторий git push -u origin master # отправляем данные из локального репозитория в удаленный (в ветку master)
«Внесение изменений» в коммит
Только если коммит ещё не был отправлен в удалённые репозиторий.
# указана последовательность действий: subl inc/header.html # редактируем и сохраняем разметку «шапки» git add inc/header.html # индексируем измененный файл git commit -m "Убрал телефон из шапки" # делаем коммит # ВНИМАНИЕ: коммит пока не был отправлен в удалённый репозиторий # сознаём, что нужно было еще что-то сделать в этом коммите. subl inc/header.html # вносим изменения git add inc/header.html # индексируем измененный файл (можно git add .) git commit --amend -m "«Шапка»: выполнена задача №34" # заново делаем коммит
Работа с ветками
Есть master (публичная версия сайта), выполняем масштабную задачу (переверстать «шапку»), но по ходу работ возникает необходимость подправить критичный баг (неправильно указан контакт в «подвале»).
# указана последовательность действий: git checkout -b new-page-header # создадим новую ветку для задачи изменения «шапки» и перейдём в неё subl inc/header.html # редактируем разметку «шапки» git commit -a -m "Новая шапка: смена логотипа" # делаем коммит (работа еще не завершена) # тут выясняется, что есть баг с контактом в «подвале» git checkout master # возвращаемся к ветке master subl inc/footer.html # устраняем баг и сохраняем разметку «подвала» git commit -a -m "Исправление контакта в подвале" # делаем коммит git push # отправляем коммит с быстрым критическим изменением в master в удалённом репозитории git checkout new-page-header # переключаемся обратно в ветку new-page-header для продолжения работ над «шапкой» subl inc/header.html # редактируем и сохраняем разметку «шапки» git commit -a -m "Новая шапка: смена навигации" # делаем коммит (работа над «шапкой» завершена) git checkout master # переключаемся в ветку master git merge new-page-header # вливаем в master изменения из ветки new-page-header git branch -d new-page-header # удаляем ветку new_page_header
Работа с ветками, слияние и откат к состоянию до слияния
Была ветка fix
, в которой исправляли баг. Исправили, влили fix
в master
. но тут выяснилось, что это исправление ломает какую-то функциональность, Нужно откатить master
к состоянию без слияния (наличие бага менее критично, чем порча функциональности).
# находимся в ветке fix, баг уже «исправлен» git checkout master # переключаемся на master git merge fix # вливаем изменения из fix в master # видим проблему: часть функциональности сломалась git checkout fix # переключаемся на fix (пока мы в master, git не даст ее двигать) git branch -f master ORIG_HEAD # передвигаем ветку master на коммит, указанный в ORIG_HEAD (тот, на который указывала master до вливания fix)
Работа с ветками, конфликт слияния
Есть ветка master
(публичная версия сайта), в двух параллельных ветках (branch-1
и branch-2
) было отредактировано одно и то же место одного и того же файла, первую ветку (branch-1
) влили в master, попытка влить вторую вызывает конфликт.
# указана последовательность действий: git checkout master # переключаемся на ветку master git checkout -b branch-1 # создаём ветку branch-1, основанную на ветке master subl . # редактируем и сохраняем файлы git commit -a -m "Правка 1" # коммитим git checkout master # возвращаемся к ветке master git checkout -b branch-2 # создаём ветку branch-2, основанную на ветке master subl . # редактируем и сохраняем файлы git commit -a -m "Правка 2" # коммитим git checkout master # возвращаемся к ветке master git merge branch-1 # вливаем изменения из ветки branch-1 в текущую ветку (master), удача (автослияние) git merge branch-2 # вливаем изменения из ветки branch-2 в текущую ветку (master), КОНФЛИКТ автослияния # Automatic merge failed; fix conflicts and then commit the result. subl . # выбираем в конфликтных файлах те участки, которые нужно оставить, сохраняем git commit -a -m "Устранение конфликта" # коммитим результат устранения конфликта
Синхронизация репозитория-форка с мастер-репозиторием
Есть некий репозиторий на github.com, он него нами был сделан форк, добавлены какие-то изменения. Оригинальный (мастер-)репозиторий был как-то обновлён. Задача: стянуть с мастер-репозитория изменения (которые там внесены уже после того, как мы его форкнули).
# указана последовательность действий: git remote add upstream https://github.com:address.git # добавляем удаленный репозиторий: сокр. имя — upstream, URL мастер-репозитория git fetch upstream # стягиваем все ветки мастер-репозитория, но пока не сливаем со своими git checkout master # переключаемся на ветку master своего репозитория git merge upstream/master # вливаем стянутую ветку master удалённого репозитория upstream в свою ветку master
Ошибка в работе: закоммитили в мастер, но поняли, что нужно было коммитить в новую ветку
ВАЖНО: это сработает только если коммит еще не отправлен в удалённый репозиторий.
# указана последовательность действий: # сделали изменения, проиндексировали их, закоммитили в master, но ЕЩЁ НЕ ОТПРАВИЛИ (не делали git push) git checkout -b new-branch # создаём новую вертку из master git checkout master # переключаемся на master git reset HEAD~ --hard # сдвигаем указатель (ветку) master на 1 коммит назад git checkout new-branch # переключаемся обратно на новую ветку для продолжения работы
Нужно вернуть содержимое файла к состоянию, бывшему в каком-либо коммите (известен хеш коммита)
# указана последовательность действий: git checkout f26ed88 -- index.html # восстановить в рабочей директории состояние указанного файла на момент указанного коммита, добавить это изменение в индекс git commit -am "Navigation fixs" # сделать коммит
При любом действии с github (или другим удалённым сервисом) запрашивается логин и пароль
Речь именно о запросе пары логин + пароль, а не ключевой фразы. Происходит это потому, что git по умолчанию не сохранит пароль для доступа к репозиторию по HTTPS.
Простое решение: указать git кешировать ваш пароль.
.gitattributes
* text=auto
*.html diff=html
*.css diff=css
*.scss diff=css
Git Commit — SYSOUT
Эта статья – шпаргалка по команде commit и сопутствующим ей командам: add, rm, reset. Здесь рассказывается, как отправить файлы в локальный репозиторий (commit), как подготовить их к отправке (add), как отменить последний снимок (с помощью команды reset) и как удалить отдельные файлы из индекса или даже из снимка.
Команда git add
Команда commit отправляет файлы в локальный репозиторий.
Однако перед выполнением команды commit надо подготовить файлы – составить список тех из них, которые будут отправлены в репозиторий. Команда git add позволяет это сделать – добавляет файлы и папки в индекс (область staging area). В GIT есть понятие staged files – это файлы, которые попадут в следующий снимок при выполнении команды commit.
Дело в том, что в параметрах commit не указывается, какие файлы включать в снимок. Это делается заранее в команде add, а в команде commit пишется просто комментарий и в репозиторий отправляются все подготовленные файлы из индекса (staging area).
Можно добавлять в индекс как файлы, так и папки. Например, эта команда подготовит для будущего снимка папку <имя_папки1> и файл <имя_файла1>:
git add <имя_файла1> <имя_папки1>
При этом все остальные файлы, даже если они отслеживаются в репозитории (tracked files) и были отредактированы (edited files), в следующий снимок не попадут.
Есть удобные вариации команды add:
git add -A добавляет все файлы (вновь созданные, измененные и удаленные) git add . добавляет вновь созданные и измененные файлы, но не удаленные git add -u добавляет измененные и удаленные, но не вновь созданные
Нетрудно заметить, что команда:
git add -A
эквивалентна двум поочередно выполненным командам:
git add . git add -u
Удаление файлов из репозитория и с диска
Возможно, вам покажется странной фраза “добавляет удаленные файлы”. На самом деле это нормально: чтобы удалить файл из локального репозитория, недостаточно просто удалить его с диска. Надо после этого еще выполнить определенную команду git.
Если речь идет об отдельном файле, то команда:
git rm <имя_файла>
добавляет файл <имя_файла> в индекс как удаленный. При этом файл удаляется и с диска, если еще не был удален оттуда.
А команда:
git add -u
позволяет выполнить git rm для всех удаленных с диска файлов одновременно, то есть отправить их в индекс.
Удаление файлов только из репозитория
Бывает надо удалить файлы из репозитория, но не удалять с диска. Например, мы отправили в репозиторий логи, которым там не место.
А на диске они должны оставаться. Чтобы добавить этот лог в индекс как удаленный, но оставить его при этом на диске, выполним команду:
git rm --cached mylogfile.log
То же самое для папки делается так:
git rm --cached -r mydirectory
Что войдет в следующий снимок
Чтобы посмотреть, что же вы итоге подготовили для снимка, выполните команду:
$ git diff --name-only --cached
Благодаря параметру –name-only выведутся только названия файлов.
Команда git commit
А дальше просто – отправьте в локальный репозиторий все находящиеся в индексе файлы, комментарий обязателен:
$ git commit -m "комментарий"
Эта команда создает новый snapshot – снимок репозитория. К этому снимку можно будет вернуться в будущем. Ваши данные и комментарий будут также доступны при просмотре истории.
add и commit одной строкой
Бывает удобным отправлять файлы в репозиторий побыстрее, не выполняя по очереди add и commit. Можно выполнить эти команды и вместе:
git commit -a -m "комментарий"
Вышеприведенная команда – это то же самое, что выполненные по очереди команды:
git add . git commit -m "комментарий"
Кратко это звучит как “добавь в индекс все измененные файлы и сделай снимок с указанным комментарием”.
Обратите внимание, что удаленные файлы затронуты не будут.
Но можно создать в конфигурации любую команду из комбинации add и commit (правда, это редко используется):
git config --global alias.add-commit '!git add -A && git commit'
Мы создали команду add-commit. И с помощью нее можем выполнять действия:
git add-commit -m 'комментарий'
Как отменить последний commit
Чтобы отменить последний локальный commit, выполните команду:
git reset HEAD~1
HEAD~1 указывает на предыдущую ревизию, так что команда вернет репозиторий к предыдущему состоянию.
Как отменить git add
Чтобы удалить все файлы из staging area, выполните команду:
git reset
Чтобы удалить конкретный файл, выполните команду:
git reset <имя_файла>
Как удалить некоторые файлы из снимка
Специальной команды тут нет. Для этого надо отменить последнюю команду commit. Эта команда сдвигает указатель на предыдущее состояние:
git reset HEAD~1
В индексе останутся файлы. Надо удалить из индекса нежелательный файл:
git reset path/to/unwanted_file
Подробнее о команде reset читайте здесь.
И затем снова отправить файлы в репозиторий. Следующая команда позволит задействовать при отправке метаданные предыдущего коммита, в том числе предыдущий комментарий:
git commit -c ORIG_HEAD
ORIG_HEAD – ссылка на предыдущий снимок.
Как исправить комментарий снимка
Допустим, мы уже отправили изменения в локальный репозиторий, но надо исправить комментарий, так как в него закралась ошибка. Делаем так:
git commit --amend -m 'новый комментарий'
git amend | Atlassian Git Tutorial
Введение
В данном обучающем материале описаны различные способы перезаписи и изменения истории в Git. В Git используется несколько способов регистрации изменений. Мы обсудим плюсы и минусы различных способов и представим примеры работы с ними. В этом обучающем материале разбираются некоторые типовые причины перезаписи состояний кода после коммита и разъясняется, как избежать ошибок при выполнении таких операций.
Основная задача Git — гарантировать, что вы не потеряете внесенные изменения. В то же время эта система предназначена для обеспечения полного контроля над процессом разработки. В числе прочего вы сами определяете, как выглядит история вашего проекта, но такая свобода создает и вероятность потери коммитов. Git содержит команды для перезаписи истории, однако необходимо учитывать, что использование таких команд может привести к потере содержимого.
В Git существует несколько механизмов хранения истории и сохранения изменений. Вот эти механизмы: commit --amend
, git rebase
и git reflog
. Это мощные инструменты для настройки рабочего процесса. По окончании работы с этим обучающим материалом вы будете знать команды, позволяющие реструктурировать коммиты Git, и сможете избежать проблем, с которыми приходится сталкиваться при перезаписи истории.
Изменение последнего коммита: git commit --amend
Команда git commit --amend
— это удобный способ изменить последний коммит. Она позволяет объединить проиндексированные изменения с предыдущим коммитом без создания нового коммита. Ее также можно использовать для простого редактирования комментария к предыдущему коммиту без изменения состояния кода в нем. Но такое изменение приводит не только к редактированию последнего коммита, но и к его полной замене. Это означает, что измененный коммит станет новой сущностью с отдельной ссылкой. Для Git он будет выглядеть как новый коммит — на схеме ниже он отмечен звездочкой (*). Существует несколько распространенных сценариев использования команды git commit --amend
. В следующих разделах мы приведем такие примеры.
Изменение комментария к последнему коммиту Git
git commit --amend
Предположим, при выполнении коммита вы допустили ошибку в комментарии к нему. Выполнение этой команды в отсутствие проиндексированных файлов позволяет отредактировать комментарий к предыдущему коммиту без изменения состояния кода.
В процессе разработки регулярно случаются преждевременные коммиты. Очень просто забыть проиндексировать файл или использовать неправильный формат комментария к коммиту. Флаг --amend
позволяет без труда исправить эти небольшие ошибки.
git commit --amend -m "обновленный комментарий к коммиту"
Добавление опции -m
позволяет передать новый комментарий из командной строки, не открывая текстовый редактор.
Изменение файлов после коммита
В следующем примере показан распространенный сценарий разработки с использованием Git. Допустим, вы отредактировали несколько файлов и хотите сделать коммит за одну операцию. Но потом выясняется, что вы забыли добавить один из файлов в самом начале. Чтобы исправить эту ошибку, достаточно проиндексировать другой файл и выполнить коммит с флагом --amend
:
# Отредактируйте файлы hello.py и main.py git add hello.py git commit # Вспомните, что вы забыли добавить изменения из файла main.py git add main.py git commit --amend --no-edit
Флаг --no-edit
позволяет внести изменения в коммит без изменения комментария к нему. Итоговый коммит заменит неполный коммит. При этом все будет выглядеть так, словно изменения в файлах hello.py
и main.py
были сделаны за один коммит.
Не используйте amend для публичных коммитов
Измененные коммиты по сути представляют собой новые коммиты. При этом предыдущий коммит не остается в текущей ветке. Последствия этой операции аналогичны сбросу (reset) публичного состояния кода. Не изменяйте коммит, после которого уже начали работу другие разработчики. Эта ситуация только запутает разработчиков, и разрешить ее будет непросто.
Обзор
Если коротко, команда git commit --amend
позволяет добавить новые проиндексированные изменения в последний коммит. С помощью коммита --amend
можно добавлять изменения в индекс Git или удалять таковые из него. Если никаких изменений не проиндексировано, при использовании флага --amend
вам все равно будет предложено изменить комментарий к последнему коммиту. Будьте осторожны при использовании флага --amend
с коммитами, доступными другим членам команды. Изменение коммита, доступного другому пользователю, может привести к путанице и длительным устранениям конфликтов при слиянии.
Изменение старых или нескольких коммитов
Для изменения старых или нескольких коммитов используйте команду git rebase
, чтобы объединить несколько коммитов в новый базовый коммит. В стандартном режиме команда git rebase
позволяет в буквальном смысле перезаписать историю: она автоматически применяет коммиты в текущей рабочей ветке к указателю head переданной ветки. Поскольку новые коммиты заменяют старые, команду git rebase
запрещено применять к коммитам, которые стали доступны публично, иначе история проекта исчезнет.
В таких или подобных случаях, когда важно сохранить чистую историю проекта, добавление опции -i
к команде git rebase
позволяет выполнить интерактивную операцию rebase interactive
. Это дает возможность изменить отдельные коммиты в процессе вместо перемещения всех коммитов. Подробную информацию об интерактивной операции rebase и дополнительных командах перебазирования см. на странице git rebase.
Изменение файлов после коммита
Во время операции rebase команда редактирования (edit, илиe
) остановит процесс на указанном коммите и позволит вам внести дополнительные изменения с помощью команды git commit --amend
. Git прервет работу и выведет следующее сообщение:
Stopped at 5d025d1... formatting Теперь можно исправить коммит с помощью git commit --amend Внеся изменения, выполните команду git rebase --continue
Несколько комментариев
Каждый стандартный коммит в Git будет содержать комментарий, в котором поясняется, что было изменено в коммите. Комментарии дают наглядное представление об истории проекта. Во время операции rebase можно выполнить несколько команд для изменения комментариев к коммитам.
- Опция reword, или r, остановит операцию rebase и позволит переписать отдельный комментарий к коммиту.
- Опция squash, или s, приостановит операцию rebase для любых коммитов, отмеченных символом
s
, и вам будет предложено ввести один общий комментарий вместо нескольких отдельных. Подробнее об этом можно узнать в разделе о склеивании коммитов ниже. - Опция fixup, или f, позволяет объединить комментарии, как и squash. При этом, в отличие от squash, опция fixup не прерывает операцию rebase с открытием редактора для объединения комментариев к коммитам. В коммитах, отмеченных символом f, комментарии будут сброшены и заменены комментарием предыдущего коммита.
Склеивайте коммиты для поддержания чистой истории
Команда склеивания (s
) позволяет в полной мере понять смысл rebase. Склеивание дает возможность указать коммиты, которые нужно объединить в предыдущие коммиты. Таким образом создается «чистая история». Во время перебазирования Git будет исполнять указанную команду rebase для каждого коммита. В случае склеенных коммитов Git откроет выбранный текстовый редактор и предложит объединить комментарии к указанным коммитам. Этот процесс можно представить следующим образом:
Обратите внимание, что идентификаторы коммитов, измененных с помощью команды rebase, отличаются от идентификаторов каждого из начальных коммитов. Коммиты с маркером pick получат новый идентификатор, если предыдущие коммиты были переписаны.
Современные решения для хостинга Git (например, Bitbucket) предоставляют возможности «автосклеивания» при слиянии. Это позволяет автоматически выполнять rebase и склеивать коммиты ветки при использовании интерфейса решений для хостинга. Дополнительную информацию см. в разделе «Склеивание коммитов при слиянии ветки Git в Bitbucket».
Обзор
Команда git rebase позволяет изменять историю, а выполнение интерактивной операции rebase «подчищает» за вами следы. Теперь вы можете совершать и исправлять ошибки, оттачивая свою работу и сохраняя чистую, линейную историю проекта.
Страховка: git reflog
Журналы ссылок (reflog) — это механизм, который используется в Git для регистрации обновлений, применяемых к концам веток и другим ссылкам на коммиты. Reflog позволяет вернуться к коммитам, даже если на них нет ссылок из какой-либо ветки или метки. После перезаписи истории reflog содержит информацию о прежнем состоянии веток и позволяет при необходимости вернуться к этому состоянию. Каждый раз при обновлении конца ветки любым способом (переключение веток, загрузка новых изменений, перезапись истории или просто добавление новых коммитов) в reflog добавляется новая запись. В этом разделе мы рассмотрим команду git reflog
и некоторые стандартные примеры ее использования.
Использование
git reflog
Отображает reflog локального репозитория.
git reflog --relative-date
Отображает reflog с относительными датами (например, 2 недели назад).
Пример
Чтобы понять команду git reflog
, давайте разберем пример.
0a2e358 HEAD@{0}: reset: moving to HEAD~2 0254ea7 HEAD@{1}: checkout: moving from 2.2 to master c10f740 HEAD@{2}: checkout: moving from master to 2.2
В вышеприведенной команде reflog показан переход из ветки master в ветку 2.2 и обратно. Отсюда можно выполнить жесткий сброс к старому коммиту. Последнее действие указано в верхней строчке с пометкой HEAD@{0}
.
Если вы случайно переместитесь назад, reflog будет содержать главный коммит, указывающий на (0254ea7)
до случайного удаления вами 2 коммитов.
git reset --hard 0254ea7
При использовании команды git reset можно вернуть главную ветку к более раннему коммиту. Это страховка на случай непреднамеренного изменения истории.
Важно отметить, что reflog обеспечивает страховку только на тот случай, когда изменения попали в коммит в локальном репозитории и в нем отслеживаются только перемещения концов веток репозитория. Кроме того, записи reflog имеют определенный срок хранения. По умолчанию этот срок составляет 90 дней.
Дополнительную информацию см. на странице git reflog
.
Резюме
В этой статье мы обсудили несколько способов изменения истории и отмены изменений в Git. Мы вкратце рассмотрели процесс git rebase. Вот основные заключения.
- Существует несколько способов переписать историю в Git.
- Используйте команду
git commit --amend
для изменения своего последнего сообщения в журнале. - Используйте команду
git commit --amend
для внесения изменений в самый последний коммит. - Используйте команду
git rebase
для объединения коммитов и изменения истории ветки. - Команда
git rebase -i
обеспечивает более точный контроль над изменениями истории, чем обычный вариант git rebase.
Узнайте больше об описанных командах на соответствующих страницах:
Git happens! 6 типичных ошибок Git и как их исправить / Блог компании Флант / Хабр
Прим. перев.: На днях в блоге для инженеров любимого нами проекта GitLab появилась небольшая, но весьма полезная заметка с инструкциями, которые помогают сохранить время и нервы в случае различных проблем, случающихся по мере работы с Git. Вряд ли они будут новы для опытных пользователей, но обязательно найдутся и те, кому они пригодятся. А в конец этого материала мы добавили небольшой бонус от себя. Хорошей всем пятницы!
Все мы делаем ошибки, особенно при работе с такими сложными системами, как Git. Но помните: Git happens!
Если вы только начинаете путь с Git, обучитесь основам работы с ним в командной строке. А здесь я расскажу о том, как можно исправить шесть наиболее распространённых ошибок в Git.
1. Упс… Я ошибся в сообщении к последнему коммиту
После нескольких часов кодинга легко допустить ошибку в сообщении коммита. К счастью, это легко исправить:
git commit --amend
С этой командой откроется текстовый редактор и позволит внести изменения в сообщение к последнему коммиту. И никто не узнает, что вы написали «addded» с тремя «d».
2. Упс… Я забыл добавить файл к последнему коммиту
Другая популярная ошибка в Git — слишком поспешный коммит. Вы забыли добавить файл, забыли его сохранить или должны внести небольшое изменение, чтобы коммит стал осмысленным? Вашим другом снова будет --amend
.
Добавьте недостающий файл и выполните эту верную команду:
git add missed-file.txt
git commit --amend
Теперь вы можете либо откорректировать сообщение, либо просто сохранить его в прежнем виде (с добавленным файлом).
3. Упс… Я добавил файл, который не должен быть в этом репозитории
Но что, если у вас обратная ситуация? Что, если вы добавили файл, который не хотите коммитить? Обманчивый ENV-файл, директорию сборки или фото с котом, что было случайно сохранено в неправильном каталоге… Всё решаемо.
Если вы сделали только stage для файла и ещё не коммитнули его, всё делается через простой reset нужного файла (находящегося в stage):
git reset /assets/img/misty-and-pepper.jpg
Если же вы всё-таки коммитнули изменение, потребуется дополнительный предварительный шаг:
git reset --soft HEAD~1
git reset /assets/img/misty-and-pepper.jpg
rm /assets/img/misty-and-pepper.jpg
git commit
Коммит будет откачен, картинка удалена, а затем сделан новый коммит.
Прим. перев.: Как замечено в комментариях к оригинальной статье, эту проблему тоже можно решить с помощью уже упомянутого --amend
. По всей видимости, данным пунктом автор хотел показать, какие ещё есть способы изменения истории коммитов для исправления ошибки.
4. Упс… Я коммитнул изменения в master
Итак, вы работаете над новой фичей и поспешили, забыв создать новую ветку для неё. Вы уже коммитнули кучу файлов и все эти коммиты оказались в master’е. К счастью, GitLab может предотвращать push’ы прямо в master. Поэтому мы можем откатить все нужные изменения в новую ветку следующими тремя командами:
Примечание: Убедитесь, что сначала коммитнули или stash‘нули свои изменения — иначе все они будут утеряны!
git branch future-brunch
git reset HEAD~ --hard
git checkout future-brunch
Будет создана новая ветка, в master’е — произведён откат до состояния, в котором он был до ваших изменений, а затем сделан checkout новой ветки со всеми вашими изменениями.
5. Упс… Я сделал ошибку в названии ветки
Самые внимательные могли заметить в предыдущем примере ошибку в названии ветки. Уже почти 15:00, а я всё ещё не обедал, поэтому мой голод назвал новую ветку (branch) как future-brunch. Вкуснотища!
Переименуем эту ветку аналогичным способом, что используется при переименовании файла с помощью команды mv, то есть поместив её в новое место с правильным названием:
git branch -m future-brunch feature-branch
Если вы уже push’нули эту ветку, понадобится пара дополнительных шагов. Мы удалим старую ветку из remote и push’нем новую:
git push origin --delete future-brunch
git push origin feature-branch
Прим. перев.: Удалить ветку из remote ещё можно с помощью:
git push origin :future-brunch
6. Oops… I did it again!
Последняя команда на тот случай, когда всё пошло не так. Когда вы накопировали и навставляли кучу решений со Stack Overflow, после чего в репозитории всё стало ещё хуже, чем было в начале. Все мы однажды сталкивались с подобным…
git reflog
показывает список всех выполненных вами операций. Затем он позволяет использовать магические возможности Git’а по путешествию во времени, т.е. вернуться к любому моменту из прошлого. Должен отметить, что это ваша последняя надежда — не стоит прибегать к ней в простых случаях. Итак, чтобы получить список, выполните:
git reflog
Каждый наш шаг находится под чутким наблюдением Git’а. Запуск команды на проекте выше выдал следующее:
3ff8691 (HEAD -> feature-branch) HEAD@{0}: Branch: renamed refs/heads/future-brunch to refs/heads/feature-branch
3ff8691 (HEAD -> feature-branch) HEAD@{2}: checkout: moving from master to future-brunch
2b7e508 (master) HEAD@{3}: reset: moving to HEAD~
3ff8691 (HEAD -> feature-branch) HEAD@{4}: commit: Adds the client logo
2b7e508 (master) HEAD@{5}: reset: moving to HEAD~1
37a632d HEAD@{6}: commit: Adds the client logo to the project
2b7e508 (master) HEAD@{7}: reset: moving to HEAD
2b7e508 (master) HEAD@{8}: commit (amend): Added contributing info to the site
dfa27a2 HEAD@{9}: reset: moving to HEAD
dfa27a2 HEAD@{10}: commit (amend): Added contributing info to the site
700d0b5 HEAD@{11}: commit: Addded contributing info to the site
efba795 HEAD@{12}: commit (initial): Initial commit
Обратите внимание на самый левый столбец — это индекс. Если вы хотите вернуться к любому моменту в истории, выполните следующую команду, заменив {index}
на соответствующее значение (например, dfa27a2
):
git reset HEAD@{index}
Итак, теперь у вас есть шесть способов выбраться из самых частых Gitfalls (игра слов: pitfall переводится как «ловушка, ошибка» — прим. перев.).
Бонус от переводчика
Во-первых, ценное замечание ко всему написанному выше (кроме пункта 5). Нужно учитывать, что эти действия меняют историю коммитов, поэтому их следует проводить, только если изменения не были отправлены в remote (push’нуты). В противном случае старый плохой коммит уже будет на remote-ветке и придётся либо выполнять git pull
(который сделает merge, и тогда попытка «почистить» историю приведёт к худшим последствиям), либо git push --force
, что чревато потерей данных при работе с веткой нескольких человек…
Теперь — небольшие полезные дополнения из нашего опыта:
- Если вы (случайно или нет) сменили ветку и вам нужно вернуться на предыдущую, самый быстрый способ — использовать
git checkout -
. - Если вы случайно добавили к коммиту файл, который не должен быть туда добавлен, но ещё не сделали коммит — используйте
git reset HEAD path/to/file
. Похожая ситуация описана в пункте 3, но в действительности она шире, т.к. относится к любым ненужным изменениям в коммите (не только к случаю лишнего файла). - Хорошей практикой, чтобы не закоммитить лишнего, является использование параметра
-p
при добавлении файла к коммиту (git add -p
). Это позволяет сделать review каждого изменения, которое уйдёт в коммит. Но стоит помнить, что он не добавляет к коммиту untracked-файлы — их нужно добавлять без этого параметра. - Ряд хороших рекомендаций (в том числе и более сложных), можно найти в статье 2014 года «Git Tutorial: 10 Common Git Problems and How to Fix Them». В частности, обратите внимание на использование
git revert
иgit rebase -i
.
P.S. от переводчика
Читайте также в нашем блоге:
Удалить файлы из Git commit
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
.
github — полностью удалить файл из всего репозитория git
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
.
Как полностью удалить файл из репозитория Git
Введение
Вы уже передали закрытый ключ SSH, файл паролей или файл конфигурации с конфиденциальными данными в свой репозиторий раньше? Если вы этого не сделали, я бы порекомендовал сначала попробовать это, прежде чем вы продолжите читать этот блог.
Для всех нас: НЕ ПАНИКА! Сделайте глубокий вдох, встаньте из-за стола, пройдитесь несколько минут. Готов? Ладно, приступим!
Цель состоит в том, чтобы полностью стереть файл из репозитория Git, чтобы скрыть все следы вашей ужасной ошибки.Вы хотите быть человеком, который передал ключи AWS в общедоступный репозиторий GitHub, только чтобы через 24 часа узнать, что на майнинг биткойнов было потрачено ~ 2000 долларов США?
Несколько методов
Просто git rm passwords.txt
этого не сделает, так как файл будет присутствовать во всех предыдущих коммитах. В зависимости от того, где находится файл, вы можете использовать несколько методов. Здесь представлен обзор каждого сценария в порядке возрастания сложности.
Примечания:
Все эти методы предполагают, что вы знакомы с консольными командами.
Они написаны для Linux, но должны работать в OS X и даже в Windows, если вы используете Git Bash.
Если вы уже внесли изменения, все может усложниться.
Если вы разработчик-одиночка, дерзайте. Но если вы работаете в команде, сначала обсудите это с ними.
Если ваш код (с ненужным файлом) уже открыт (GitHub, BitBucket ,…) тогда вам может не повезти. Но продолжайте читать до конца.
Сценарий 1: файл находится в последней фиксации, а вы еще не отправили
1. Вы хотите сохранить файл локально
Измените последнюю фиксацию, чтобы удалить файл из репозитория, и добавьте его в .gitignore
, чтобы предотвратить его повторное добавление случайно.
git rm --cached $ FILE
эхо $ ФАЙЛ >> .gitignore
git добавить .gitignore
git commit --amend --no-edit
git reflog expire --expire = now --all && git gc --prune = now --aggressive
Команды git reflog expire
и git gc
вызывают сборку мусора, чтобы файл не зависал где-нибудь в вашем репозитории.
2. Вы не хотите хранить файл локально
Просто измените последний коммит.
git rm $ ФАЙЛ
git commit --amend --no-edit
git reflog expire --expire = now --all && git gc --prune = now --aggressive
Сценарий 2: файл находится дальше в истории, и вы еще не нажали
Решение 1: BFG Repo-Cleaner
Загрузите ‘BFG Repo-Cleaner’ здесь. Этот инструмент утверждает, что работает в 10-720 раз быстрее, чем любой другой метод, но вы не можете указать подкаталог, он удалит все файлы с тем же именем в любом каталоге.
Обычно BFG Repo-Cleaner защищает ваш последний коммит, но если вы знаете, что делаете (и знаете, верно?), Вы даете ему опцию --no-blob-protection
, что вроде как сказать , делай что хочу и не защищай меня от ошибок.
java -jar bfg.jar --delete-files $ FILE --no-blob-protection.
rm $ FILE
git reflog expire --expire = now --all && git gc --prune = now --aggressive
Решение 2. Интерактивная переустановка
Интерактивная перестановка позволяет вернуться в историю и повторить коммиты, как если бы они изначально были правильными.Похоже на обман? Может быть. Но вы хотите избавиться от этого файла, и у вас есть возможность сделать это.
У этой команды есть подоболочка внутри $ (...)
: она находит первую фиксацию, в которую был добавлен файл, даже с учетом переименований файла. Затем команда за пределами $ (...)
запускает интерактивную перебазировку в родительском ( ~
) этого коммита.
git rebase --interactive \
$ (git log --follow --find-renames = 40% --diff-filter = A --format =% H - $ FILE) ~
Отредактируйте файл git-rebase-todo
: измените первую команду с выбора на редактирование.
edit 7b0a4be987 Добавить новую таблицу тестов ширины
pick 38737174a7 Избегайте использования метода FontProgram # getBaseName, когда он не подходит, обновите документацию
pick 66f95dd41b Обобщить чтение байтов для преобразования формата woff
# Rebase d1613dff58..66f95dd41b на d1613dff58 (3 команды)
#
# Команды:
# p, pick = использовать фиксацию
# r, reword = использовать фиксацию, но отредактировать сообщение фиксации
# e, edit = использовать фиксацию, но не вносить поправки
# s, squash = использовать фиксацию, но сливается с предыдущей фиксацией
# f, fixup = как "squash", но удалить сообщение журнала этой фиксации
# x, exec = run команда (остальная часть строки) с использованием оболочки
# d, drop = удалить фиксацию
#
# Эти строки можно переупорядочить; они выполняются сверху вниз.#
# Если вы удалите здесь строчку, ЧТО COMMIT БУДЕТ УТЕРЯНЫ.
#
# Однако, если вы удалите все, перебазирование будет прервано.
#
# Обратите внимание, что пустые коммиты закомментированы
Затем сохраните и закройте редактор. Перебазирование откатит коммиты к фиксации, которая добавила нежелательный файл.
git rm $ ФАЙЛ
эхо $ ФАЙЛ >> .gitignore
git добавить .gitignore
git commit --amend --no-edit
git rebase - продолжить
git reflog expire --expire = now --all && git gc --prune = now --aggressive
Решение 3. Git filter-branch
Это запускает сценарий, указанный в --tree-filter
(f.пример: удалить определенный файл) при каждой фиксации. Это действительно МЕДЛЕННО! Это потому, что он должен проверять каждую фиксацию, запускать сценарий, выполнять фиксацию и переходить к следующей фиксации. Используйте это, когда есть теги или коммиты слияния между ошибочной фиксацией и HEAD, или когда нарушающий файл существует в нескольких ветвях. Другими словами, используйте в крайнем случае!
В этом скрипте я использую тот же трюк, чтобы найти первую фиксацию, которая добавляет ненужный файл, а затем я запускаю фильтр только на родительском этого коммита, вплоть до HEAD
текущей ветки. git filer-branch
всегда делает резервную копию и ставит перед исходной веткой префикс original
. Команда git for-each-ref
очищает эти резервные ветки, потому что мы действительно хотим избавиться от этого надоедливого файла. --tag-name-filter cat
будет следить за тем, чтобы любые теги перемещались вместе с их коммитами.
git фильтр-ветка -f \
--prune-empty \
--tag-name-filter cat \
--tree-filter 'rm -f $ FILE' \
$ (git log --follow --find-renames = 40% --diff-filter = A --format =% H - $ FILE) ~..ГОЛОВА
git for-each-ref --format = "% (refname)" refs / original / | xargs -n 1 git update-ref -d
git reflog expire --expire = now --all && git gc --prune = now --aggressive
Если вы хотите сделать это для всего репозитория (не стоит!):
git фильтр-ветка -f \
--prune-empty \
--tag-name-filter cat \
--tree-filter 'rm -f $ FILE' \
-- --все
git for-each-ref --format = "% (refname)" refs / original / | xargs -n 1 git update-ref -d
git reflog expire --expire = now --all && git gc --prune = now --aggressive
Сценарий 3: вы уже отправили
Я не могу повторить это достаточно: сначала проконсультируйтесь с остальной частью вашей команды !!! Если вы этого не сделаете, вы сделаете их жизнь несчастной.
Во-вторых, сделайте резервную копию репозитория, прежде чем делать что-либо еще.
Затем: СОЗДАТЬ РЕЗЕРВНУЮ КОПИЮ !!!
Не знаю, упоминал ли я об этом уже, но действительно ли вы уверены, что сделали резервную копию?
Используйте один из описанных выше методов для удаления файла.
Принудительно нажмите, но знайте, что делаете, и помните о последствиях, потому что нет возможности вернуться, если у вас нет резервной копии.
--force-with-lease
должно быть здесь по умолчанию, потому что сначала проверяется, что вы не перезаписываете работу других людей. См. Также блог Atlassian для отличного объяснения.git push --force-with-lease origin $ BRANCH
Сценарий 4: коммиты уже находятся на GitHub
В этом случае существует риск того, что кто-то все еще может получить доступ к нежелательному файлу даже после принудительного нажатия.
Это можно сделать двумя способами:
, если они сделали форк или клон репозитория: принудительное нажатие обновит только наш репозиторий, оно не обновит форки / клоны.
, если они знают точный хэш коммита, добавившего файл (возможно, они его записали или веб-страница все еще находится в кеше браузера), по URL-адресу:
https://github.com/$USER/ $ REPO / совершить / $ COMMIT
GitHub может собирать кэшированные представления мусора через некоторое время, но на это нельзя полагаться.
Лучшее, что можно сделать, — это связаться со службой поддержки GitHub и сообщить им репозиторий и ошибочную фиксацию, после чего они вручную удалят кешированные представления.
В следующем блоге я расскажу о некоторых передовых методах, используемых в iText Software для обработки конфиденциальных файлов, необходимых в наших проектах.
.
Как мне удалить большой файл из моей истории коммитов?
Если вы зафиксировали в своем репозитории большой файл, который занимает большой объем дискового пространства, простое удаление его в фиксации на самом деле не поможет.
Это потому, что Git не удаляет файл полностью, когда вы удаляете его из рабочего каталога. Он будет сохранен в истории Git, если вы захотите его восстановить.
Git’s filter-branch
на помощь
Допустим, в предыдущем коммите вы случайно добавили 15-мегабайтную фотографию своего генерального директора по имени ceo.jpg
. Чтобы полностью удалить файл из репозитория, вам необходимо выполнить следующую команду в каталоге вашего проекта:
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch путь / к / ceo.jpg' \
--prune-empty --tag-name-filter cat - --all
Если файл был успешно удален, вы должны увидеть следующий результат:
Rewrite ee94db7633e1bf370512d95e5ab57b851ad6c8cf (5/5)
Ссылка refs / Heads / master была переписана
Обновите .gitignore
файл
На этом этапе рекомендуется обновить файл .gitignore
, чтобы предотвратить случайное повторное принятие этого файла в будущем.
Примечание: Мы написали руководство для начинающих по файлам .gitignore
.
Принудительная отправка на ваши пульты
Если вы отправили большой файл на удаленный хост (например, GitHub), вам нужно принудительно отправить изменения, чтобы обновить все перезаписанные коммиты.
Форсированный толчок, особенно при работе с другими разработчиками, может быть опасным.Итак, если в вашей команде есть опытные пользователи Git, проконсультируйтесь с ними, прежде чем выполнять этот шаг, или ознакомьтесь с последствиями принудительного нажатия.
Когда будете готовы, запустите эту команду:
git push origin --force --all
Примечание: Пространство не обязательно будет освобождено на хосте немедленно. Вам нужно будет дождаться запуска сборки мусора, прежде чем размер будет пересчитан.
.