Git: 브랜치 삭제, 머지, 그리고 잘못된 푸시 되돌리기
August 2, 2026 · – 방문자
이 세 가지는 항상 일어나는 일인데, 이상하게도 명령어들이 매번 머릿속에 제대로 붙어 있질 않는다. 그래서 여기 제대로 정리해 둔다.
브랜치 삭제하기
git branch -d feature-x
이건 안전한 버전이다 — Git이 먼저 확인해서, feature-x에 현재 브랜치로 아직 들어오지 않은 커밋이 있으면 거부한다. 확실하다면 강제로 진행할 수 있다 (1).
git branch -D feature-x
다만 이건 로컬에서만 삭제된다. 원격(GitHub 같은 곳)에도 브랜치가 있다면 거기서도 따로 삭제해야 한다.
git push origin --delete feature-x
알아두면 좋은 게 하나 있다. 브랜치를 삭제해도 그 안의 커밋들이 실제로 사라지는 건 아니다. 그냥 참조가 끊긴 채로 저장소에 남아 있다가, Git의 가비지 컬렉터가 언젠가 정리해 가는데 이게 꽤 오래 걸릴 수 있다. 그래서 git branch -D는 보기보다 관대한 명령이다 — 엉뚱한 브랜치를 지웠더라도 대개 돌아갈 방법이 남아 있다(아래 리플로그 부분에서 더 다룬다). 이걸 계획으로 삼고 싶진 않지만, 그런 안전망이 있다는 건 알아두면 좋다.
브랜치 머지하기
보통의 흐름은 이렇다. 머지해서 들어갈 브랜치로 체크아웃한 다음, 다른 브랜치를 그 안으로 머지한다.
git checkout main
git merge feature-x
그다음에 무슨 일이 일어나는지는 브랜치를 딴 이후로 main이 움직였는지에 달려 있다. 움직이지 않았다면 Git은 그냥 main 포인터를 feature-x에 맞춰 앞으로 밀어준다 — 이게 패스트 포워드이고, 머지 커밋은 생기지 않는다. 그사이 main이 움직였다면 Git은 두 히스토리를 묶어주는 실제 머지 커밋을 만든다 (2).
패스트 포워드가 가능한 상황에서도 머지 커밋을 원할 때가 있다 — 변경 사항이 조용히 스며드는 대신, 피처 브랜치가 존재했고 머지되었다는 흔적을 히스토리에 눈에 띄게 남겨주기 때문이다. 그럴 때는 이렇게 한다.
git merge --no-ff feature-x
양쪽에서 같은 줄을 건드렸다면 Git은 멈추고 충돌을 직접 해결하도록 남겨둔다.
git status
그러면 어떤 파일이 충돌 상태인지 목록으로 보여준다. 각 파일을 열어보면 서로 경쟁하는 변경 사항 주위에 <<<<<<<, =======, >>>>>>> 마커가 보일 것이다 — 실제로 남길 내용을 고르고, 마커를 지운 다음 이렇게 한다.
git add resolved-file.txt
git commit
그리고 감당할 가치가 없을 만큼 엉망이 됐다면, 그냥 전부 없던 일로 하고 물러날 수도 있다.
git merge --abort
그러면 머지를 시작하기 전 상태로 정확히 되돌아간다.
잘못된 푸시 되돌리기
사람들이 제일 당황하는 상황인데, 솔직히 그 당황은 대개 불필요하다 — 다만 여기서는 어떤 해결책을 쓰느냐가 실제로 중요하다.
누군가 이미 그 브랜치를 풀했을 가능성이 조금이라도 있다면, 히스토리를 건드리지 마라. 대신 이전 커밋을 취소하는 새 커밋을 추가한다.
git revert <bad-commit-sha>
git push
지루하지만 언제나 안전한 방법이다. 아무것도 다시 쓰지 않는다 — 그냥 실수를 상쇄하는 커밋을 위에 하나 얹을 뿐이라서, 다른 사람들이 각자 뭔가 특별한 걸 하지 않아도 모두의 히스토리가 그대로 맞아떨어진다 (3).
그 브랜치가 정말로 나 혼자만의 것이고 아직 아무도 풀하지 않았다면, 되감아서 다시 쓸 수 있다 (4).
git reset --hard <last-good-commit-sha>
git push --force-with-lease
다른 이유가 없더라도 습관적으로 그냥 --force 대신 --force-with-lease를 쓰자. 그 차이는 보이는 것보다 훨씬 중요하다. --force-with-lease는 마지막으로 페치한 이후 다른 누군가가 그 브랜치에 푸시하지 않았는지 확인하고, 만약 그랬다면 거부한다. 반면 그냥 --force는 아무것도 확인하지 않는다 — 경고 한 마디 없이 다른 사람의 작업을 태연하게 덮어써 버린다 (5).
그리고 마지막으로 멀쩡했던 커밋이 뭐였는지 기억해 내려고 터미널만 노려보고 있다면 — git log는 여기서 도움이 안 된다. 지금 위치에서 도달 가능한 커밋만 보여주는데, 이미 리셋으로 벗어난 커밋은 여기 포함되지 않기 때문이다. 필요한 건 이거다.
git reflog
이건 브랜치가 최근에 가리켰던 모든 위치를 보여준다, 일반적인 히스토리에서 빠져나간 것들까지 포함해서. 일이 잘못되기 전 시점까지 거슬러 올라간 다음 이렇게 한다 (6).
git reset --hard HEAD@{2}
(실제 상황에 맞는 위치나 SHA로 바꿔 넣으면 된다.) 리플로그는 각자의 컴퓨터에만 로컬로 존재하고 보통 약 90일 정도 기록을 유지하는데, 그러니 이건 "잘못된 푸시를 위한 긴급 되돌리기"라기보다는 "방금 뭔가 망가뜨린 것 같다"에 대한 일반적인 안전망에 가깝다 — 이 상황이 아니더라도 존재한다는 걸 기억해 둘 가치가 있다.
마치며
이 세 가지는 모두 같은 사실에 기대고 있다. Git은 거의 무엇도 즉시 버리지 않는다. 삭제된 브랜치, 리셋된 커밋, 브랜치의 예전 위치들 — 이 모두가 보이는 것보다 오래 남아 있다. 그게 바로 -D, reset --hard, 강제 푸시를 일상적으로 써도 충분히 안전하게 만들어주는 이유다, 실수였다는 게 드러났을 때 어디를 찾아봐야 하는지만 알고 있다면.
관련 글
- Make 이해하기 — 실제로 재빌드를 유발하는 것
더 읽을거리
- git-branch — 브랜치 생성, 목록 확인, 삭제.
- git-merge — 머지 전략과 충돌 해결.
- git-revert — 새 커밋을 만들어 이전 커밋을 취소하는 방법.
- git-reset — 브랜치 포인터 이동,
--soft,--mixed,--hard의 차이. - git-push: --force-with-lease — 왜
--force보다 안전한지. - git-reflog — 일반 히스토리에 더 이상 나타나지 않는 커밋을 복구하는 법.
댓글