Skip to content
isdnetworks
Go back

커밋에 남의 작업이 딸려 들어갔다

개발 서버 한 대에서 여럿이 같은 폴더를 고치고 있었다. 거기서 커밋하니 내가 안 만진 파일이 같이 들어갔다.

Table of contents

Open Table of contents

증상 — 무엇이 들어갔는지 봤다

커밋에 무엇이 담겼는지 뽑았다.

$ git show --stat HEAD
 app/Http/Controllers/OrderController.php  |  42 +++--
 app/Services/FeeService.php               |  18 ++-
 resources/views/product/edit.blade.php    | 210 ++++++++++++++++++
 config/queue.php                          |   6 +-

edit.blade.phpqueue.php 는 내가 안 만졌고 다른 사람이 작업 중이던 것이었다.

git add . 을 했기 때문인데 공용 폴더에서 그 명령은 누가 만든 것이든 그 시점의 모든 변경을 담는다.

딸려 온 것 중에는 아직 동작하지 않는 중간 상태도 있어서 그대로 두면 다음 사람이 그 상태를 기준으로 작업하게 된다.

edit.blade.php 는 210줄이 통째로 들어간 새 파일이었다. 작업하던 사람은 아직 올릴 생각이 없었을 것이다.

조치 — 되돌리는 커밋으로

이미 올라가 남이 받아 간 뒤였다.

$ git revert --no-commit HEAD
$ git checkout HEAD -- app/Http/Controllers/OrderController.php app/Services/FeeService.php
$ git commit -m "다른 작업 파일이 섞여 들어간 것을 되돌린다"

git revert 뒤에 git checkout HEAD -- 로 내 파일 둘은 되살리고 나머지만 되돌렸다.

rebase--amend 로 이력을 고치는 방법도 있지만 이미 pull 해 간 것이라 쓰면 안 됐다. 받아 간 쪽의 기준이 사라지면 다음 병합에서 문제가 더 커진다.

이력이 지저분해지는 것과 남의 기준이 무너지는 것 중에서 이력이 지저분해지는 쪽을 골랐다.

되돌리는 커밋은 무엇이 왜 되돌려졌는지가 이력에 남는다는 이점도 있다. 이력을 고쳐 쓰면 그 사고가 있었다는 사실 자체가 사라진다.

담을 것을 지정하게 바꿨다

바로 할 수 있는 조치는 담을 것을 매번 적는 것이었다.

$ git add app/Http/Controllers/OrderController.php app/Services/FeeService.php
$ git commit

git add. 을 안 쓰고 파일 이름을 매번 적는다.

담기 전에 목록을 보는 것도 붙였다.

$ git status -s
 M app/Http/Controllers/OrderController.php
 M app/Services/FeeService.php
 M resources/views/product/edit.blade.php 남의

git status -s 목록을 커밋 전에 보는 것을 습관으로 뒀다.

다만 이것은 조심으로 막는 방식이라 언젠가 다시 나는데 급할 때는 확인을 건너뛰고 새로 온 사람에게는 그 습관이 없다.

한 사람이 규칙을 지켜도 같은 폴더를 쓰는 다른 사람이 안 지키면 소용이 없다. 공용 자리에서는 규칙이 전원에게 동시에 지켜져야 효과가 난다.

원인 — 공용 폴더라는 구조

근본은 개발 서버의 한 폴더를 여럿이 함께 고치고 있다는 구조 쪽이었다.

개발자 각자    로컬 작업 공간 + 자기 브랜치
개발 서버      배포된 것만. 여기서 파일을 고치지 않는다

각자 자기 feature/ 에서 작업하고 개발 서버에는 배포된 것만 있게 했다.

개발 서버에서 직접 고치는 것이 편해서 그렇게 하고 있었는데 편한 만큼 섞였고 그 편의를 포기해야 사고가 없어진다.

고치고 바로 화면에서 확인할 수 있다는 것이 그 편의의 실체였다. 각자 자리에서 작업하면 그 확인에 한 단계가 더 붙는다.

조심으로 막는 문제는 구조로 막아야 다시 안 난다.

설정 — 브랜치 규칙과 배포 표시

각자 feature/ 를 쓰기로 하니 이름과 병합 규칙이 함께 필요했다.

master          배포된 것
develop         다음 배포 대상
feature/<작업>  각자 작업
hotfix/<작업>   급한 수정. master에서 갈라져 master와 develop 둘 다로 간다
$ git checkout -b feature/order-fee develop
...
$ git push -u origin feature/order-fee

develop 으로 병합할 때는 요청을 올려 한 사람이 더 보고 넣기로 했다.

혼자 넣으면 이번 같은 것이 그대로 통과한다. 보는 사람이 하나 더 있으면 남의 파일이 섞인 것은 대개 그 자리에서 걸린다.

여럿이 고치던 때는 개발 서버가 어느 판을 물고 있는지 아무도 몰랐다.

$ cat /srv/app/REVISION
develop@8f2a1c3  2018-06-10 13:20  by jenkins

REVISION 에 배포할 때마다 남기고 화면에서도 보이게 했다.

내 코드가 올라갔느냐고 묻지 않고 보게 됐고 구조를 바꾸면 그에 딸린 규칙과 표시가 함께 따라온다.

검증 — 서버에서 고친 것 잡기

규칙을 정해도 급하면 서버에서 고친다.

$ cd /srv/app && git status --porcelain
 M app/Services/FeeService.php

서버에서 고친 것이 다음 배포에 조용히 덮여 사라지는 것이 문제였다.

if [ -n "$(git status --porcelain)" ]; then
    echo "서버에서 직접 고친 파일이 있습니다:"; git status --porcelain; exit 1
fi

git status --porcelain 이 비어 있지 않으면 배포가 멈춘다.

일부러 파일 하나를 고쳐 놓고 이 검사가 멈추는지 봤는데 안 멈추면 그 검사는 아무것도 안 하는 것이다.

멈추는 것을 확인하고 나서야 그 검사를 믿을 수 있었다. 통과만 보고 작동한다고 판단하면 있으나 마나 한 것을 그대로 두게 된다.

정리


Share this post on:

Previous Post
태그가 유일한 비용 손잡이다
Next Post
그 오류는 우리 것이 아니었다