개발/Git

Private GitLab에서 다른 서버(GitHub 또는 Gitlab)로 옮기다 push가 막혔을 때 내가 배운 것

데이터분석뉴비 2025. 12. 15. 20:53
728x90

사내에서 Gitlab을 사용중인데, 잠시 서버가 내려가 다른 쪽에 코드를 옮길 때 당황했던 경험을 오늘 하여 내용을 정리해보고자 한다.

물론 실 사례 내용은 적기가 애매하여 대략적인 상황을 작성하고 개념에 대한 내용과 그래서 앞으로 어떻게 할 지에 대해서 정리해보겠습니다.

 

상황 정리

  • 기존에 잘 쓰던 Git 서버(GitLab 등)가 내려갔다
  • 새로 배포해야 할 최종 코드가 로컬에 있다
  • Git으로 관리 중이었고, 아직 push 하지 못한 커밋들이 있다
  • 목표는 새로운 Git 서버(GitHub)에 코드를 올리고 main에 merge하는 것

이 상태에서 초보자가 가장 많이 하는 실수는
“push부터 어떻게 할지”를 먼저 고민하는 것이다.

하지만 이 상황에서 제일 중요한 건 push가 아니다.

 

1. 이 상황에서 가장 먼저 확인해야 할 것

❗ 로컬 코드가 “Git에 저장돼 있는가?”

여기서 말하는 저장은:

  • ❌ push
  • commit

즉, 지금 확인해야 할 질문은 이거다.

“내가 수정한 코드들이
전부 커밋으로 남아 있는 상태인가?”

git status
git log --oneline

 

 

  • git status에 변경 사항이 남아 있다면
    아직 안전하지 않다
  • 커밋으로 남아 있다면
    → 서버가 없어도 코드는 살아 있다

 

2. 아직 push 못 한 코드가 있다면, 가장 먼저 할 일

이 상황에서의 정답 행동은 하나뿐이다.

“어디로 push할지 고민하기 전에
일단 커밋으로 고정한다.”

 

git add .
git commit -m "WIP: local changes before server migration"

이 커밋은:

  • 배포용이 아니어도 되고
  • 메시지가 정리돼 있지 않아도 된다

목적은 단 하나다.

“이 상태를 Git이 기억하게 만든다.”

이걸 해두면:

  • 서버 이전 작업 중 실수해도
  • 브랜치를 바꿔도
  • remote 설정을 잘못해도

코드는 복구 가능 상태다.

 

3. 그 다음에야 “새 서버로 어떻게 옮길지”를 결정한다

로컬 코드가 커밋으로 안전하게 고정된 상태라면
이제서야 다음 질문을 할 수 있다.

“이 커밋들을 그대로 새 GitHub에 옮길 것인가, 아니면 코드 상태만 옮길 것인가?”

이 선택에 따라 전략이 갈린다.

구분 커밋 이력 그대로 옮길 경우 코드 상태만
이전 대상 모든 커밋 히스토리 현재 로컬 코드 상태
과거 커밋 포함 O (전부 포함) X
실패 가능성 높음 매우 낮음
GitHub 정책 영향 큼 (용량·보안 등) 거의 없음
대용량 파일 문제 자주 발생 거의 발생 안 함
초보자 난이도 높음 낮음
이전 속도 느림 빠름
심리적 안정감 낮음 높음
서버 장애 대응 부적합 적합
main merge 용이성 상황에 따라 다름 매우 쉬움

 

4. 초보자 기준으로 가장 안전한 기본 전략

이런 상황에서는 보통 이 선택이 가장 안전하다.

“새 GitHub 서버에는 ‘현재 코드 상태’를 기준으로 새로운 히스토리를 만든다.”

즉,

  • 기존 서버의 커밋 이력은 참고용으로 두고
  • 새 서버에서는 새 출발

이 방식은:

  • 서버 정책 차이(GitLab ↔ GitHub)
  • 과거 커밋에 섞인 문제 요소
  • 대용량 파일 이슈 (100MB 넘을 경우)

같은 변수들을 한 번에 제거해준다.

 

4-1. 안전한 기본 전략을 실제로 실행하는 순서

전제 상황은 이거다.

  • Private GitHub Repository가 이미 생성됨
  • GitHub SSH 주소도 발급됨
    예: git@github.com:my-org/my-project.git
  • 로컬에는 배포해야 할 최종 코드가 있고, 커밋까지 완료된 상태
  • 기존 GitLab 서버는 더 이상 신뢰하기 어려움

목표는 단순하다.

“현재 코드 상태를 기준으로
GitHub에서 새로운 히스토리를 시작하고
main에 반영한다.”

 

1️⃣ 먼저 GitHub remote를 추가한다

기존 GitLab remote는 그대로 둬도 된다.
우리는 새 출발용 remote를 하나 더 추가한다.

git remote add github git@github.com:my-org/my-project.git

 

git remote -v

 

origin   git@gitlab.company.com:old/project.git (fetch)
origin   git@gitlab.company.com:old/project.git (push)
github   git@github.com:my-org/my-project.git (fetch)
github   git@github.com:my-org/my-project.git (push)

 

여기까지는 아직 아무 것도 GitHub에 안 올라갔다
(remote는 “연결 정보”일 뿐이다)

 

2️⃣ GitHub 기준으로 깨끗한 브랜치를 만든다

이 단계가 이 전략의 핵심이다.

GitHub의 main을 기준으로 완전히 새로운 브랜치를 만든다.

git fetch github
git checkout -b import-from-gitlab github/main

 

이 브랜치의 의미는 이거다.

“GitHub가 이해할 수 있는
깨끗한 히스토리에서 시작한다”

  • 과거 GitLab 커밋 ❌
  • 대용량 파일 히스토리 ❌
  • 정책 충돌 요소 ❌

