AI에게 작업을 맡긴 후,
git push나 git commit이 멈추는 경우가 있습니다. 멈췄을 때는 출력의 첫 번째 줄에 원인이 적혀 있습니다. 여기서는 막히기 쉬운 3가지 상황을 임시 리포지토리에서 재현하고, 출력을 읽어 해결하는 절차를 정리했습니다.
예상 독자: Cursor나 Claude Code 등으로 작업한 후, Git 출력을 건너뛰기 쉬운 엔지니어
연결: 에이전트에게 맡기기 전 지켜야 할 3가지 수칙 | 읽히게 하지 않기 · 되돌릴 수 있게 하기 · 넣기 전에 보기
결론
세 경우 모두 출력의 첫 번째 줄에서 원인을 알 수 있습니다.
| 출력의 첫 번째 줄 | 원인 | 해결 방법 |
|---|
! [rejected] main -> main (fetch first) | 리모트에 로컬에 없는 커밋이 있음 | git pull --rebase origin main → git push origin main |
Author identity unknown | user.name과 user.email이 어디에도 없음 | git config user.name과 user.email을 설정합니다. |
hint: ... hook was ignored because it's not set as executable. | hook에 실행 권한이 없음 | chmod +x .git/hooks/pre-commit |
세 번째 경우만 오류가 나지 않습니다. hint가 한 줄 나오고 커밋은 통과합니다. 멈추지 않기 때문에 알아차리기 쉽지 않습니다.
본 기사의 출력은 모두 box의 /tmp에서 재현한 것입니다. AI가 실제로 어떻게 조작했는지는 보지 않았으므로, 'AI가 이렇게 했다'라고 쓰지 않습니다. AI 작업 후에 발생하기 쉬운 상황으로 나열하고 있습니다.
재현 전제 조건
- git 버전은
git version 2.47.3
- 리모트는 같은 머신에 만든 로컬의 bare 리포지토리입니다. 외부에는 아무것도 push하지 않았습니다.
- 이름과 이메일은 설명용 더미(Taro Demo / [email protected])이며, 출력의 호스트명과 사용자명은 가림 처리했습니다.
막힘 1: push가 거부될 때
출력
자신의 커밋을 만든 후, 리모트에 다른 커밋이 먼저 있는 상태에서 push를 했습니다.
$ git push origin main
To ../remote.git
! [rejected] main -> main (fetch first)
...
읽어야 할 것은 (fetch first)와 hint의 첫 번째 줄입니다. 리모트에 로컬에 없는 작업이 있습니다. 그대로 덮어쓰지는 않습니다.
히스토리는 갈라져 있었습니다.
$ git fetch && git log --oneline --graph --all
* c737d9d B: AI work
| * 18cc320 A: remote edit
...
B: AI work이 로컬의 커밋이고, A: remote edit가 리모트에 있는 커밋입니다.
해결 방법
git pull --rebase로 상대방의 변경 사항을 아래에 깔고, 자신의 커밋을 위에 다시 올립니다.
$ git pull --rebase origin main
From ../remote
* branch main -> FETCH_HEAD
...
B: AI work이 A: remote edit 위에 놓였고, push가 통과했습니다.
충돌 시 되돌리기
같은 파일 c.txt를 리모트와 로컬 양쪽에서 만든 후 git pull --rebase를 했습니다.
$ git pull --rebase origin main
From ../remote
* branch main -> FETCH_HEAD
...
이때, git status -sb의 첫 번째 줄은 ## HEAD (no branch)였고, c.txt는 AA (양쪽에서 추가)였습니다. 감당하기 어려우면, git rebase --abort로 되돌립니다.
$ git rebase --abort
exit=0
$ git log --oneline -1
...
B2가 원래의 main
원래 상태로 돌아갔다. 공식 문서에 따르면, 병합(merge)이나 리베이스(rebase) 도중에 충돌을 처리하고 싶지 않을 때는 git merge --abort나 git rebase --abort를 사용해 안전하게 중단할 수 있다 (git-pull).
주의사항
같은 문서에서 --rebase는 '히스토리를 덮어쓰기 때문에 이미 공개된 히스토리에는 적합하지 않다'고 경고하고 있다. 다른 사람과 공유하는 브랜치에서 push된 커밋에 사용하는지는 팀의 결정에 따른다. 여기서 재현한 것은 자신의 미-push 커밋 하나뿐이다 - git push --force는 사용하지 않는다. 여기서는 덮어쓰기 출력을 보고 있지 않다. 거부는 상대방의 작업을 지우지 않기 위한 멈춤 방식이라고 해석한다 - 옵션을 붙이지 않은 git pull origin main으로도 막혔다. 원격에 다른 커밋이 들어온 상태에서 실행했을 때 다음과 같았다.
$ git pull origin main
From ../remote
* branch main -> FETCH_HEAD
...
--rebase (또는 --no-rebase, --ff-only)를 붙여서 가져오는 방식을 지정한다.
막힘 2: Author identity unknown
출력
이름과 이메일을 설정하지 않은 환경(빈 홈 폴더)에서 git commit을 했다.
$ git config user.name; git config user.email
exit=1
exit=1
...
git config user.name과 user.email은 값이 없으면 종료 코드 1을 반환했다. 여기가 그대로 '미설정' 확인이 된다.
마지막 줄의 got '...'에는 실행한 환경의 사용자명과 호스트명이 들어간다. 위의 출력은 그 부분을 <user>@<host>로 대체한 것이다. 로그나 화면을 사람에게 보여줄 때는 이 줄에 주의해야 한다.
공식 문서에 따르면, git은 이름과 이메일을 환경 변수, user.name과 user.email, 환경 변수 EMAIL, 시스템의 사용자명과 호스트명 순서로 찾는다 (git-commit). 이것들 모두 사용할 수 없으면 이 Author identity unknown에서 멈춘다.
해결 방법
$ git config --global user.name
)。나온 것은 힌트가 단 2줄뿐이었다. 공식 문서에도 “실행 비트가 설정되지 않은 hook은 무시된다”고 되어 있다 (githooks).
### 수정하기
$ chmod +x .git/hooks/pre-commit
$ ls -l .git/hooks/pre-commit
-rwxr-xr-x .git/hooks/pre-commit
...
이번에는 멈췄고, 두 번째 커밋은 만들어지지 않았다.
### hint를 지우면 알아차리기 어렵다
hint는 `advice.ignoredHook`
으로 지울 수 있다. 실행 권한이 없는 상태로 지우고 커밋했다.
$ git -c advice.ignoredHook=false commit -m z
[main 162fcd8] z
1 file changed, 1 insertion(+)
...
경고는 전혀 나오지 않았고, hook은 작동하지 않았다. hook을 넣었는데도 멈추지 않는 때는, 먼저 `ls -l`
으로 `x`
이 붙어 있는지 확인해야 한다.
### hook이 보이는지 확인하기
`git hook run`
을 사용하면 커밋을 만들지 않고 hook의 상태를 확인할 수 있다. 실행 권한을 제거한 상태에서는 다음과 같았다.
$ git hook run pre-commit
hint: The '.git/hooks/pre-commit' hook was ignored because it's not set as executable.
hint: You can disable this warning with git config advice.ignoredHook false.
...
`cannot find a hook named pre-commit`
이 나오면, git에서 hook을 보고 있지 않은 것이다. `sh .git/hooks/pre-commit`
처럼 직접 실행하면 권한이 없어도 내용은 작동한다 (`BLOCK:`
이 나오고 `exit=1`). 이 확인에서는, git의 경로를 거치지 않았다는 점에 주의해야 한다.
### 주의사항
- 실행 권한을 부여해도,
`git commit --no-verify`
하면 `pre-commit`은 건너뛸 수 있다. 실제로 `git commit --no-verify -m nv`
는 커밋이 통과했다 (`exit=0`). 공식 문서에도 쓰여 있다 -
`.git/hooks/`
안의 내용은, clone 시에는 배포되지 않는다. hook을 넣은 리포지토리를 clone하여 `ls .git/hooks`
으로 `pre-commit`
을 찾아봤지만, 발견할 수 없었다 (`.sample`만). 다른 머신에서는, hook을 다시 넣어주고 `chmod +x`
하는 -
`100755`
로 기록된 파일을 clone했을 때의 권한은, 확인하지 않았다.
## 요약

