Небольшая памятка по командам Git, приемы работы с локальным репозиторием.
1. Основные команды (выполненные в текущем каталоге корневой папки проекта):
Команда
Функция
git init
Создание репозитория в текущем каталоге.
git config user.name "имя"
Ввод имени пользователя репозитория(1).
git config user.email "box@domain.ru"
Ввод email пользователя репозитория(1).
git add -n *
Проверка, какие файлы будут добавлены в репозиторий.
git add readme.txt
Добавить в репозиторий файл readme.txt(2).
git add util/**/*.cpp
Добавить все файлы *.cpp, которые находятся в папке util и её подкаталогах.
git add *.c *.h *.s *.asm
Добавить в репозиторий все файлы(2) с расширениями *.c, *.h, *.s, *.asm.
git add --all
Добавит изменения всех отслеживаемых и не отслеживаемых в базе файлов. Опция -A аналогична опции --all, см. далее врезку "Q020. Как удалить отслеживаемые файлы из репозитория".
git commit -m "190311 first commit"
Выполнить коммит репозитория. Чтобы исправить текущую фиксацию, используйте команду git commit --amend.
git commit -am "текст комментария"
Добавление опции -a автоматически отразит в базе репозитория все отслеживаемые, модифицированные файлы перед применением фиксации. См. далее врезку "Q020. Как удалить отслеживаемые файлы из репозитория".
git status
Показать состояние репозитория - какие файлы были добавлены или изменены.
git status --untracked-files=no
Показать состояние репозитория без отображения файлов, которые еще не добавлены в репозиторий.
git rm --cached имяфайла
Убирает из индекса репозитория указанный файл (он больше не отслеживается). В рабочем каталоге этот файл останется. Команду удобно использовать, если вы поторопились добавить в индекс файл командой add, и хотите сделать дополнительные изменения в этом файле.
git log
Просмотр истории изменений репозитория (история фиксаций commit).
git log --reverse
По умолчанию git log показывает историю фиксаций в обратном порядке: сначала в списке самые свежие фиксации. Опция --reverse выводит лог фиксаций так, что сначала самые старые фиксации.
git log --reflog
Просмотр истории ВСЕХ фиксаций. Эта команда полезна, когда был произведен откат на более старую фиксацию (простая команда git log более свежие фиксации не покажет). См. также git reflog.
git reflog
Просмотр истории всех фиксаций в сокращенном виде. В некоторых случаях эта команда более удобна, чем git log --reflog. См. также врезку "Отличия git log --reflog и git reflog".
git pull
Взять изменения из remote-репозитория в локальный репозиторий.
git push
Выгрузить изменения в локальном репозитории в remote-репозиторий.
git push -uf
Принудительная выгрузка локальных изменений на сервер. Полезно использовать после команды git commit --amend.
git clone address [newname]
Сделать локальную копию репозитория(3).
git checkout -b имяветки
Создание новой ветви имяветки в репозитории, и переключение на работу в ней. Основная ветвь носит имя master, содержимое ветви master будет сохраняться неизменной.
git checkout master
Возврат в основную ветвь репозитория.
git checkout -- файл
Откат текущих изменений файла. Файл вернется к состоянию, которое было сохранено в последнем commit. Внимание: все изменения в файле, если они были, будут безвозвратно потеряны!
git stash
Позволяет временно заархивировать (припрятать [7]) измененные, но не прошедшие commit файлы, когда их требует перезаписать команда git pull.
git commit -e
Откроет текстовый редактор для ввода комментария фиксации. Этот вариант создания фиксации позволяет нативно вводить многострочный комментарий [11].
По умолчанию в качестве редатора запускается Vim, для завершения ввода текста и вывода нажмите Esc, затем введите :wq Enter. См. также Q023.
git diff ...
Сравнение фиксаций или ветвей проекта [12].
git reset --hard
Откат изменений всех файлов к последней фиксации. Внимание: это опасная команда в том плане, что все не зафиксированные изменения в файлах будут потеряны, и проект вернется к последнему состоянию, который был сохранен последним commit.
Примечания:
(1) Просмотреть все настройки можно командой git config -l или git config --list. (2) Если добавляемые файлы уже присутствуют в репозитории, то будут отображены изменения в этих файлах. (3) Команда git clone автоматически создаст папку для репозитория. Если не указан параметр newname, то имя этой папки будет назначено автоматически из имени репозитория, иначе репозиторий будет создан в папке с именем newname.
2. Подробная помощь по команде (откроется окно браузера со справкой):
git help команда
3. Краткая подсказка по команде:
git команда -h
4. Файл .gitignore позволяет создать список файлов, которые не нужно отслеживать. В этом файле можно делать комментарии, комментарием считается строка, которая начинается на символ #. В каждой строке указывается имя файла, который игнорируется, в именах можно использовать символы группирования * и ?. Чтобы исключить папку и файлы в ней, нужно добавить имя папки со слешем в конце, например: Debug/. Примеры файлов .gitignore см. в [4].
5. Можно создавать алиасы (синонимы) команд для быстрого доступа к ним. Вот так например, можно создать синоним git st для команды git status:
git config --global alias.st "status -s"
После этого команды git st и git status будут выполняться одинаково.
Установка выполняется по шагам с помощью обычного мастера. Однако не некоторых шагах не очевидно, какие опции выбирать.
Начальные 4 шага вопросов не вызывают. Нужно согласиться с условиями лицензии, выбрать папку для установки, поставить галочки устанавливаемых компонентов, выбрать место размещения для ярлыков запуска. Можно оставить все по умолчанию:
На этом шаге лучше всего выбрать редактор, которым Вы привыкли пользоваться. Мне нравится Notepad2:
На этом шаге предлагают настроить рабочее окружения для запуска Git. Первый вариант никак не модифицирует переменные окружения, подразумевается запуск Git под управлением командной строки MinGW bash. Второй и третий вариант прописывает некоторые переменные окружения (пути запуска), чтобы можно было запускать Git как из стандартного интерпретатора команд Windows, так и из MinGW bash. Я выбрал второй вариант, который задан по умолчанию:
Здесь выбирается библиотека, с помощью которой обслуживаются защищенные соединения. Оставил этот вариант по умолчанию:
Здесь выбрал вариант, который при операциях Git не модифицирует окончания строк текстовых файлов:
Здесь лучше оставить выбор по умолчанию. Вариант настройки MinTTY обеспечивает удобную цветовую подсветку выводимого текста в консоли:
Как работать с Git по шагам, начиная с создания репозитория. Предполагается, что Git уже установлен.
1. Зайдите в рабочий каталог проекта, запустите сессию bash. Можно конечно пользоваться и стандартной командной строкой Windows, но MINGW64 Bash удобнее, потому что он предоставляет цветовую подсветку сообщений, и корректно поддерживает Unicode, что позволяет пользоваться русскими буквами в командах Git.
2. Необходимо создать репозиторий и указать для него имя пользователя и email. Для создания репозитория выполните команду:
git init
После этого выполните следующие команды (вместо Your Name и anyemail@domain.ru укажите любое имя и адрес электронной почты):
3. Выполните команду git add -n *, которая выведет список файлов, которые могут быть потенциально добавлены в репозиторий. Скорее всего, в этом списке будут некоторые файлы, изменение которых отслеживать не нужно (объектные и двоичные файлы, картинки, логи и т. п.). Если такие файлы есть, то перейдите к шагу 4, а если нужно добавить все файлы из выведенного списка, то перейдите к шагу 6.
Если проект большой, и много его файлов находится в отдельных папках, то команду проверки git add -n можно запускать на файлы только одной папки. Например, вот проверка, какие файлы будут добавляться в репозиторий из папки lib проекта:
git add -n lib
4. Создайте в текстовом редакторе файл .gitignore, после этого начните добавлять в него записи для тех файлов, которые нужно игнорировать (Git не будет их отслеживать). Начните с папок, которые находятся в каталоге проекта, папку .git обрабатывать не нужно, это служебная папка.
Внимание: чтобы можно было в файле .gitignore использовать имена файлов с русскими буквами, файл .gitignore должен быть в кодировке UTF-8.
Предположим, что есть папка bin в каталоге проекта, и в ней находятся файлы с расширениями dlb, ldr, bin, log, которые не надо добавлять в репозиторий. Тогда в файл .gitignore добавьте следующие строки:
# Что игнорировать в папке bin:
bin/*.dlb
bin/*.ldr
bin/*.bin
bin/*.log
Если в папке много подкаталогов, и Вы хотите обработать их сразу все, то можно воспользоваться группировкой /**/:
doc/**/*.bmp
Обратите внимание, что первая строка начинается на #, это просто комментарий, добавленный для удобства. Сохраните файл .gitignore и снова выполните команду git add -n *, Вы увидите, что файлы из составленного списка игнорируются.
Каждую отдельную папку можно проверять командой git add -n имяпапки/.
5. После того, как создали список игнорируемых файлов для папки, добавьте её в репозиторий на отслеживание, для этого выполните команду git add без опции -n. Например, так добавляется папка lib:
git add lib/
Аналогичные шаги 4 и 5 проделайте со всеми папками и файлами проекта.
6. Теперь осталось сделать коммит.
git commit -m "190312 первый коммит"
Здесь опция -m задает обязательный комментарий для коммита. В комментарии я люблю указывать 6 цифрами дату коммита (YYMMDD). Имейте в виду, что русские буквы в комментарии можно указывать только в командной строке bash (он устанавливается вместе с Git).
7. Чтобы сделать локальную копию репозитория в текущем каталоге на диске, используйте команду git clone. Пример клонирования репозитория BluetoothBLEClient [8] через web-ссылку:
[git reflog]
NAME
git-reflog - Управление информацией reflog
SYNOPSIS
git reflog < subcommand> < options>
DESCRIPTION
Эта команда принимает различные субкоманды (subcommand), а также различные опции (options), зависящие от
subcommand:
git reflog [show] [log-options] [< ref>]
git reflog expire [--expire=< time>] [--expire-unreachable=< time>]
[--rewrite] [--updateref] [--stale-fix]
[--dry-run | -n] [--verbose] [--all [--single-worktree] | < refs>...]
git reflog delete [--rewrite] [--updateref]
[--dry-run | -n] [--verbose] ref@{specifier}...
git reflog exists < ref>
Ссылка на лог (reference logs, или "reflogs") записывается, когда в локальном репозитории обновляются подсказки
по ветвям (tips of branches) и другие ссылки. Reflogs полезны в различных командах Git, чтобы можно было
указать старое значение ссылки. Например, HEAD@{2} означает "где имя HEAD использовалось за 2 перемещения
до этого", а master@{one.week.ago} означает "где имя master используется для указания на одну неделю ранее
в этом локальном репозитории", и так далее. См. в gitrevisions(7) для более подробной информации.
Эта команда управляет информацией, записанной в reflogs.
Субкоманда "show" (которая также активируется по умолчанию, когда не указана субкоманда для git reflog) покажет
лог ссылки, предоставленной в командной строке (или HEAD, по умолчанию). Команда reflog охватывает все недавние
действия, и дополнительно HEAD reflog записывает переключение между ветвями репозитория. Команда git reflog show
это алиас для команды git log -g --abbrev-commit --pretty=oneline; см. git-log(1) для дополнительной информации.
Субкоманда "expire" elfkztn старые записи журнала. Записи, которые старше чем expire time, или записи, которые
старее чем expire-unreachable time, и недоступные из текущего состояния (current tip), будут удалены из reflog.
Обычно это не используется напрямую — вместо этого см. git-gc(1).
Субкоманда "delete" удаляет одиночные записи из reflog. Её аргумент должен четко указывать на удаляемую запись
(например "git reflog delete master@{2}"). Эта субкоманда также обычно не используется напрямую.
Субкоманда "exists" проверит, subcommand есть ли в reflog ссылка ref. Если есть, то будет возвращен нулевой
статус, иначе будет возвращен ненулевой статус.
Опции для show:
git reflog принимает любые опции, которые принимает команда git log.
Опции для expire:
--all
Обработать reflogs всех ссылок.
--single-worktree
По умолчанию, когда указано --all, обрабатываются reflogs из всех рабочих ветвлений (working trees). Эта опция
ограничит обработку на reflogs только из текущего working tree.
--expire=< time>
Удалит записи, которые старше указанного времени time. Если эта опция не указана, то время устаревания
(expiration time) берется из установки конфигурации gc.reflogExpire, которая в свою очередь по умолчанию
равна 90 дней. Опция --expire=all удалит записи независимо от их возраста; --expire=never выключит удаление
доступных записей (однако см. --expire-unreachable).
--expire-unreachable=< time>
Удалит записи старее чем < time>, которые недоступны из текущего положения (current tip) ветви репозитория.
Если эта опция не указана, то expiration time берется из установки конфигурации gc.reflogExpireUnreachable,
которая в свою очередь по умолчанию равна 30 дням. Опция --expire-unreachable=all удалит недоступные
записи независимо от их возраста; --expire-unreachable=never выключит раннее удаление недоступных
записей (однако см. --expire).
--updateref
Обновит ссылку на значение верхней записи reflog (т. е. < ref>@{0}), если предыдущая верхняя запись была
удалена (эта опция игнорируется для символических ссылок).
--rewrite
Если предшествующая запись reflog была удалена, подстроит её "old" поле SHA-1 равным "new" SHA-1 полю записи,
которая ей теперь предшествует.
--stale-fix
Удалит любые записи reflog, указывающие на "испорченные фиксации" (broken commits). Испорченная фиксация
это commit, который недоступен из любого имени ссылки (reference tip), и таким образом ссылается, прямо
или косвенно, на отсутствующий commit, tree, или объект blob.
Это вычисление включает в себя обход всех доступных объектов, т. е. это имеет ту же стоимость, что и
git prune. Это главным образом предназначено для исправления повреждения, вызванного сборкой мусора
(см. git-gc) более старых версий Git, которые не защищают объекты, на которые ссылается reflogs.
-n, --dry-run
Не делает реальное удаление любых записей; просто покажет, какие записи могли быть удалены.
--verbose
Выводит дополнительную информацию.
Опции для delete:
Команда git reflog delete принимает опции --updateref, --rewrite, -n, --dry-run и --verbose, которые имеют
тоже самое значение, которое использовалось для субкоманды expire.
[git log --reflog]
--reflog
Работает так, как если бы все объекты, упомянутые в reflog, были перечислены в командной строке
как < commit>.
[Манипуляции с ветками (branch)]
Ветка это просто обособленная версия проекта, которая может храниться в репозитории независимо от остальных веток. Можно переключаться между ветками, и делать в каждой из них какую-либо экспериментальную работу.
Команда
Функция
git branch
Показать список всех веток, которые существуют в репозитории. По умолчанию в репозитории существует только одна основная ветка - master. Если веток несколько, то текущая ветка будет помечена звездочкой и её название выделена зеленым текстом.
git branch -a
Посмотреть список веток в локальном и сетевом репозитории. Текущая ветка в локальном репозитории будет выделена зеленым цветом, а ветки в сетевом репозитории будут выделены красным, и будут иметь префикс remotes/origin/.
git branch имяновойветки
Создать новую ветку в проекте без переключения на неё.
git checkout -b имяновойветки
Создать новую ветку и переключиться на неё.
git switch -c имяновойветки
Создать новую ветку от текущей фиксации, и сделать эту ветку текущей. Как переключаться между фиксациями, см. [9].
git branch -D имяветки
Удалить ветку.
git switch -
Отмена предыдущей операции переключения между ветками.
git checkout ссылканаветку
Переключение между ветками. Вместо ссылканаветку может быть указано либо имя ветки (master или любое другое имя), либо первые шесть HEX-символа хеша фиксации. Список фиксаций с хешами можно посмотреть командой git log --pretty=oneline.
git branch -m old new
Переименовать ветку. Ветка с именем old получит имя new.
Хороший стиль работы - не плодить слишком много веток, чтобы не запутаться, либо вести подробную документацию по каждой ветке. В ветке master должен быть основной результат работы над проектом, а в ветках какие-либо мало значимые эксперименты.
Создайте файл .gitignore, поместите его в корневую папку проекта (там же, где находится папка репозитория .git), и в этом файле создайте строки, обозначающие исключаемые файлы (см. выше описание работы с файлом .gitignore).
Для этого используйте группировку /**/. Например, следующая запись .gitignore исключит из репозитория все файлы *.pdf, которые находятся в папке util, и во всех её подкаталогах:
util/**/*.pdf
Групповые подстановки можно также использовать и в командной строке Git.
Файл .gitignore должен иметь кодировку UTF-8. Вместо стандартной консоли команд cmd.exe в Windows используйте командную строку MINGW64 bash (устанавливается вместе с Git).
Процесс по шагам (взято из замечательной статьи [6]):
1. Сначала надо создать на сервере пустой репозиторий. Обычно это делается в HTML-интерфейсе сервера. После этого нужно запомнить Git-ссылку на этот репозиторий. Предположим, ссылка такая:
http://git.netserver.ru/username/myproject.git
2. В папке локального репозитория выполнить команды:
git remote add server http://git.netserver.ru/username/myproject.git git push server master:master
Первая команда добавляет в конфигурацию репозитория новый сервер, вторая делает выгрузку репозитория на сервер.
3. Для того, чтобы команды git теперь работали с репозиторием на сетевом сервере git.netserver.ru, выполните команду:
Иногда надо дополнительно выполнить следующую команду, чтобы протолкнуть (push) текущую ветку репозитория (branch) на сетевой сервер, и установить его как приемник push:
git push --set-upstream origin master
После этой команды git push и git pull будут по умолчанию работать с репозиторием на сетевом сервере.
4. Чтобы сохранить наработанные изменения и протолкнуть их на сервер, используйте команды:
git add . git commit -a git push
Чтобы засинхронизировать текущий проект с сервером, используйте команду:
В репозитории (это был nRF5x SDK 12.3) множество проектов примеров содержат файлы Makefile, распределенные по разным каталогам. Простая команда с указанием имени файла не позволяет добавить в репозиторий эти файлы:
d:\asm\nRF5_SDK_12.3.0_d7731ad>git add Makefile
fatal: pathspec 'Makefile' did not match any files
Проблема в том, что тут указано полное имя, без шаблона wildcard. Чтобы команда сработала, нужно указать в качестве имени файла */Makefile, что будет соответствовать файлам Makefile в любом из подкаталогов репозитория:
Попытался сделать push ветки на сервер, не получилось, git выдает сообщение:
fatal: Вы сейчас не находитесь ни на одной из веток
В чем ошибка: перед внесением изменений в код не была установлена текущая ветка. Что надо сделать:
1. Копию всех исходников! 2. git checkout имя_той_ветки_котору_надо_выгрузить_на_сервер. Эта команда отменит все изменения, и вернет старое локальное состояние этой ветки. 3. Вернуть все исходники обратно из копии, сделанной на шаге 1. 4. git add *, git commit -m "bla-bla" 5. git push
Восстановить случайно удаленный файл можно командой git checkout имяфайла.
$ git status
Текущая ветка: main
Эта ветка соответствует « main ».
Изменения, которые не в индексе для коммита:
удалено: src/adcbatt.c
удалено: src/main.c
$ git checkout src/adcbatt.c
Updated 1 path from the index
$ git checkout src/main.c
Updated 1 path from the index
В чем ошибка: перед внесением изменений в код не была установлена текущая ветка. Что надо сделать:
1. Копию всех исходников! 2. git checkout имя_той_ветки_котору_надо_выгрузить_на_сервер. Эта команда отменит все изменения, и вернет старое локальное состояние этой ветки. 3. Вернуть все исходники обратно из копии, сделанной на шаге 1. 4. git add *, git commit -m "bla-bla" 5. git push
Подобная ошибка может произойти, если была переустановка операционной системы, и каталог репозитория был восстановлен с помощью внешнего диска с файловой системой FAT32.
$ git status
fatal: detected dubious ownership in repository at '/home/имяпользователя/каталог'
To add an exception for this directory, call:
Исправить ошибку можно либо командой git config --global, как советуется в этом сообщении об ошибке, либо если поменять владельца каталога репозитория на текущего пользователя:
Предположим, что вы сделали несколько изменений в проекте, и не хотите делать фиксацию (commit) этих изменений. И вам нужно переключиться на какую-то предыдущую фиксацию, сбросив все эти изменения. Для этого нужно сначала сбросить все изменения командой git reset --hard, а потом командой git checkout переключиться на нужную фиксацию, указав её контрольную сумму:
При переходе на новый SDK было удалено из локальной папки проекта множество файлов. После команд git add * и git commit -m "сообщение фиксации" эти файлы остались в локальном репозитории git, помеченные как "deleted". Как их быстро удалить, чтобы не удалять каждый файл по отдельности командой git rm?
Это можно сделать следующей последовательностью команд:
$ git add --all $ git commit -am "Удалил файлы из репозитория git." $ git status $ git push
Что означает -all. Опция --all команды add (можно применить вместо неё -A) добавит изменения всех отслеживаемых и не отслеживаемых в базе файлов, т. е. удалит из репозитория все удаленные в проекте файлы, и добавит не отслеживаемые, в том числе и те, которые начинаются на точку (такие как .gitignore или .config) (см. [1]).
Что означает -am. Из документации: "Команда git commit -a автоматически отразит в базе репозитория все отслеживаемые, модифицированные файлы перед применением фиксации. Если вы считаете, что стадия git add в рабочем процессе излишняя, Git позволит вам пропустить эту часть с помощью опции -a. Это в основном говорит Git запустить git add на любом файле, который "отслеживается" - т. е. на любом файле, который был в вашей последней фиксации, и который был изменен. Это позволит вам, если захотите, получить рабочий процесс больше похожим на стиль Subversion, когда после редактирования файлов вы просто запускаете git commit -a, когда хотите сделать снимок всего, что было изменено. Хотя вам все еще понадобится запустить команду git add, чтобы начать отслеживать новые файлы, так же как и в Subversion.
Таким образом, команда git commit -am позволит вам добавить изменения в базу репозитория и одновременно создать фиксацию с указанным сообщением [2].
Когда вы используете git commit -e, Git открывает текстовый редактор, чтобы вы могли написать или отредактировать сообщение коммита. Чтобы завершить ввод и создать коммит, нужно **сохранить файл с сообщением и закрыть редактор**.
Способ сохранения и выхода зависит от вашего редактора:
Vim / Vi: нажмите `Esc`, затем введите `:wq` и нажмите `Enter` (сохранить и выйти). Nano: нажмите `Ctrl + X`, затем `Y` (подтвердить сохранение), и `Enter`. Emacs: нажмите `Ctrl + X`, затем `Ctrl + S` (сохранить), и `Ctrl + X`, затем `Ctrl + C` (выйти). VS Code (если он настроен как редактор): просто закройте вкладку с файлом коммита. Sublime Text / Atom и другие GUI редакторы: закройте окно или вкладку.
После того как вы сохраните файл и закроете редактор, Git автоматически завершит коммит с вашим сообщением.
Для того чтобы Git игнорировал изменения прав доступа (chmod) к файлам и папкам, нужно настроить параметр core.fileMode.
Вот как это сделать:
1. Для конкретного репозитория. Находясь в папке репозитория, выполните команду:
git config core.fileMode false
2. Глобально (для всех репозиториев на компьютере). Если вы хотите, чтобы Git всегда игнорировал права доступа, выполните:
git config --global core.fileMode false
Что это даст?
- Git перестанет видеть изменения бита «исполняемости» (executable) и прав на запись/чтение. - Команда `git status` перестанет показывать такие файлы как изменённые (`modified`), если поменялись только права.
Важное предостережение: этот параметр не отключает отслеживание прав, которые уже были закоммичены. Если вы хотите, чтобы Git совсем забыл о правах для конкретного файла, нужно выполнить:
git update-index --chmod=-x путь/к/файлу
(или `+x` для добавления исполняемости), после чего закоммитить это изменение.
Права для папок. Git не отслеживает права доступа к папкам напрямую (он отслеживает только файлы). Поэтому настройка `core.fileMode` полностью решает проблему с игнорированием прав для всего содержимого репозитория, включая папки (через их файлы).
Проверка текущего значения. Чтобы узнать, включён ли игнор:
Команда `git update-index` сама по себе не поддерживает рекурсивную обработку каталогов. Однако в Ubuntu это легко сделать, комбинируя её с другими командами оболочки.
Ниже приведены три способа. Самый безопасный и рекомендуемый — с использованием `git ls-files`.
Способ 1: `git ls-files` + `xargs` (рекомендуется)
Этот метод получает список всех файлов, отслеживаемых Git, и передаёт их по очереди в `git update-index`.
● `git ls-files -z` — выводит имена всех отслеживаемых файлов, разделяя их нулевым символом (`\0`). Это корректно обрабатывает имена с пробелами и спецсимволами. ● `xargs -0` — читает входные данные, разделённые нулём, и подставляет их как аргументы для следующей команды.
Способ 2: `find` (простой, но есть нюансы)
find . -type f -exec git update-index --chmod=-x {} \;
● Эта команда рекурсивно обходит всё, начиная с текущего каталога (`.`), находит все обычные файлы (`-type f`) и для каждого из них выполняет `git update-index --chmod=-x`. ● Важно: `find` обрабатывает все файлы в каталоге, включая те, которые не отслеживаются Git. Из-за этого могут появляться сообщения об ошибках (например, "файл не в индексе"). Это не критично, но неаккуратно.
Способ 3: `git add --chmod=-x` (Git 2.9 и новее)
Если у вас установлен Git версии 2.9 или выше, проще всего использовать встроенную возможность `git add`:
git add --chmod=-x .
● Эта команда рекурсивно обрабатывает все файлы в текущем каталоге (и подкаталогах), снимает с них флаг выполнения и сразу же добавляет изменения в индекс (staging area). ● Она работает только с отслеживаемыми файлами, так что лишних ошибок не будет.
Важные замечания:
1. Изменяется только индекс Git. `git update-index` (и `git add --chmod`) меняет атрибуты только в индексе (staging area). Реальные права доступа к файлам в вашей рабочей директории не меняются. Если вы хотите также изменить права в файловой системе, нужно дополнительно выполнить команду `chmod -x` для нужных файлов.
2. Только для отслеживаемых файлов. Все перечисленные команды (кроме `find`) влияют только на те файлы, которые уже находятся под версионным контролем. Новые или игнорируемые файлы не затрагиваются.
3. Проверьте результат. После выполнения любой из команд выполните `git status`, чтобы увидеть, какие изменения попали в индекс. Убедитесь, что всё соответствует вашим ожиданиям.
Для этого нужно переписать историю коммитов, что является деструктивной операцией. После неё все хеши коммитов изменятся, поэтому при работе с общим репозиторием необходимо согласовать действия со всей командой.
Для решения этой задачи есть два основных инструмента. Современный и рекомендуемый — git filter-repo, а git filter-branch — это классический, но устаревший способ.
Способ 1: git filter-repo (рекомендуемый)
Этот инструмент нужно установить отдельно (например, через `pip install git-filter-repo`), но он работает быстрее и безопаснее.
Чтобы удалить файл readme.txt из всей истории, выполните команду в корне репозитория:
git filter-repo --invert-paths --path readme.txt
Если файл находится не в корне, укажите путь к нему, например:
Работа в команде: после переписывания истории все ваши коллеги должны будут заново клонировать репозиторий или выполнить `git fetch --force` и сбросить свои ветки.
Резервная копия: перед выполнением этих операций настоятельно рекомендуется сделать полную резервную копию всего репозитория.
Локальный файл: если вы хотите удалить файл только из истории, но оставить его в рабочем каталоге, используйте `git rm --cached` перед переписыванием истории.
[Альтернативный инструмент: BFG Repo-Cleaner]
Существует также сторонний инструмент BFG Repo-Cleaner, который специализируется на удалении больших или конфиденциальных файлов из истории Git и может быть проще в использовании.
warning: in the working copy of '.gitignore', LF will be replaced by CRLF the next time Git touches it
Как избавиться от этого сообщения?
[Что это означает?]
Предупреждение: в рабочей копии файла `.gitignore` символы окончания строк `LF` будут заменены на `CRLF` при следующем обращении Git к этому файлу.
Git предупреждает, что в вашем файле `.gitignore` используются переводы строк в стиле Unix (`LF`), но ваша текущая конфигурация Git (например, `core.autocrlf` или настройки атрибутов) предписывает при следующем изменении файла автоматически преобразовывать их в формат Windows (`CRLF`). Это не ошибка, а информационное сообщение.
[Как избавиться от этого сообщения?]
Основные способы:
1. Самый надёжный способ – создать в корне проекта файл .gitattributes, и прописать в нём правила для всех текстовых файлов, например:
* text=auto eol=lf
Это заставит Git при коммитах преобразовывать все текстовые файлы к формату `LF`, и предупреждение исчезнет. Также можно явно задать правила для конкретных файлов.
2. Изменить глобальную настройку `core.autocrlf`:
- На Windows: `git config --global core.autocrlf true` - На macOS/Linux: `git config --global core.autocrlf input` - Либо отключить автоматическую конвертацию: `git config --global core.autocrlf false` (тогда предупреждение тоже пропадёт, но вам придётся самостоятельно следить за окончаниями строк).
3. Отключить само предупреждение (не рекомендуется):
git config --global core.safecrlf false
Это скроет сообщение, но не решит проблему с несовместимостью окончаний строк.
Рекомендуется воспользоваться именно первым способом – он самый правильный и для индивидуальной работы, и для командной.
[Почему предупреждение осталось?]
git config --global core.autocrlf true
После выполнения этой команды предупреждение git diff осталось.
git diff warning: in the working copy of '.gitignore', LF will be replaced by CRLF the next time Git touches it
Это нормально — давайте разберёмся, почему так происходит и что с этим делать.
Почему предупреждение осталось? `core.autocrlf true` говорит Git:
- при извлечении (checkout) превращать `LF` в `CRLF` (для Windows),| - при фиксации (commit) превращать `CRLF` обратно в `LF`.
Однако это правило применяется не мгновенно ко всем файлам, а только в момент, когда Git касается файла — то есть когда вы его добавляете (`git add`), переключаете ветку или выполняете `git checkout`.
Команда `git diff` как раз сравнивает рабочую копию с индексом (или с последним коммитом). Если в рабочей копии у файла `.gitignore` стоят `LF`, а Git "знает", что при следующем добавлении он превратит их в `CRLF`, то он честно предупреждает вас об этом. Сама настройка `autocrlf` не приводит к немедленной замене — она только определяет поведение при операциях записи.
Как убрать это предупреждение прямо сейчас? Вам нужно дать Git возможность применить правило к этому файлу. Самый простой способ — добавить файл в индекс (даже если он не менялся):
git add .gitignore
После этого Git "коснётся" файла и преобразует его окончания строк согласно `autocrlf`. При следующем запуске `git diff` предупреждение исчезнет (если, конечно, вы не измените файл снова вручную, вставив новые `LF`).
Если таких файлов много, можно сделать массовую «перенормализацию» всех файлов в репозитории:
git add --renormalize .
Эта команда заставит Git перечитать атрибуты и применить их ко всем файлам, обновив их в индексе. После этого предупреждения больше не будут появляться (пока вы не создадите новые файлы с неподходящими окончаниями).
Как избавиться от предупреждения навсегда (и для всех будущих файлов)?
Ваш `core.autocrlf true` уже настроен глобально — это хороший шаг. Но для полной уверенности и единообразия лучше использовать файл `.gitattributes` в корне проекта. Он имеет приоритет над глобальной настройкой и гарантирует одинаковое поведение у всех разработчиков.
Создайте `.gitattributes` со следующим содержимым:
* text=auto
А затем выполните:
git add --renormalize . git commit -m "Normalize line endings"
После этого все файлы в репозитории получат правильные окончания, и предупреждение больше никогда не появится ни у вас, ни у коллег.
Если предупреждение всё же появляется после `git add`? Проверьте, не стоит ли у вас локально переопределение через `.gitattributes` или `core.autocrlf` на уровне репозитория. Команда:
.. покажет, какие правила действуют для этого конкретного файла. Возможно, вы ранее установили `core.autocrlf false` локально — тогда глобальная настройка не применяется.
Резюме:
- Предупреждение при `git diff` — это нормально, оно говорит о том, что Git планирует преобразование при следующем касании. - Чтобы оно исчезло, выполните `git add .gitignore` или `git add --renormalize .`. - Для долгосрочного решения используйте `.gitattributes` с `* text=auto` и выполните `git add --renormalize .`. - Если после этих действий предупреждение остаётся — проверьте локальные настройки Git.
[Pro Git]
Существует книга, которая может послужить замечательным введением в мир git - Pro Git, авторы Scott Chacon и Ben Straub. Эта книга переведена на многие языки, в том числе и на русский язык.
Книга на русском языке доступна в виде репозитория GitHub [13], а также доступна её онлайн-версия [14]. Получить книгу последней версии в популярных электронных форматах можно, если выполнить её компиляцию (см. врезку).
После выполнения этой команды в папке проекта progit2-ru появятся скомпилированные файлы progit.pdf, progit.mobi, progit-kf8.epub, progit.fb2.zip, progit.epub, progit.html.
При выполнении команды bundle install столкнулся с ошибкой:
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory:
/home/user/asm/progit2-ru/.bundle/vendor/ruby/3.0.0/gems/racc-1.7.3/ext/racc/cparse
/usr/bin/ruby3.0 -I /usr/lib/ruby/vendor_ruby -r ./siteconf20240109-25035-tgyk07.rb extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.h
You might have to install separate package for the ruby development
environment, ruby-dev or ruby-devel for example.
extconf failed, exit code 1
Как исправить:
$ sudo apt install ruby-bundler
[git status: проблема с изменениями прав доступа к файлам]
Часто происходит неприятная ситуация с большим репозиторием, когда git status показывает изменения почти во всех файлах, хотя на самом деле изменены были только права доступа:
$ git diff components/unity/port/esp/unity_utils_memory_esp.c
diff --git a/components/unity/port/esp/unity_utils_memory_esp.c
b/components/unity/port/esp/unity_utils_memory_esp.c
old mode 100644
new mode 100755
В Ubuntu режим файлов 100644 устанавливается через файловую систему, а не настройками Git. Этот код (644) — это стандартные разрешения для обычных файлов в Linux, которые Git просто сохраняет в своей базе.
Ниже приведены способы управления разрешениями файлов, в том числе для получения режима 644. Чтобы изменить разрешения файла в файловой системе Ubuntu на 644 (владелец: чтение+запись, остальные: только чтение), используется команда chmod:
$ chmod 644 имя_файла
То же самое с рекурсией по директориям:
$ chmod -R 644 имя_файла
Альтернативный способ рекурсивного изменения прав доступа:
$ find . -type f -exec chmod -x {} \;
Чтобы проверить текущие разрешения файла:
$ ls -l имя_файла
В результате вы увидите строку -rw-r--r--, которая и соответствует разрешениям 644.
Разрешения и Git:
● Автоматическое отслеживание: когда вы добавляете файл с разрешениями 644 в репозиторий с помощью git add, Git запомнит их как режим 100644 в своем индексе. ● Изменение разрешений в индексе Git: если файл уже находится в индексе Git, а вы изменили его разрешения в файловой системе, Git отметит это как изменение. Чтобы обновить разрешения в индексе Git, нужно повторно добавить файл (git add). ● Специальный случай: исполняемые файлы: для файлов с установленным флагом исполняемости (chmod +x) Git будет хранить режим 100755. Вернуть такой файл обратно к 100644 можно, сняв флаг исполняемости в системе (chmod -x) и снова добавив файл в Git.
Ключевые различия: система vs Git:
Аспект
В файловой системе Ubuntu
В индексе Git (например, git ls-files --stage)
Как отображается
Символами (напр., -rw-r--r--)
Числовым кодом (100644)
Как установить
Команда chmod 644 файл
Автоматически, при добавлении файла с правами 644 командой git add
Как проверить
ls -l файл
git ls-files --stage -- файл
Если Git постоянно отмечает изменение режима файла (например, с 100755 на 100644), это может быть связано с настройкой core.filemode или работой с файлами между разными ОС. Чтобы игнорировать изменения только в разрешениях файлов, можно установить опцию конфигурации core.filemode false в вашем репозитории:
$ git config core.filemode false
[Словарик]
branch ветвление проекта (создание его отдельной версии в репозитории).
commit легковесный снимок состояния файлов в определенный момент времени (когда был сделан коммит).
head самая последняя версия файлов в репозитории.
repository репозиторий, база данных, где хранится история изменений проекта. Git хранит репозиторий в папке .git, которая находится в корневом каталоге проекта.
staging area область файловой системы (список файлов), подготовленная к коммиту.
stash операция, которая поглощает грязное состояние рабочего каталога, то есть изменённые отслеживаемые файлы и изменения в индексе, и сохраняет их в стек незавершённых изменений, которые вы потом в любое время можете снова применить.
[Ссылки]
1. Downloads Git site:git-scm.com. 2. Learn Git site:atlassian.com. 3. Подробное введение в работу с Git site:tproger.ru. 4. A collection of useful .gitignore templates site:github.com. 5. git: быстрый старт. 6. Как перенести локальный GIT-репозитарий на сервер вместе со всей историей site:webhamster.ru. 7. Инструменты Git - Припрятывание и очистка site:git-scm.com. 8. jjjsmit / BluetoothBLEClient site:github.com. 9. Git: как переключаться между фиксациями. 10. How do I force "git pull" to overwrite local files? site:stackoverflow.com. 11. git: как создавать многострочный комментарий для commit. 12. git: как сравнивать фиксации и ветки. 13. Репозиторий Pro Git на русском языке. 14. Онлайн-версия Pro Git на русском языке. 15. 240109progit2-ru.zip - скомпилированная книга Pro Git на русском языке в форматах HTML, EPUB, FB2, Mobi (kf8), PDF. 16. Is there a way to cause git-reflog to show a date alongside each entry? site:stackoverflow.com. 17. Output of git branch in tree like fashion site:stackoverflow.com.