3️⃣ 기존 브랜치에서 “파일 상태만” 가져온다

이제 핵심 동작이다.

git checkout old-gitlab-branch -- .

 

이 명령이 의미하는 바는 정확히 이거다.

  • 커밋 이력 ❌
  • 브랜치 히스토리 ❌
  • 현재 파일 내용만 ⭕

즉,

“old-gitlab-branch의 결과물만 지금 브랜치에 복사한다”

조합하면 이렇게 된다.

“old-gitlab-branch에 있는
모든 파일 상태를
현재 브랜치의 워킹 디렉토리에 덮어써라.”

 

 

 

4️⃣ 혹시 모를 대용량 파일을 한 번 더 점검한다

GitHub 이전에서 이 단계는 안전벨트다.

git status
 

불필요한 대용량 파일이 보이면:

git rm --cached path/to/large-file.zip

그리고 .gitignore에 추가:

*.zip 
*.tar 
*.model

 

5️⃣ 이 상태를 첫 커밋으로 만든다

이 커밋이 GitHub에서의 시작점이다.

git add .
git commit -m "import: initial snapshot from GitLab"

이 커밋의 의미는 명확하다.

“이 시점의 코드 상태가
GitHub에서의 최초 버전이다”

 

 

6️⃣ 이제 GitHub로 push 한다 (거의 실패하지 않는다)

git push -u github import-from-gitlab

이 시점에서:

  • 과거 문제 커밋 ❌
  • GitHub 정책 위반 ❌
  • push 실패 가능성 ❌

7️⃣ GitHub에서 main에 merge 한다

이제 GitHub UI에서:

  • import-from-gitlab → main
  • Pull Request 생성
  • 코드 확인 후 merge

혹은 로컬에서 바로 하고 싶다면:

git checkout main
git pull github main
git merge import-from-gitlab
git push github main

 

 

 

배울점

1️⃣ push는 저장이 아니라 “복사”다

  • ❌ push를 해야 코드가 안전해진다
  • commit만 되어 있으면 코드는 이미 안전하다

push는 로컬 커밋을 원격 서버로 복사하는 행위일 뿐이다.
서버가 없어도, push를 못 해도 커밋은 로컬에 남아 있다.


2️⃣ Git은 “파일”이 아니라 “커밋 그래프”를 관리한다

  • ❌ 지금 파일에 뭐가 있느냐
  • 과거 커밋에 무엇이 있었느냐

그래서:

  • 대용량 파일을 지금 지워도
  • 과거 커밋에 있으면
  • GitHub push는 계속 막힌다

3️⃣ 브랜치를 새로 만든다고 히스토리가 사라지지 않는다

git checkout -b new-branch
 

이건:

  • 히스토리를 새로 만드는 게 아니라
  • 기존 커밋 그래프 위에 포인터 하나를 더 얹는 것

그래서:

  • 문제 커밋도
  • 대용량 파일 이력도
  • 그대로 따라온다

4️⃣ “코드 상태만 옮긴다”는 건 Git에서 가능한 공식적인 방법이다

git checkout old-branch -- .

이 명령은:

  • 브랜치 이동 ❌
  • merge ❌
  • rebase ❌
  • 파일 내용만 복사 ⭕

즉:

히스토리를 버리고 결과물만 가져오는,
Git이 허용하는 정상적인 전략


5️⃣ commit 안 된 변경 사항은 어떤 전략으로도 보호되지 않는다

  • commit ❌
  • stash ❌
  • 백업 ❌

이 상태에서:

  • 브랜치 이동
  • reset
  • checkout

코드 날아간다

그래서 서버 이전에서 제일 먼저 할 일은 항상:

git commit

 

6️⃣ remote는 “이름”이 아니라 “다른 세계”다

origin  → GitLab
github  → GitHub
  • 같은 브랜치라도
  • 다른 remote로 push하면
  • 전혀 다른 레포에 다른 히스토리가 생긴다

remote를 바꾼다는 건:

“다른 서버에 다른 프로젝트를 만든다”에 가깝다


7️⃣ GitHub의 100MB 제한은 버그가 아니라 설계다

  • GitHub는 Git을 코드 저장소로 쓰길 원한다
  • 대용량 파일은:
    • Git LFS
    • 외부 스토리지
    • 릴리즈 아티팩트

즉:

“Git에 넣지 말라는 신호”


8️⃣ 서버 이전은 Git 명령 문제가 아니라 “의사결정 문제”다

이전 상황에서 가장 중요한 질문은 이거였다.

  • 커밋 이력을 살릴 것인가?
  • 아니면 결과물만 살릴 것인가?

이걸 정하지 않으면:

  • 명령어를 바꿔도
  • 브랜치를 바꿔도
  • 계속 같은 문제에 부딪힌다

한 문장 요약 (이건 진짜 중요)

Git을 쓰기 시작한 초보자는
파일을 관리한다고 생각하지만,
Git은 처음부터 끝까지 ‘히스토리’를 관리한다.

이 차이를 이해한 순간부터:

  • push 에러가 덜 무섭고
  • 서버 이전이 덜 위험하고
  • Git이 도구처럼 느껴지기 시작한다

 

 

마지막 전체 실행 예시 

git status
git branch
git remote -v
git remote add github git@github-company:example-org/project.git
git remote -v
git remote set-url github git@github-company:example-org/project.git
git fetch github
git config user.name "Your Name"
git config user.email "your.email@example.com"
git config --list
git checkout -b test-import-from-gitlab github/main
git branch
git checkout old-branch -- .
git rm --cached deps/*.zip
git status
git add . # 상황에 따라 다르게
git commit -m "import: initial snapshot from GitLab"
git push -u github test-import-from-gitlab