CI/CD Practice 04
하나의 변경으로 보는 CI/CD 흐름
웹에서 파일을 고치고, pipeline이 돌고, VS Code에서 pull을 하는 장면이 각각 따로 보이면 하나의 변경이 어디까지 전파됐는지 판단하기 어렵다.
근거 · CI/CD 교안 p56-p67
1장: GitHub 웹 수정: 새로운 버전의 시작
솔라가 노트북 화면을 들여다보며 미간을 찌푸렸다. 화면 한구석에는 방금 읽은 문장이 머릿속에서 떠나지 않고 있었다. “GitHub에서 파일을 수정하면 pipeline이 다시 실행되고 로컬 저장소도 pull로 동기화합니다.”
분명 각각의 단어는 모두 아는 것이었다. GitHub, 파일 수정, 파이프라인, pull. 하지만 단어들을 한 줄로 이어 붙인 문장은 솔라에게는 마치 세 개의 다른 섬처럼 느껴졌다. 첫 번째 섬에서 횃불을 들면, 두 번째 섬에서 저절로 봉화가 피어오르고, 세 번째 섬의 주민은 그 연기를 보고 깃발을 올린다. 하지만 그 사이를 잇는 배는 보이지 않았다.
“언니, 이것 좀 봐봐.”
솔라의 부름에 옆에서 조용히 책을 읽던 루나가 고개를 들었다. 솔라가 노트북 화면을 루나 쪽으로 돌렸다.
“이 문장, 꼭 해야 할 일 목록 같지 않아? 첫째, GitHub에서 파일 고치기. 둘째, 파이프라인 실행되는지 보기. 셋째, 내 컴퓨터에서 pull 받기. 그런데 이 세 가지가 그냥 순서대로 일어나는 별개의 사건이야? 아니면 뭔가 하나의 흐름인 거야?”
솔라는 답답하다는 듯이 말했다. “특히 ‘파일을 수정하면’이라는 첫 부분이 제일 애매해. 그냥 메모장에서 오타 고치는 거랑 똑같은 느낌이거든. 파일을 고쳤는데, 어떻게 저 멀리 있는 파이프라인이 그걸 알아채고 움직인다는 건지 도무지 연결이 안 돼.”
루나는 솔라의 말을 잠자코 듣더니, 화면을 가만히 들여다보았다. “그 문장의 첫 단추부터 같이 끼워볼까? 솔라 네가 제일 애매하다고 한 부분. ‘GitHub에서 파일을 수정한다’는 게 정말 메모장에서 오타 고치는 거랑 같은 일인지.”
루나는 노트북을 자기 앞으로 가져와, 익숙한 프로젝트의 GitHub 저장소 페이지를 열었다. 화면에는 파일과 폴더 목록이 보였다. 루나는 그중 index.html 파일을 클릭했다. 파일 내용과 함께 오른쪽 위에 작은 연필 모양 아이콘이 나타났다.
“자, 여기서 간단한 문장 하나만 바꿔보자.”
솔라는 루나의 손가락이 가리키는 대로, ‘Edit this file’이라고 적힌 연필 아이콘을 눌렀다. 텍스트를 편집할 수 있는 화면으로 바뀌자, 솔라는 <h1>Hello World</h1> 라고 되어 있던 부분을 <h1>Hello Universe!</h1>로 고쳤다. 정말 메모장에서 글자를 바꾸는 것과 다를 바 없는 간단한 작업이었다.
“됐어. 이제 저장하면… 어?”
솔라의 손가락이 멈칫했다. 화면 오른쪽 위에는 ‘저장(Save)’ 버튼 대신 ‘변경 사항 커밋(Commit changes)‘이라는 초록색 버튼이 있었다. 그 아래에는 변경 내용을 요약하는 제목과 설명을 적는 칸도 보였다.
Commit changes
[ Update index.html ]
< Add an optional extended description... >
“그냥 파일을 고치는 거라면 바로 저장하면 그만일 텐데.” 루나가 조용히 말했다. “그런데 여기선 왜 ‘커밋’이라는 단계를 거치면서, 굳이 변경 내용을 기록하라고 할까?”
“음… 내가 뭘 바꿨는지 나중에 알아보려고?” 솔라가 말했다.
“맞아. 정확히는 ‘누가, 언제, 무엇을, 왜’ 바꿨는지 공식적인 기록을 남기는 거야.”
솔라는 잠시 생각하더니, 제목 칸에 ‘헤드라인 문구 수정’이라고 입력하고 초록색 버튼을 눌렀다. 잠시 후 페이지가 새로고침되면서 파일 목록 화면으로 돌아왔다. index.html 파일 옆에는 방금 솔라가 입력한 ‘헤드라인 문구 수정’이라는 글자와 함께, 변경된 시간이 표시되어 있었다.
“봐, 그냥 파일 내용만 바뀐 게 아니야.” 루나가 말했다. “솔라 네가 한 변경이 ‘헤드라인 문구 수정’이라는 이름표를 달고 저장소의 역사에 한 줄로 기록됐어. 이제 그 이름표를 따라가 보자.”
루나는 저장소 페이지 상단의 ‘commits’ 탭을 클릭했다. 맨 위에는 방금 솔라가 만든 변경 기록이 보였다.
- 헤드라인 문구 수정
a1b2c3d
“이게 방금 네가 한 작업의 결과야. 그런데 저기, 이름표 옆에 붙은 이상한 숫자와 알파벳 조합 보이지? a1b2c3d 같은 거.”
“응. 이건 뭐야? 암호인가?”
“일종의 영수증 번호나 운송장 번호 같은 거야. 이 세상에 단 하나뿐인, 이 변경만을 위한 고유 식별 번호. 우리는 이걸 커밋 ID라고 불러.”
루나가 커밋 ID를 클릭하자, 화면이 바뀌며 초록색으로 강조된 + <h1>Hello Universe!</h1>와 빨간색으로 강조된 - <h1>Hello World</h1>가 나란히 나타났다. 정확히 솔라가 무엇을 지우고 무엇을 추가했는지 한눈에 보였다.
그제야 솔라의 얼굴에 아하, 하는 표정이 떠올랐다.
“알겠다! GitHub에서 파일을 수정하는 건 그냥 내용을 바꾸는 게 아니었어. ‘이런 변경 사항을 담은 새로운 버전을 하나 만들어주세요’ 하고 공식적으로 요청하는 행위였던 거야. 그리고 그 버전에는 커밋 ID라는 고유한 이름표가 붙는 거고.”
솔라는 고개를 끄덕였다. 이제 ‘GitHub에서 파일을 수정하면’이라는 말이 전과 다르게 들렸다. 그것은 안갯속의 모호한 행동이 아니라, ‘고유한 ID를 가진 새로운 버전이 생성되면’이라는 명확한 사건으로 바뀌어 있었다.
퍼즐의 첫 조각이 제자리를 찾은 느낌이었다. 이제 첫 번째 섬에서는 횃불이 아니라, ‘커밋 ID a1b2c3d’라는 명확한 신호탄이 쏘아 올려졌다.
솔라는 다시 생각에 잠겼다. “좋아. 이제 GitHub에 a1b2c3d라는 명확한 증거가 남았다는 건 알겠어. 그런데… 저 멀리 있는 파이프라인은 이 수많은 커밋들 중에 하필이면 이 a1b2c3d가 새로 생겼다는 걸 어떻게 알고 반응하는 거지? 계속 GitHub 페이지만 쳐다보고 있는 건가?“
2장: 커밋과 파이프라인: 자동화된 연결고리
솔라의 질문에 루나는 대답 대신 노트북 화면을 바꿨다. 방금 전까지 보던 익숙한 GitHub 페이지가 사라지고, 회색 배경에 여러 개의 상자가 선으로 이어진 다이어그램이 나타났다. AWS CodePipeline 콘솔이었다.
화면 중앙에는 ‘MyWebAppPipeline’이라는 이름의 파이프라인이 보였다. Source, Build, Deploy라는 이름표를 단 상자들이 왼쪽에서 오른쪽으로 이어져 있었고, 각 상자는 초록색으로 칠해져 ‘Succeeded’라는 단어를 표시하고 있었다. 마지막 실행은 몇 시간 전이었다. 파이프라인은 솔라의 생각처럼 쉴 새 없이 GitHub를 쳐다보며 안절부절못하는 모습이 아니었다. 그저 조용히, 마지막 임무를 완수한 채로 대기 중이었다.
“계속 쳐다보고 있는 건 아니네.”
솔라가 툭 내뱉자, 루나는 “그렇지? 대신 약속을 하고 기다리는 쪽이야.”라고 답하며 페이지를 새로고침했다.
순간, Source 상자의 초록색 불이 파란색으로 바뀌며 ‘In Progress’라는 글자가 깜빡이기 시작했다. 파이프라인이 잠에서 깨어난 것이다. 몇 초 지나지 않아 Source 상자는 다시 초록색으로 돌아왔고, 이번엔 Build 상자가 파랗게 물들었다. 마치 컨베이어 벨트 위의 상자가 다음 공정으로 넘어가는 것 같았다.
“어! 움직인다! 방금 우리가 커밋해서 그런 거지?” 솔라의 목소리가 들떴다.
“맞아. 그런데 더 중요한 질문이 있어.” 루나가 Source 상자를 가리켰다. “파이프라인이 그냥 ‘뭔가 바뀌었네’ 하고 움직이기 시작했을까? 아니면 정확히 ‘솔라가 만든 a1b2c3d 커밋’을 보고 움직이기 시작했을까?”
솔라는 잠시 할 말을 잃었다. 그녀에게는 그냥 ‘파이프라인이 돌았다’는 사실 자체가 신기할 뿐이었다. 그 시작이 특정 커밋과 연결되어 있다는 생각까지는 미치지 못했다. “음… 후자여야 할 것 같은데… 그걸 어떻게 확인하지?”
루나는 ‘MyWebAppPipeline’의 실행 이력(Execution history)에서 방금 시작된 최신 항목을 클릭했다. 파이프라인의 각 단계가 더 상세하게 표시된 화면으로 바뀌었다. 루나는 Source 단계 아래에 있는 작은 링크, ‘Execution details’를 눌렀다.
팝업 창이 뜨자, 그 안에는 몇 줄의 정보가 간결하게 정리되어 있었다. 솔라는 자기도 모르게 숨을 멈췄다.
Source location: GitHub/my-user/my-repo/main
Commit ID: a1b2c3d
Commit message: 헤드라인 문구 수정
“a1b2c3d…!”
솔라의 눈이 커졌다. 방금 전 GitHub에서 봤던, 바로 그 커밋 ID였다. 암호 같던 그 문자열이 지금 이곳, 파이프라인의 심장부에서 발견된 것이다. 그것은 우연히 발생한 사건이 아니었다. 파이프라인은 정확히 a1b2c3d라는 이름표를 가진 버전을 감지하고, 그 버전을 배포하기 위해 움직이기 시작한 것이었다.
“알겠다! 파이프라인은 그냥 막연하게 ‘새로운 게 있네’ 하고 움직이는 게 아니구나. GitHub랑 미리 약속을 해둔 거야. ‘이 저장소의 이 브랜치에 새로운 커밋이 생기면 나에게 알려줘’ 하고. 그래서 a1b2c3d가 생기자마자 GitHub가 파이프라인에게 신호를 보낸 거고, 파이프라인은 그 커밋 ID를 정확히 인계받아서 일을 시작하는 거였어.”
솔라는 이제 ‘수정 commit이 생성되면 pipeline이 다시 실행된다’는 문장을 완벽히 이해할 수 있었다. 두 번째 섬에서 피어오른 봉화는 맹목적인 반응이 아니었다. 첫 번째 섬에서 쏘아 올린 a1b2c3d라는 선명한 신호탄을 정확히 수신한 결과였다.
잠시 후, 파이프라인의 모든 단계가 다시 초록색으로 바뀌며 ‘Succeeded’ 상태가 되었다. 두 번째 섬의 임무는 끝났다.
솔라는 만족스러운 표정으로 화면을 바라보다가, 문득 Deploy라고 적힌 마지막 상자에 시선이 머물렀다. “Deploy 성공. 배포 성공이라… 그럼 이제 정말로 웹사이트에 Hello Universe!라고 뜨는 건가? 이 초록색 불빛만 믿어도 되는 걸까?“
3장: 배포 확인: 실제 프로덕션 환경에서 변경 검증
파이프라인의 모든 단계가 선명한 초록색으로 빛나고 있었다. Source, Build, Deploy. 각 상자 아래에는 ‘Succeeded’라는 단어가 명패처럼 붙어 있었다. 자동화된 공정은 흠잡을 데 없이 임무를 완수했다. 솔라의 시선은 ‘Deploy’라는 마지막 상자에 머물렀다.
루나는 아무 말 없이 새 브라우저 탭을 열었다. 방금까지 보던 파이프라인의 복잡한 다이어그램이 사라지고, 텅 빈 주소창만 덩그러니 남았다. 그녀가 키보드를 몇 번 두드리자 짧은 주소가 나타났다.
http://my-prod-site.com
“이게 세 번째 섬의 주소야.”
루나가 짧게 말했다. 첫 번째 섬은 GitHub 저장소, 두 번째 섬은 CodePipeline. 그리고 지금 눈앞에 나타난 주소가 바로 그 모든 과정의 최종 목적지, 실제 사용자들이 방문하는 프로덕션 웹사이트였다. 파이프라인의 초록불은 ‘배포를 성공적으로 마쳤다’는 시스템의 보고서일 뿐. 보고서가 진실인지 확인하는 것은 시스템의 몫이 아니었다.
루나가 엔터 키를 눌렀다.
짧은 로딩 시간 후, 하얀 화면 중앙에 검은 글씨가 나타났다.
Hello Universe!
“와…!”
솔라의 입에서 짧은 탄성이 터져 나왔다. 너무나 간단하고 당연한 결과였지만, 직접 눈으로 확인하는 순간의 감각은 전혀 달랐다. 안갯속에 흩어져 있던 세 개의 섬이 마침내 하나의 분명한 항로로 연결되는 순간이었다. GitHub에서 시작된 작은 수정(a1b2c3d)이 파이프라인이라는 자동화된 항로를 거쳐, 마침내 세 번째 섬인 프로덕션 웹사이트에 정확히 도착한 것이다.
“알겠다.” 솔라가 무릎을 탁 쳤다. “파이프라인 화면의 초록색 ‘Succeeded’는 그냥 ‘배포 작업이 오류 없이 끝났습니다’라는 보고서일 뿐이었어. 그 자체가 결과는 아니었던 거야. 진짜 결과물은 이 웹사이트고, 이건 내 눈으로 직접 확인해야만 확신할 수 있는 거였네.”
솔라는 이제 ‘production website endpoint에서 바뀐 페이지를 확인한다’는 문장의 무게를 이해했다. 그것은 선택 사항이나 부가적인 확인 절차가 아니었다. 전체 CI/CD 흐름의 종착점에서, 모든 과정이 헛되지 않았음을 증명하는 필수적인 검증 행위였다. 두 번째 섬에서 피어오른 봉화가 정말로 세 번째 섬의 풍경을 바꾸었는지, 직접 건너가 보는 것과 같았다.
솔라는 만족스러운 미소를 지으며 의자 깊숙이 등을 기댔다. “좋아. 이제 GitHub에도, 파이프라인 기록에도, 실제 웹사이트에도 Hello Universe!가 반영됐어. 완벽하게 연결됐네.”
이제 모든 것이 제자리를 찾은 것 같았다. 솔라는 자신의 노트북을 열어 VS Code를 실행했다. 다음 작업을 위해 로컬 프로젝트 폴더를 열고 index.html 파일을 클릭했다. 화면에 익숙한 코드가 나타났다.
그런데, 무언가 이상했다.
솔라는 눈을 비비고 화면을 다시 들여다봤다. 웹사이트에서 방금 확인했던 문구와 달랐다.
<h1>Hello World</h1>
분명히 GitHub에서 ‘Hello Universe!’로 고쳤고, 그 변경이 파이프라인을 거쳐 웹사이트에 배포까지 되었는데, 정작 자신의 작업 공간인 로컬 컴퓨터에는 옛날 내용이 그대로 남아 있었다.
연결된 줄 알았던 흐름에 예상치 못한 단절이 나타났다. “어? 내 컴퓨터는 왜 그대로지? 여기는 이 흐름 밖에 있는 건가?“
4장: 로컬 동기화: 내 작업 환경에 변경 가져오기
솔라의 노트북 화면에는 명백한 모순이 펼쳐져 있었다. 오른쪽 웹 브라우저 탭에는 방금 배포된 Hello Universe!가 선명했지만, 왼쪽 VS Code 편집기에서 열린 index.html 파일은 여전히 <h1>Hello World</h1>를 고집하고 있었다. GitHub, 파이프라인, 실제 서비스까지 이어진 흐름의 마지막 종착지, 바로 자신의 작업 공간에서 연결이 끊긴 것이다.
솔라는 마우스 커서로 두 창을 번갈아 클릭했다. 브라우저를 새로고침해도 결과는 같았다. 원격 세상의 변화가 자신의 로컬 컴퓨터에는 전혀 영향을 주지 못한 채, 두 개의 버전이 한 화면 안에서 서로를 외면하고 있었다.
솔라의 혼란스러운 표정을 본 루나가 노트북 화면을 들여다보았다. 루나는 두 화면을 번갈아 보더니, 솔라의 VS Code 창을 손가락으로 가리켰다.
“지금까지 우리가 확인한 세 곳—GitHub, 파이프라인, 그리고 웹사이트—의 공통점이 뭔지 알아?”
“음… 모두 웹 브라우저로 접속했고, 다 인터넷 너머 어딘가에 있다는 거?”
“정확해. 모두 ‘원격(remote)’ 세상에 있는 것들이야. 그리고 그들끼리는 서로 약속된 신호(커밋)를 주고받으며 자동으로 움직였지.” 루나는 말을 이었다. “하지만 지금 솔라 네가 보고 있는 VS Code 속 폴더는 ‘로컬(local)’, 바로 이 노트북 안에 있어. 원격 세상에서 일어나는 일은 로컬 세상에 자동으로 알려지지 않아. 별개의 공간이니까.”
“별개의 공간이라니… 그럼 영원히 연결이 안 되는 거야?”
“아니, 연결할 수 있어. 다만 자동이 아닐 뿐이야. 로컬 세상의 주인이 직접 원격 세상에 ‘새 소식 있으면 나에게도 알려줘’ 하고 요청해야 해.”
루나는 솔라에게 VS Code 하단의 터미널 창을 열어보라고 했다. 익숙한 명령 프롬프트가 깜빡였다.
“먼저 네 로컬 저장소가 현재 상황을 어떻게 파악하고 있는지 물어보자.”
솔라는 루나가 알려준 대로 터미널에 명령어를 입력했다.
git status
엔터 키를 누르자 몇 줄의 메시지가 나타났다. 솔라는 그중 한 줄에 시선이 꽂혔다.
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
“어? ‘behind’라고 나오네? 1 커밋만큼 뒤처져 있다고?”
솔라는 놀란 목소리로 말했다. 자신의 컴퓨터가 최신 상태가 아니라는 사실을 Git 스스로가 이미 알고 있었던 것이다. 심지어 친절하게 git pull 명령어를 사용하라는 안내까지 해주고 있었다. 지금까지 로컬 환경이 흐름에서 완전히 배제된 외딴섬이라고 생각했는데, 그게 아니었다. 최신 소식을 받지 못했을 뿐, 원격 저장소와 연결이 끊어진 상태는 아니었다.
“이제 네 로컬 저장소도 a1b2c3d 커밋의 존재를 알게 된 거야. 하지만 아직 그 내용을 가져오진 않았지. 이제 직접 가져오라고 명령할 차례야.”
솔라는 조금 전 안내 메시지에서 봤던 명령어를 그대로 터미널에 입력했다.
git pull
명령을 실행하자, 터미널 화면에 새로운 내용이 빠르게 출력되었다.
Updating a1b2c3d..e4f5g6h
Fast-forward
index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
index.html 파일이 변경되었다는 메시지였다. 솔라가 고개를 들어 VS Code 편집기 창을 보는 순간, 놀라움에 눈이 동그래졌다. 방금 전까지 Hello World였던 코드가 터미널 명령이 끝나자마자 Hello Universe!로 바뀌어 있었다.
<h1>Hello Universe!</h1>
마법처럼 느껴졌다. 솔라는 이제 로컬 저장소도 pull로 동기화합니다라는 문장의 의미를 온전히 이해할 수 있었다. 이것은 CI/CD 자동화 흐름의 일부가 아니었다. 개발자인 내가, 내 작업 공간을 원격 세상의 최신 변경 사항과 맞추기 위해 직접 수행해야 하는 능동적인 ‘동기화’ 행위였던 것이다.
“알겠다! 내 컴퓨터는 자동 구독자가 아니었구나. 내가 원할 때마다 직접 ‘최신 소식 좀 줘!’ 하고 요청해야 하는 거였어. git pull은 그냥 파일을 다운로드하는 게 아니라, 원격 저장소와 내 작업실의 시간을 맞추는 거였네.”
솔라는 만족스러운 표정으로 의자에 등을 기댔다. 흩어져 있던 네 개의 점—GitHub, 파이프라인, 웹사이트, 그리고 로컬 컴퓨터—이 모두 Hello Universe!라는 하나의 상태로 통일되었다.
문득 솔라의 머릿속에 새로운 질문이 떠올랐다.
“좋아. 이제 네 군데 모두에서 변경을 확인했어. GitHub에서 시작해서, 파이프라인을 거쳐, 웹사이트에 도착하고, 내 컴퓨터에도 가져왔지. 그런데… 이 모든 게 정말로 우리가 처음에 만들었던 그 커밋, a1b2c3d 하나 때문에 일어난 일이라는 걸 한눈에 증명할 수 있을까? 점들은 다 찍었는데, 이 점들을 하나의 선으로 이을 수 있냐는 말이야.”
5장: 하나의 변경, 전체 흐름: 단일 커밋의 여정
솔라의 질문이 조용한 거실 공기에 스며들었다. 흩어진 점들을 하나의 선으로 이을 수 있을까. 루나는 대답 대신, 옆에 있던 메모패드와 펜을 가져왔다. 그리고 방금 솔라가 거쳐온 네 개의 장소를 간결하게 적어 내려갔다.
1. GitHub 저장소
2. CodePipeline
3. 프로덕션 웹사이트
4. 로컬 컴퓨터 (내 노트북)
루나는 메모지를 솔라 쪽으로 밀어주었다. 솔라가 머릿속에서 ‘점’이라고 표현했던 네 개의 장소가 눈앞에 명확한 목록으로 나타났다. 마치 각기 다른 주소를 가진 네 개의 섬처럼, 서로 떨어져 있는 것처럼 보였다.
“네 말대로, 우리는 네 개의 섬을 모두 방문했어.” 루나가 입을 열었다. “그리고 각 섬에서 ‘Hello Universe!’라는 깃발이 꽂힌 것도 확인했지. 하지만 이게 우연히 각 섬에 같은 깃발이 꽂힌 건지, 아니면 첫 번째 섬에서 출발한 깃발이 차례대로 전달된 건지 아직 증명하지 못했어.”
루나는 펜을 들어 목록 옆 빈 공간에, 이제는 익숙해진 그 문자열을 적었다.
a1b2c3d
“이게 우리의 증거야. 이 커밋 ID라는 단 하나의 실을 가지고, 네 개의 섬을 모두 꿰뚫을 수 있는지 확인해 보는 거야.”
솔라는 루나의 말에 고개를 끄덕였다. 지금까지 각 장소를 개별적으로 확인했지만, 이 커밋 ID를 탐정의 돋보기처럼 들고 처음부터 다시 추적해 본다는 생각은 하지 못했다.
“좋아, 탐색 시작.” 솔라가 노트북을 다시 자기 앞으로 당겨왔다.
첫 번째 단서: GitHub 저장소
솔라는 먼저 GitHub 저장소의 커밋 히스토리 페이지를 열었다. 맨 위에는 의심의 여지 없이, 우리가 만든 변경 기록이 있었다.
a1b2c3d- 헤드라인 문구 수정
“첫 번째 섬에서 범인, 아니 커밋의 신원 확보.” 솔라가 장난스럽게 말하며 메모지의 ‘1. GitHub 저장소’ 옆에 작은 체크 표시를 했다. ✔
두 번째 단서: CodePipeline
다음은 파이프라인이었다. 솔라는 CodePipeline 콘솔로 이동해, 조금 전 성공적으로 실행된 기록을 클릭했다. 그리고 Source 단계의 세부 정보를 열었다. 팝업 창에 나타난 정보는 명확했다.
- Commit ID:
a1b2c3d
“두 번째 섬도 이 커밋의 방문 기록을 정확히 기억하고 있어.” 솔라의 손가락이 두 번째 항목 옆에도 체크 표시를 그렸다. ✔
세 번째 단서: 프로덕션 웹사이트
“자, 이제 세 번째.” 솔라가 웹사이트 탭으로 이동했다. 하얀 화면에 Hello Universe!가 선명했다. “그런데 여긴 커밋 ID가 없잖아. 어떻게 증명하지?”
“이 섬의 주민은 커밋 ID 같은 어려운 말은 몰라.” 루나가 말했다. “대신 이 주민이 보여주고 있는 풍경, Hello Universe!는 어디서 왔을까?”
“아! a1b2c3d 커밋이 만든 변경 내용이지!”
솔라는 GitHub 탭으로 돌아가 a1b2c3d 커밋의 변경 내역을 다시 확인했다. - <h1>Hello World</h1> 와 + <h1>Hello Universe!</h1>. 웹사이트에 표시된 내용은 정확히 이 커밋이 만들어낸 결과물이었다. 직접적인 ID는 없었지만, 커밋이 남긴 명백한 발자국이 있었다.
“정황 증거 확보. 세 번째 섬도 통과.” 솔라가 세 번째 항목 옆에 체크 표시를 했다. ✔
네 번째 단서: 로컬 컴퓨터
마지막은 솔라 자신의 노트북이었다. 솔라는 VS Code의 터미널 창에 익숙한 명령어를 입력했다.
git log
엔터 키를 누르자, 로컬 저장소의 역사가 화면에 펼쳐졌다. 그리고 그 가장 맨 위, 가장 최신 기록에서 빛나는 이름표를 발견했다.
commit a1b2c3d... (origin/main, main)
Author: 솔라 ...
Date: ...
헤드라인 문구 수정
솔라는 자기도 모르게 미소를 지었다. 원격 세상의 일이라고만 생각했던 a1b2c3d가, 이제는 자신의 작업 공간에 공식적인 역사 기록으로 남게 된 것이다. 솔라는 마지막 항목 옆에도 힘주어 체크 표시를 했다. ✔
메모패드에는 이제 네 개의 체크 표시가 선명했다.
✔ 1. GitHub 저장소 (ID: a1b2c3d)
✔ 2. CodePipeline (Trigger: a1b2c3d)
✔ 3. 프로덕션 웹사이트 (Result from a1b2c3d)
✔ 4. 로컬 컴퓨터 (History includes a1b2c3d)
솔라는 완성된 목록을 가만히 들여다보았다. 흩어져 있던 점들이 아니었다. 이것은 a1b2c3d라는 하나의 변경이 GitHub에서 시작되어, 파이프라인이라는 길을 따라 웹사이트라는 목적지에 도착하고, 그 소식이 로컬 컴퓨터까지 전해지는 하나의 긴 여정이었다.
그제야 솔라는 처음 자신을 혼란스럽게 했던 그 문장을 다시 떠올렸다.
“GitHub에서 파일을 수정하면 pipeline이 다시 실행되고 로컬 저장소도 pull로 동기화합니다.”
솔라는 펜을 집어 들었다. 그리고 체크리스트 위 빈 공간에, 자신만의 다이어그램을 그리기 시작했다. ‘GitHub’에서 ‘Pipeline’으로, ‘Pipeline’에서 ‘Website’로, 그리고 ‘GitHub’에서 ‘Local’로 화살표를 그었다. 그리고 그 모든 화살표 위에, 그녀는 이 모든 것을 가능하게 한 마법의 열쇠, a1b2c3d를 적어 넣었다.
“알겠다.” 솔라가 완성된 그림을 보며 말했다. “이건 해야 할 일 목록이 아니었어. 하나의 변경이 시스템 전체를 여행하는 경로, 일종의 지도였던 거야. 그리고 커밋 ID는 그 여행 내내 사용되는 단 하나의 여권이었고.”
이제 솔라는 어떤 변경이 어디까지 진행되었는지 막막할 때, 무엇을 확인해야 하는지 정확히 알게 되었다. 그것은 바로 이 여권 번호, 커밋 ID를 들고 각 지점의 출입국 기록을 확인하는 것이었다. 솔라는 자신의 손으로 완성한 작은 다이어그램을 보며, 흩어져 있던 섬들을 잇는 튼튼한 다리를 마침내 완성한 기분을 느꼈다.