작업하던 로컬 디렉터리를 새로 만든 원격 저장소에 올리려고 한다. 원격에는 생성 시 만들어진 README.md 가 이미 하나 있고, 로컬에도 다른 내용의 README.md 가 있다. 이 상태에서 푸시하면 거절당한다.
! [rejected] main -> main (fetch first)
error: failed to push some refs to '...'
이어서 git pull 을 하면 다음이 난다.
fatal: refusing to merge unrelated histories
가장 단순한 경우다. 순서대로 하면 된다.
cd /path/to/project
git init
git branch -M main
git add .
git commit -m "초기 커밋"
git remote add origin ssh://git@git.example.com:2222/team/app.git
git push -u origin main
git init 의 기본 브랜치 이름은 git 2.28 부터 설정으로 바꿀 수 있다. 한 번 정해 두면 git branch -M 을 매번 칠 필요가 없다.
git config --global init.defaultBranch main
main 과 master 는 이름만 다른 평범한 브랜치다. 기능 차이는 없고, 원격이 기대하는 이름에 맞추면 된다. 원격의 기본 브랜치는 다음으로 확인한다.
git ls-remote --symref origin HEAD
로컬과 원격이 서로 다른 뿌리에서 시작했으므로 git 은 둘을 무관한 이력으로 본다. 그래서 병합을 거부한다. 두 이력을 합치겠다고 명시하면 된다.
git remote add origin ssh://git@git.example.com:2222/team/app.git
git fetch origin
git pull origin main --allow-unrelated-histories
# README.md 충돌 해결
git add README.md
git commit
git push -u origin main
충돌은 README.md 한 파일에서만 난다. 파일을 열면 양쪽 내용이 표시자와 함께 들어 있으므로, 남길 내용만 남기고 표시자를 지운다.
<<<<<<< HEAD
로컬 내용
=======
원격 내용
>>>>>>> origin/main
원격의 README.md 가 저장소를 만들 때 자동 생성된 것이고 지킬 가치가 없다면, 로컬 이력으로 덮어써도 된다.
git push -u origin main --force
--force 는 원격의 커밋을 지운다. 다른 사람이 이미 그 원격에서 클론했다면 쓰지 않는다. 방금 만든 빈 저장소일 때만 안전하다. 조금이라도 불확실하면 --force-with-lease 를 쓴다. 내가 마지막으로 본 상태에서 원격이 바뀌었으면 거절한다.
git push -u origin main --force-with-lease
원격에 나보다 앞선 커밋이 있을 때다. 순서로 정리하면 이렇다.
작업하고 커밋한다. 푸시한다. 거절당하면 그때 pull 하고 다시 푸시한다. 여러 사람이 같은 브랜치를 쓴다면 작업을 시작하기 전에도 한 번 당긴다.
이력을 한 줄로 유지하고 싶으면 병합 대신 리베이스를 쓴다.
git pull --rebase origin main
기본 동작을 정해 두면 git pull 이 경고를 내지 않는다.
git config --global pull.rebase false # 병합
git config --global pull.rebase true # 리베이스
git add . 을 치기 전에 .gitignore 를 만든다. 한번 올라간 파일은 이력에 남아 나중에 지워도 이력에서는 사라지지 않는다.
.env
*.key
*.pem
__pycache__/
.venv/
node_modules/
*.log
data/
이미 커밋해 버렸다면 추적만 끊는다. 비밀 값이 올라갔다면 추적을 끊는 것으로는 부족하고, 그 값을 즉시 폐기하고 새로 발급해야 한다.
git rm --cached .env
echo '.env' >> .gitignore
git commit -m "환경 파일 추적 제외"
연결과 상태를 본다.
git remote -v
git branch -vv
git log --oneline --graph --all -n 20
git status --short