로컬 브랜치를 원격과 완전히 같게 만들려면 두 단계다.
git fetch origin
git reset --hard origin/development
git pull 이 아니라 fetch + reset --hard 인 이유는, pull 은 병합이나 리베이스를 시도하므로 충돌이 나고 로컬 커밋이 남기 때문이다. reset --hard 는 브랜치 포인터를 원격 위치로 옮기고 작업 트리도 그 시점으로 덮는다.
되돌릴 수 없는 것이 함께 사라진다. 커밋하지 않은 변경, 스테이징한 변경, 로컬에만 있던 커밋이 모두 없어진다. 실행 전에 확인한다.
git status
git log --oneline origin/development..HEAD # 로컬에만 있는 커밋
git stash push -u -m "reset 전 임시 보관" # 남겨 둘 것이 있으면
추적되지 않는 파일은 reset --hard 로 지워지지 않는다. 완전히 깨끗하게 하려면 별도로 지운다. -n 으로 먼저 무엇이 지워질지 본다.
git clean -nd
git clean -fd
.gitignore 에 걸린 파일까지 지우려면 -x 를 더한다. 로컬 설정 파일이나 빌드 캐시가 함께 사라지므로 신중히 쓴다.
실수로 reset --hard 했더라도 커밋된 내용은 대개 살릴 수 있다.
git reflog
git reset --hard HEAD@{3}
커밋하지 않았던 변경은 reflog 로도 못 살린다.
.gitignore 는 추적되지 않는 파일에만 적용된다. 이미 한 번 커밋되어 추적 중인 파일은 나중에 무시 목록에 넣어도 계속 추적된다.
git check-ignore -v path/to/file # 어느 규칙에 걸리는지 확인
git ls-files --error-unmatch path/to/file # 추적 중이면 경로를 출력한다
추적에서 빼되 파일은 남기려면 다음을 쓴다.
git rm --cached path/to/file
git rm -r --cached build/
git commit -m "chore: 빌드 산출물 추적 제외"
--cached 를 빠뜨리면 실제 파일도 지워진다.
이 커밋 이후 다른 개발자가 pull 하면 그쪽의 해당 파일도 삭제된다는 점을 알려 둔다. 설정 파일처럼 각자 들고 있어야 하는 것이라면 config.yaml.example 을 추적하고 실제 파일은 무시하는 구조로 바꾼다.
이미 커밋된 비밀 값은 추적만 끊어서는 이력에 남는다. 이력에서 지우려면 git filter-repo 등으로 다시 쓰고, 무엇보다 그 자격증명을 폐기하고 새로 발급한다.
remote: GitLab: You are not allowed to push code to protected branches on this project.
main · master 같은 브랜치가 보호 설정으로 직접 푸시가 막혀 있다는 뜻이다. 권한 문제가 아니라 정책이며, 정상 동작이다.
작업 브랜치를 만들어 올리고 병합 요청으로 합치는 것이 정해진 경로다.
git switch -c feature/xxx
git push -u origin feature/xxx
정말로 직접 푸시해야 한다면 프로젝트 설정의 Settings > Repository > Protected branches 에서 해당 브랜치의 Allowed to push 에 역할이나 사용자를 추가한다. Maintainer 이상 권한이 필요하다.
푸시는 되는데 강제 푸시만 막히는 설정도 있다. 이 경우 Allow force push 를 별도로 켜야 한다. 보호를 푼 채로 두지 말고 작업이 끝나면 되돌린다.