🧙 Садовник: уточнил шаги, добавил проверки и обоснования. Примите, если полезно.

#1
open+276proposed by devops · Aug 16, 2026 · based on v2
Proposed changes · v2 → suggestion
+1079
1¶ # Зачем это нужно
2
3 Типичная ситуация: что-то сломалось или выстрелило, ты нашёл в файле строку, которая всё объясняет. Остались вопросы: когда она туда попала, вместе с чем и почему никто не заметил.
4
5 Главное сразу: **цель расследования — не виноватый, а механизм.** Фамилия в коммите ничего не чинит. Ответ на вопрос «как это прошло ревью и выкатку» — чинит.
6
7 Список непоследовательный — бери ту команду, которая подходит к твоему вопросу.
81## Подготовка
92• Убедиться, что история вообще есть
103 Самая обидная преграда: репозиторий клонировали с обрезанной историей, и старых коммитов просто нет.
114
125 ```bash
136 git rev-parse --is-shallow-repository # true = история обрезана
147 git fetch --unshallow # дотянуть всю
158 git log --oneline | wc -l # сколько коммитов теперь
169 ```
1710
1811 Так бывает чаще, чем кажется: системы развёртывания клонируют с `--depth 1` ради скорости.
1912 $ git rev-parse --is-shallow-repository
2013 why: На обрезанной истории `git log` по файлу покажет один коммит и создаст впечатление, что файл сразу таким и родился. Можно потратить час на неверный вывод.
2114 - [ ] Команда отвечает false
2215 - [ ] Число коммитов похоже на правду
2316 → git fetch --unshallow — https://git-scm.com/docs/git-fetch
2417## Поиск
2518• Найти коммит, где появилась конкретная строка
2619 Главный инструмент расследования — флаг `-S`, в документации он называется pickaxe, «кирка»:
2720
2821 ```bash
2922 # коммиты, где число вхождений строки изменилось
3023 git log -S'5432:5432' --oneline -- docker-compose.yml
3124
3225 # то же, но сразу с датами и авторами
3326 git log -S'5432:5432' --format='%h %ad %an %s' --date=short
3427
3528 # если нужна регулярка по тексту изменений
3629 git log -G'ports:\s*$' --oneline
3730 ```
3831
3932 Разница между ними важная. `-S` ищет коммиты, где строка **появилась или исчезла**. `-G` — все, где она просто встретилась в диффе, включая перемещения и переотступы. Для вопроса «когда это появилось» нужен `-S`.
4033 $ git log -S'искомая строка' --format='%h %ad %an %s' --date=short
4134 why: Поиск глазами по `git log -p` работает на десятке коммитов и проваливается на тысяче. `-S` даёт ответ за секунды на любом размере истории.
4235 - [ ] Найден коммит, в котором строка появилась
4336 - [ ] Ты понимаешь разницу между -S и -G
4437 → git log — документация — https://git-scm.com/docs/git-log
4538• Посмотреть историю файла через переименования [recommended]
4639 ```bash
4740 git log --oneline --follow -- путь/к/файлу
4841 ```
4942
5043 Флаг `--follow` продолжает историю через переименования и перемещения. Без него история обрывается в точке, где файл переехал в другую папку.
5144
5245 Работает только с одним путём — это ограничение самой команды.
5346 $ git log --oneline --follow -- путь/к/файлу
5447 why: Файлы переезжают при любой перестройке структуры. Без --follow легко решить, что проблема свежая, хотя она ездит с проектом год.
5548 - [ ] Видна вся история файла, включая жизнь под старым именем
5649• Прочитать файл таким, каким он был в тот момент
5750 Когда коммит найден, нужно увидеть контекст целиком, а не только строку:
5851
5952 ```bash
6053 # файл целиком на момент коммита
6154 git show <sha>:путь/к/файлу
6255
6356 # только изменения по этому файлу
6457 git show <sha> -- путь/к/файлу
6558
6659 # что ещё ехало в том же коммите
6760 git show --stat <sha>
6861 ```
6962
7063 Обрати внимание на двоеточие против двойного тире: `<sha>:путь` — содержимое файла, `<sha> -- путь` — дифф.
7164 $ git show --stat <sha>
7265 why: Отдельная строка часто выглядит глупостью, а в контексте оказывается частью большого коммита на сотни строк — такого, который физически невозможно внимательно проревьюить. Это уже ответ на вопрос «как прошло мимо».
7366 - [ ] Виден весь файл на момент коммита
7467 - [ ] Известен размер того коммита целиком
7568• Посмотреть построчно, откуда взялась каждая строка [recommended]
7669 ```bash
7770 # только нужный диапазон строк
7871 git blame -L 40,55 путь/к/файлу
7972
8073 # игнорировать правки пробелов и отследить перенос строк из других файлов
8174 git blame -w -C -C -L 40,55 путь/к/файлу
8275 ```
8376
8477 Флаги важны: `-w` игнорирует изменения пробелов, `-C -C` ищет, откуда строку скопировали. Без них blame часто показывает того, кто прогнал форматтер — а не автора строки.
8578 $ git blame -w -C -C -L 40,55 путь/к/файлу
8679 why: Половина претензий к blame — из-за этих флагов. Люди видят чужую фамилию, махают рукой и решают, что инструмент врёт.
8780 - [ ] Ты понимаешь, зачем нужны -w и -C
8881 → git blame — документация — https://git-scm.com/docs/git-blame
8982• Если опорной строки нет — бинарный поиск [recommended]
9083 Когда известно только «раньше работало, теперь нет»:
9184
9285 ```bash
9386 git bisect start
9487 git bisect bad # текущий — сломанный
9588 git bisect good <старый-sha> # там было хорошо
9689
9790 # git переключает на середину, ты проверяешь и говоришь:
9891 git bisect good # или
9992 git bisect bad
10093
10194 git bisect reset # вернуться как было
10295 ```
10396
10497 Если проверку можно автоматизировать, git сделает всё сам:
10598
10699 ```bash
107100 git bisect run ./check.sh # код 0 = хорошо, не 0 = плохо
108101 ```
109102
110103 За 20 шагов просеивается миллион коммитов — это обычный двоичный поиск.
111104 $ git bisect start
112105 why: Не всякая проблема выражается строкой, которую можно поискать. Падение производительности или плавающая ошибка ищется только так.
113106 - [ ] Ты знаешь про git bisect run
114107 - [ ] Помнишь про git bisect reset в конце
115108 → git bisect — документация — https://git-scm.com/docs/git-bisect
116## Собрать таймлайн
117
118 Отдельный коммит мало что говорит. Смысл появляется, когда время из git ложится рядом со временем из системных логов:
119
120 ```bash
121 # события из git за период
122 git log --since='2 weeks ago' --format='%ad %h %an %s' --date=iso
123
124 # события системы за тот же период
125 journalctl --since '2025-10-08' --until '2025-10-14' | grep -i 'oom\|killed'
126
127 # когда контейнер создали и запустили
128 docker inspect --format '{{.Created}} {{.State.StartedAt}}' имя
129 ```
130
131 В разобранном случае таймлайн выглядел так:
132
133 | Время | Источник | Событие |
134 |---|---|---|
135 | 08:07 | git | коммит с открытым портом |
136 | ~08:30 | docker | контейнер создан |
137 | 16:29 | системный лог | OOM killer убил неизвестный процесс |
138
139 Последняя строка — самая важная. **Сигнал был в первый же день**, просто его никто не читал. Отсюда родился вывод, который дал больше пользы, чем поиск автора коммита: нужен алерт на срабатывание OOM killer.
140¶ ## Главное правило разбора
141
142 Когда виновная строка найдена, появляется соблазн написать в отчёте фамилию автора и распределить ответственность в процентах. Это бесполезно и вредно.
143
144 Бесполезно — потому что не меняет вероятность повтора. Вредно — потому что следующий человек, наткнувшийся на странность, предпочтёт промолчать.
145
146 Заканчивай разбор тремя пунктами:
147
148 1. **Что сработало как надо.** Аварию всё-таки заметили — как именно?
149 2. **Где был шанс поймать раньше.** Не «кто пропустил», а «какой проверки не было».
150 3. **Какая проверка поймала бы это автоматически.** И сразу завести на неё задачу.
151
152 Для того инцидента ответ на третий пункт — проверка в конвейере, которая не пускает в бой compose-файл с прокинутым портом базы:
153
154 ```bash
155 # в простейшем виде — одна строка в конвейере
156 grep -nE '^\s*-\s*"?[0-9]+:(5432|6379|3306|27017)"?' docker-compose.yml && exit 1
157 ```
158
159 Такая строка полезнее любого вывода о том, кто виноват.
160¶ ## Шпаргалка
161
162 ```bash
163 # есть ли история
164 git rev-parse --is-shallow-repository
165 git fetch --unshallow
166
167 # когда появилась строка
168 git log -S'строка' --format='%h %ad %an %s' --date=short
169 git log -G'регулярка' --oneline
170
171 # история файла
172 git log --oneline --follow -- путь
173
174 # состояние на момент
175 git show <sha>:путь # файл целиком
176 git show <sha> -- путь # только дифф
177 git show --stat <sha> # что ещё ехало рядом
178
179 # построчно
180 git blame -w -C -C -L 40,55 путь
181
182 # если строки нет
183 git bisect start / bad / good / run ./check.sh / reset
184 ```
185
186
187
109+## Проверка
110+• Проверить актуальную версию Git
111+ Убедитесь, что используете последнюю версию Git, так как некоторые флаги могут изменяться или устаревать.
112+ $ git --version
113+ why: Актуальные версии содержат исправления и новые функции.
114+ - [ ] Версия Git соответствует последним рекомендациям
115+ git документация https://git-scm.com/doc
116+• Проверить наличие необходимых прав на репозиторий
117+ Убедитесь, что у вас есть доступ для выполнения всех необходимых команд в репозитории.
118+ why: Без необходимых прав вы не сможете выполнить команды, что приведет к ошибкам.
Review