# Зачем это нужноAdded
Зачем это нужно
Типичная ситуация: что-то сломалось или выстрелило, ты нашёл в файле строку, которая всё объясняет. Остались вопросы: когда она туда попала, вместе с чем и почему никто не заметил.
Главное сразу: цель расследования — не виноватый, а механизм. Фамилия в коммите ничего не чинит. Ответ на вопрос «как это прошло ревью и выкатку» — чинит.
Список непоследовательный — бери ту команду, которая подходит к твоему вопросу.
Убедиться, что история вообще естьAdded
Самая обидная преграда: репозиторий клонировали с обрезанной историей, и старых коммитов просто нет.
1git rev-parse --is-shallow-repository
2git fetch --unshallow
3git log --oneline | wc -l
Так бывает чаще, чем кажется: системы развёртывания клонируют с --depth 1 ради скорости.
git rev-parse --is-shallow-repositoryНайти коммит, где появилась конкретная строкаAdded
Главный инструмент расследования — флаг -S, в документации он называется pickaxe, «кирка»:
1
2git log -S'5432:5432' --oneline -- docker-compose.yml
3
4
5git log -S'5432:5432' --format='%h %ad %an %s' --date=short
6
7
8git log -G'ports:\s*$' --oneline
Разница между ними важная. -S ищет коммиты, где строка появилась или исчезла. -G — все, где она просто встретилась в диффе, включая перемещения и переотступы. Для вопроса «когда это появилось» нужен -S.
git log -S'искомая строка' --format='%h %ad %an %s' --date=shortПосмотреть историю файла через переименованияRecommendedAdded
1git log --oneline --follow -- путь/к/файлу
Флаг --follow продолжает историю через переименования и перемещения. Без него история обрывается в точке, где файл переехал в другую папку.
Работает только с одним путём — это ограничение самой команды.
git log --oneline --follow -- путь/к/файлуПрочитать файл таким, каким он был в тот моментAdded
Когда коммит найден, нужно увидеть контекст целиком, а не только строку:
1
2git show <sha>:путь/к/файлу
3
4
5git show <sha> -- путь/к/файлу
6
7
8git show --stat <sha>
Обрати внимание на двоеточие против двойного тире: <sha>:путь — содержимое файла, <sha> -- путь — дифф.
git show --stat <sha>Посмотреть построчно, откуда взялась каждая строкаRecommendedAdded
1
2git blame -L 40,55 путь/к/файлу
3
4
5git blame -w -C -C -L 40,55 путь/к/файлу
Флаги важны: -w игнорирует изменения пробелов, -C -C ищет, откуда строку скопировали. Без них blame часто показывает того, кто прогнал форматтер — а не автора строки.
git blame -w -C -C -L 40,55 путь/к/файлуЕсли опорной строки нет — бинарный поискRecommendedAdded
Когда известно только «раньше работало, теперь нет»:
1git bisect start
2git bisect bad
3git bisect good <старый-sha>
4
5
6git bisect good
7git bisect bad
8
9git bisect reset
Если проверку можно автоматизировать, git сделает всё сам:
1git bisect run ./check.sh
За 20 шагов просеивается миллион коммитов — это обычный двоичный поиск.
git bisect start## Собрать таймлайнAdded
Собрать таймлайн
Отдельный коммит мало что говорит. Смысл появляется, когда время из git ложится рядом со временем из системных логов:
1
2git log --since='2 weeks ago' --format='%ad %h %an %s' --date=iso
3
4
5journalctl --since '2025-10-08' --until '2025-10-14' | grep -i 'oom\|killed'
6
7
8docker inspect --format '{{.Created}} {{.State.StartedAt}}' имя
В разобранном случае таймлайн выглядел так:
| Время | Источник | Событие |
|---|
| 08:07 | git | коммит с открытым портом |
| ~08:30 | docker | контейнер создан |
| 16:29 | системный лог | OOM killer убил неизвестный процесс |
Последняя строка — самая важная. Сигнал был в первый же день, просто его никто не читал. Отсюда родился вывод, который дал больше пользы, чем поиск автора коммита: нужен алерт на срабатывание OOM killer.
## Главное правило разбораAdded
Главное правило разбора
Когда виновная строка найдена, появляется соблазн написать в отчёте фамилию автора и распределить ответственность в процентах. Это бесполезно и вредно.
Бесполезно — потому что не меняет вероятность повтора. Вредно — потому что следующий человек, наткнувшийся на странность, предпочтёт промолчать.
Заканчивай разбор тремя пунктами:
- Что сработало как надо. Аварию всё-таки заметили — как именно?
- Где был шанс поймать раньше. Не «кто пропустил», а «какой проверки не было».
- Какая проверка поймала бы это автоматически. И сразу завести на неё задачу.
Для того инцидента ответ на третий пункт — проверка в конвейере, которая не пускает в бой compose-файл с прокинутым портом базы:
1
2grep -nE '^\s*-\s*"?[0-9]+:(5432|6379|3306|27017)"?' docker-compose.yml && exit 1
Такая строка полезнее любого вывода о том, кто виноват.
## ШпаргалкаAdded
Шпаргалка
1
2git rev-parse --is-shallow-repository
3git fetch --unshallow
4
5
6git log -S'строка' --format='%h %ad %an %s' --date=short
7git log -G'регулярка' --oneline
8
9
10git log --oneline --follow -- путь
11
12
13git show <sha>:путь
14git show <sha> -- путь
15git show --stat <sha>
16
17
18git blame -w -C -C -L 40,55 путь
19
20
21git bisect start / bad / good / run ./check.sh / reset
# Зачем это нужноRemoved
# Зачем это нужно
Типичная ситуация: что-то сломалось или выстрелило, ты нашёл в файле строку, которая всё объясняет. Остались вопросы: когда она туда попала, вместе с чем и почему никто не заметил.
Главное сразу: **цель расследования — не виноватый, а механизм.** Фамилия в коммите ничего не чинит. Ответ на вопрос ´как это прошло ревью и выкатку´ — чинит.
Список непоследовательный — бери ту команду, которая подходит к твоему вопросу.
Убедиться, что история вообще естьRemoved
Самая обидная преграда: репозиторий клонировали с обрезанной историей, и старых коммитов просто нет.
```bash
git rev-parse --is-shallow-repository # true = история обрезана
git fetch --unshallow # дотянуть всю
git log --oneline | wc -l # сколько коммитов теперь
```
Так бывает чаще, чем кажется: системы развёртывания клонируют с `--depth 1` ради скорости.
Найти коммит, где появилась конкретная строкаRemoved
Главный инструмент расследования — флаг `-S`, в документации он называется pickaxe, «кирка»:
```bash
# коммиты, где число вхождений строки изменилось
git log -S'5432:5432' --oneline -- docker-compose.yml
# то же, но сразу с датами и авторами
git log -S'5432:5432' --format='%h %ad %an %s' --date=short
# если нужна регулярка по тексту изменений
git log -G'ports:\s*$' --oneline
```
Разница между ними важная. `-S` ищет коммиты, где строка **появилась или исчезла**. `-G` — все, где она просто встретилась в диффе, включая перемещения и переотступы. Для вопроса «когда это появилось» нужен `-S`.
Посмотреть историю файла через переименованияRecommendedRemoved
```bash
git log --oneline --follow -- путь/к/файлу
```
Флаг `--follow` продолжает историю через переименования и перемещения. Без него история обрывается в точке, где файл переехал в другую папку.
Работает только с одним путᑑм — это ограничение самой команды.
Прочитать файл таким, каким он был в тот моментRemoved
Когда коммит найден, нужно увидеть контекст целиком, а не только строку:
```bash
# файл целиком на момент коммита
git show <sha>:путь/к/файлу
# только изменения по этому файлу
git show <sha> -- путь/к/файлу
# что ещё ехало в том же коммите
git show --stat <sha>
```
Обрати внимание на двоеточие против двойного тире: `<sha>:путь` — содержимое файла, `<sha> -- путь` — дифф.
Посмотреть построчно, откуда взялась каждая строкаRecommendedRemoved
```bash
# только нужный диапазон строк
git blame -L 40,55 путь/к/файлу
# игнорировать правки пробелов и отследить перенос строк из других файлов
git blame -w -C -C -L 40,55 путь/к/файлу
```
Флаги важны: `-w` игнорирует изменения пробелов, `-C -C` ищет, откуда строку скопировали. Без них blame часто показывает того, кто прогнал форматтер — а не автора строки.
Если опорной строки нет — бинарный поискRecommendedRemoved
Когда известно только «раньше работало, теперь нет»:
```bash
git bisect start
git bisect bad # текущий — сломанный
git bisect good <старый-sha> # там было хорошо
# git переключает на середину, ты проверяешь и говоришь:
git bisect good # или
git bisect bad
git bisect reset # вернуться как было
```
Если проверку можно автоматизировать, git сделает всё сам:
```bash
git bisect run ./check.sh # код 0 = хорошо, не 0 = плохо
```
За 20 шагов просеивается миллион коммитов — это обычный двоичный поиск.
## Собрать таймлайнRemoved
## Собрать таймлайн
Отдельный коммит мало что говорит. Смысл появляется, когда время из git ложится рядом со временем из системных логов:
```bash
# события из git за период
git log --since='2 weeks ago' --format='%ad %h %an %s' --date=iso
# события системы за тот же период
journalctl --since '2025-10-08' --until '2025-10-14' | grep -i 'oom\|killed'
# когда контейнер создали и запустили
docker inspect --format '{{.Created}} {{.State.StartedAt}}' имя
```
В разобранном случае таймлайн выглядел так:
| Время | Источник | Событие |
|---|---|---|
| 08:07 | git | коммит с открытым портом |
| ~08:30 | docker | контейнер создан |
| 16:29 | системный лог | OOM killer убил неизвестный процесс |
Последняя строка — самая важная. **Сигнал был в первый же день**, просто его никто не читал. Отсюда родился вывод, который дал больше пользы, чем поиск автора коммита: нужен алерт на срабатывание OOM killer.
## Главное правило разбораRemoved
## Главное правило разбора
Когда виновная строка найдена, появляется соблазн написать в отчᑑте фамилию автора и распределить ответственность в процентах. Это бесполезно и вредно.
Бесполезно — потому что не меняет вероятность повтора. Вредно — потому что следующий человек, наткнувшийся на странность, предпочтᑑт промолчать.
Заканчивай разбор тремя пунктами:
1. **Что сработало как надо.** Аварию всᑑ-таки заметили — как именно?
2. **Где был шанс поймать раньше.** Не «кто пропустил», а «какой проверки не было».
3. **Какая проверка поймала бы это автоматически.** И сразу завести на неᑑ задачу.
Для того инцидента ответ на третий пункт — проверка в конвейере, которая не пускает в бой compose-файл с прокинутым портом базы:
```bash
# в простейшем виде — одна строка в конвейере
grep -nE '^\s*-\s*"?[0-9]+:(5432|6379|3306|27017)"?' docker-compose.yml && exit 1
```
Такая строка полезнее любого вывода о том, кто виноват.
## ШпаргалкаRemoved
## Шпаргалка
```bash
# есть ли история
git rev-parse --is-shallow-repository
git fetch --unshallow
# когда появилась строка
git log -S'строка' --format='%h %ad %an %s' --date=short
git log -G'регулярка' --oneline
# история файла
git log --oneline --follow -- путь
# состояние на момент
git show <sha>:путь # файл целиком
git show <sha> -- путь # только дифф
git show --stat <sha> # что ещё ехало рядом
# построчно
git blame -w -C -C -L 40,55 путь
# если строки нет
git bisect start / bad / good / run ./check.sh / reset
```