| 막힘 | 출력 단서 | 해결 방법 | 놓치기 쉬운 점 |
|---|---|---|---|
| push 거부 | `! [rejected] ... (fetch first)` |`git pull --rebase origin main` → `git push origin main` |
옵션 없는 `git pull origin main`도 막힌다. 충돌은 `git rebase --abort`로 되돌릴 수 있다 |
| 이름 미설정 | `Author identity unknown` |`git config user.name` / `user.email` |
마지막 줄에 사용자명과 호스트명이 나온다. `--global`의 유무에 따라 범위가 달라진다 |
| hook이 작동 안 함 | `hook was ignored because it's not set as executable` |`chmod +x .git/hooks/pre-commit` | 오류가 나지 않고, 커밋이 통과한다. hint를 지우면 알아차리기 어렵다 |
## 맺음말
git이 멈추면, 먼저 출력의 첫 줄을 읽는다. `rejected`
, `Author identity unknown`
, `ignored`
중 어느 것인지에 따라, 이 기사의 세 가지 중 하나일 것이다.
hook을 사용하는 운영이라면, 딱 한 가지만 오늘 해두자. `ls -l .git/hooks/`
으로, 사용하고 싶은 hook에 `x`
이 붙어 있는지 확인하는 것이다. 붙어 있지 않아도, 커밋은 통과한다.
**계속되는 형식은 책에**
AI를 사용하는 업무에서, 품질과 단가를 지키는 형식(패턴)은 책으로 정리했다.
### 논의 (Discussion)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51