<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>violet_evgadn.log</title>
        <link>https://velog.io/</link>
        <description>혹시 틀린 내용이 있다면 언제든 말씀해주세요!</description>
        <lastBuildDate>Mon, 22 Jan 2024 23:27:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>violet_evgadn.log</title>
            <url>https://velog.velcdn.com/images/violet_evgadn/profile/52cd42ed-7a98-4cdd-9d7a-05e5b0e6f6e6/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. violet_evgadn.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/violet_evgadn" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[ABAP 개요]]></title>
            <link>https://velog.io/@violet_evgadn/ABAP-%EA%B0%9C%EC%9A%94</link>
            <guid>https://velog.io/@violet_evgadn/ABAP-%EA%B0%9C%EC%9A%94</guid>
            <pubDate>Mon, 22 Jan 2024 23:27:19 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreensap"><span style="color: lightgreen">SAP</h1>
<h3 id="span-stylecolor-lightblueerp란"><span style="color: lightblue">ERP란?</h3>
<p>SAP는 ERP 시스템이다.
즉, SAP라는 것을 알기 위해선 ERP를 알아야 한다는 것이다.</p>
<p>ERP는 전사적지원관리(Enterprise Resource Planning)의 약자로 기업의 모든 업무를 통합 관리할 수 있는 시스템을 의미한다.</p>
<p>기업이 하는 업무는 무엇일까?
시공사라면 건물만 지으면 되고, 제조사라면 물건만 만들면 될까?</p>
<p>제조사를 예를 들어보자.
제조사에선 당연히 물건을 만들 것이다. 하지만 물건을 만들기 위하여 재료의 재고를 파악해야 할 필요가 있고 부족하면 주문도 해야할 것이다.
만들어진 제품의 재고도 알아야하며 이를 배송할지도 관리해야 한다.
제조사라고 물건만 관리하진 않는다. 물건을 관리할 사람들을 뽑을 인사과도 존재해야 하며 재료를 얼마에 사고 상품을 얼마에 팔았는지 관리해줄 회계팀도 필요하다.
돈이 부정 없이 활용되는지 감시하기 위해 감사팀도 필요할 것이고 직원들에게 돈을 줘야하기에 급여를 주는 과도 필요할 것이다.</p>
<p>ERP 시스템은 이러한 회사에서 하는 여러 업무를 관리해주는 시스템을 의미한다.</p>
<p>ERP 시스템의 장점은 크게 5가지 존재한다.</p>
<ol>
<li>시스템이 자동으로 업무를 수행하므로 Human Error를 줄일 수 있음</li>
<li>시스템이 데이터를 규칙에 맞게 관리하므로 데이터의 정합성을 보장할 수 있음</li>
<li>ERP 시스템에 입력한 정보를 분석하여 경영자의 의사결정을 도울 수 있음</li>
<li>ERP 시스템 정보를 다양한 형태의 보고서로 만들 수 있음</li>
<li>직원들의 반복 업무를줄이고 업무 공유및 보고가 쉬워짐
⮕ 시간 / 인력을 효율적으로 활용할 수 있음
⮕ 회사 핵심 업무에 집중할 수 있음</li>
</ol>
<h3 id="span-stylecolor-lightblueerp-모두가-써야하는가"><span style="color: lightblue">ERP, 모두가 써야하는가?</h3>
<p>이렇게만 보면 ERP는 완벽한 시스템이고 모든 회사에서 활용되어야 할 것 같다.
실제로 2000년대 중반에는 기업과 무관한 대학교에서도 학사 관리를 위해 ERP를 활용했던 적이 있다고 한다.</p>
<p>소제목을 보고 눈치챘을수도 있겠지만 그렇다고 ERP는 완전무결한 시스템이 아니다.
ERP 시스템은 유지보수에 돈이 많이 들기도 하고 몇 가지 전제조건이 충족되어야지만 효율적인 활용이 가능해진다.</p>
<ul>
<li>기업 전체의 인적 / 물적 자원 흐름이 사람이 직접 관리하기엔 어렵고 복잡하며 다수일 것</li>
<li>재고관리나 물류 관리 등을 실시간에 가깝도록 관리되는 것이 필수이거나 많은 수익을 낼 수 있어야 함</li>
<li>조직 전체의 의사결정을 신속하게 하기 위하여 자료 정리가 자주 필요하다.</li>
</ul>
<p>즉, 점포의 개수가 많지 않거나 조직이 의사결정을 수행하지 않고 타업체 의사 결정에 따르는 경우가 많을 경우 오히려 ERP에 투자한 돈이 낭비가 되는 문제가 발생할 수 있다.</p>
<p>(물론 최근들어 외국과의 거래 시 필요한 서류 및 과정이 복잡해져 수출입 기업들의 경우 해당 기준을 임의로 판단하기엔 위험성이 커져 수출입 파트에만 한정적으로 ERP 모듈을 적용시키는 경우도 있다)</p>
<h3 id="span-stylecolor-lightbluesap"><span style="color: lightblue">SAP</h3>
<p>독일의 SAP SE란 기업에서 개발한 ERP 시스템이다.
위에서 설명한 ERP가 &quot;빵집&quot;이라면 SAP는 &quot;성심당&quot;이라는 느낌이며 독일 SAP SE 회사는 SAP의 높은 활용율에 힘입어 독일 시총 1위를 달리고 있다.
(<del>교육 1개당 100만원 이상을 받는 무친 기업...</del>)</p>
<h3 id="span-stylecolor-lightbluesap를-통해-활용할-수-있는-기능"><span style="color: lightblue">SAP를 통해 활용할 수 있는 기능</h3>
<h4 id="span-stylecolor-orange1-재무-및-회계-관리"><span style="color: orange">1. 재무 및 회계 관리</h4>
<p>SAP는 IFRS(국제회계기준)에 부합하는 재무 및 회계 관리가 가능하다.</p>
<p>채무, 채권, 재고와 고정자산 분석, 세금 및 비용 관리가 가능해지며 회계 장부도 생성해주기에 재무 거래의 자동화, 정확성, 그리고 투명성을 보장할 수 있다.</p>
<h4 id="span-stylecolor-orange2-공급망-관리le"><span style="color: orange">2. 공급망 관리(LE)</h4>
<p>수요와 공급을 분석하여 재고, 오더, 물류, 공급자를 효율적으로 관리할 수 있다.</p>
<h4 id="span-stylecolor-orange3-판매-및-유통-관리sd"><span style="color: orange">3. 판매 및 유통 관리(SD)</h4>
<p>주문 관리, 가격 설정, 제품 및 재고 추적, 판매 분석 등을 통해 판매 프로세스를 효율화하고 고객 서비스를 개선할 수 있다.</p>
<p>고객사별 매출 분석을 통해 마케팅 혹은 영업팀에 도움을 줄 수 있고 가격이 어떻게 결정되었는지 쉽게 파악할 수 있다.</p>
<h4 id="span-stylecolor-orange4-고객-관계-관리crm"><span style="color: orange">4. 고객 관계 관리(CRM)</h4>
<p>고객별 특화 저장 위치 및 제품 특징에 맞도록 고객 맞춤 서비스를 제공할 수 있으며 판매 History나 Complaint 해결 추적을 통해 고객과의 관계를 수급 및 강화할 수 있다.</p>
<h4 id="span-stylecolor-orange5-생산-관리mm"><span style="color: orange">5. 생산 관리(MM)</h4>
<p>생산 계획, 원가 계산, 제조 프로세스 관리, 품질 관리 등을 지원하여 생산 프로세스를 효율화하고 생산성을 높일 수 있다.</p>
<p>제품별 MRP(자재 소요량) Setting과 고객사 오더 주기 Setting을 통해 자동적으로 생산 오더가 생성되며 이를 위한 원자재 구매 오더도 생산된다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenabap"><span style="color: lightgreen">ABAP</h1>
<h3 id="span-stylecolor-lightblueabap이란"><span style="color: lightblue">ABAP이란?</h3>
<p>SAP R/3는 ABAP/4 언어로개발된 ERP 패키지이다.</p>
<p>ABAP은 Advanced Business Application Programming의 약자이며 4는 4세대 언어라는 의미이다.</p>
<p>ABAP은 단순 DB 데이터 추출을 넘어서 프로그램과 DB를 논리적으로 구성할 수 있는 상위 레벨의 DB를 사용한다는 의미를 담은 축약어이다.</p>
<p>기존 SQL은 DCL, DML, DDL을 통해 데이터 및 Table 등을 생성/조회/삭제하기만 하였지만 ABAP은 이러한 데이터 및 프로세스들을 프로그램에 녹여 조금 더 고차원적인 DB 작업을 수행할 수 있다는 의미를 담은 것이다.</p>
<p>하지만 이는 SAP에서 발표한 내용에 불과하고, 그냥 SQL보다는 조금 고수준으로 만들어진 SAP 구성 프로그래밍 언어에 불과하다.
JAVA와 Python과 비교했을 때 ABAP은 한없이 저수준 언어이다.</p>
<p>ABAP 언어를 통해 SAP 시스템이 구성되어 있고 새로운 프로그램을 개발할 수 있는 것이다.</p>
<h3 id="span-stylecolor-lightbluecbo-vs-standard"><span style="color: lightblue">CBO VS Standard</h3>
<p>ABAP 개발 시 매우 많이 들을 단어이기에 지금 확실히 외워두고 가자</p>
<ul>
<li>CBO : 고객(개발자)이 직접 추가로 개발한 프로그램 및 Object<ul>
<li>Customer Bolt On</li>
</ul>
</li>
<li>Standard : SAP 측에서 기본적으로 제공해주는 프로그램 및 Object<ul>
<li>일반적으로 변경 불가</li>
<li>Standard Object의 본질을 훼손하지 않는 선에서 변경을 허락하기 위해 커스터마이징 구멍을 뚫어놓았는데 이 부분은 심화 개념이므로 일단 넘어가겠음</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-lightbluer1-r2-r3"><span style="color: lightblue">R/1, R/2, R/3</h3>
<p>SAP에서 R/1, R/2, R/3 버전이 순차적으로 나와 1, 2, 3이 버전이라고 착각할 수 있다.
하지만 여기서 1, 2, 3은 &quot;N-tier&quot; 중 N을 의미한다.</p>
<p>Tier에 대해 설명하기 전 &quot;R&quot;부터 설명하자.
SAP에서 매우 중요시 생각하는 R은 &quot;Real-time&quot;의 첫 문자를 따온 것이다.</p>
<p>SAP가 개발될 당시 SW는 부가 상품 정도로만 간주되며 고가의 Mainframe의 HW만 중요시되었다.</p>
<blockquote>
<p>Mainframe : 대형 컴퓨터. 통계 데이터, 금융 관련 전산 업무, ERP 같은 복잡한 작업을 처리하는 컴퓨터</p>
</blockquote>
<p>문제는 Mainframe의 경우 데이터를 자기 테이프(Magnetic Tape)에 저장했기에 야간 배치를 통해 일괄 처리 시키는 경우가 많았으며 당연하게도 야간 배치가 돈 후에야 관리하는 데이터(재고, 회계 정보 등)가 실제 상황과 일치하게 되었다.</p>
<p>SAP는 이런 문제를 해결하기 위해 Process를 Real-time으로 처리하도록 만든 시스템이다.</p>
<p>R/1, R/2, R/3는 아래와 같은 특징을 가진다.</p>
<ul>
<li>R/1<ul>
<li>Mainframe(서버)만 존재하는 구조</li>
<li>재무 / 회계 기능만 존재</li>
</ul>
</li>
<li>R/2<ul>
<li>Terminal + Application &amp; Database Server</li>
<li>R/1에 생산 영역을 추가</li>
</ul>
</li>
<li>R/3<ul>
<li>Presentation + Application + Database Server</li>
<li>Client / Server Architecture</li>
<li>R/3부터 ABAP 프로그램을 이용해 프로그램을 개발하고 USER-EXIT 같은 확장(Enhancement)솔루션을 통해 Standard에도 기능을 추가할 수 있게 됨</li>
<li>사용자에게 편리한 화면을 제공한다
<del>고는 하지만 솔직히 사용자 입장에선 엄청 불편하다. GUI 화면을 제공해준다 정도...?</del></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Diff]]></title>
            <link>https://velog.io/@violet_evgadn/Diff</link>
            <guid>https://velog.io/@violet_evgadn/Diff</guid>
            <pubDate>Mon, 25 Sep 2023 15:20:17 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreengit-diff"><span style="color: lightgreen">Git Diff</h1>
<h3 id="span-stylecolor-lightbluegit-diff-사용법"><span style="color: lightblue">Git Diff 사용법</h3>
<pre><code class="language-bash">git diff &lt;저장소 A&gt; &lt;저장소 B&gt;</code></pre>
<p><code>git diff</code> 명령어는 A 저장소를 기반으로 B 저장소와 어떤 차이가 있는지 보여준다.
일반적으로 A는 작업 이전, B는 작업 이후 저장소로 많이 입력한다.</p>
<p><code>git diff</code> 같은 경우 옵션을 사용하지 않을 경우 스테이지에 올라가지 않은 파일들(Untracked 파일들)을 볼 수 없다.
즉, <code>git diff</code>란 일반적으로 Staging에 올라와 있는 파일과 Working Directory에 존재하는 파일들 사이의 차이점을 보여준다는 것을 알 수 있다.</p>
<h3 id="span-stylecolor-lightblueoption--사용법"><span style="color: lightblue">Option &amp; 사용법</h3>
<ul>
<li><p><code>git diff --cached</code> : HEAD와 스테이지와의 차이점 출력</p>
<ul>
<li>장소 A : HEAD / 저장소 B : 스테이지</li>
<li>결과물 = 앞으로 생성할 커밋과 현재 커밋의 차이점</li>
</ul>
</li>
<li><p><code>git diff origin/main main</code> : 원격 브랜치와 현재 브랜치의 내용을 비교</p>
<ul>
<li>Push 할 경우 어떤 내용이 반영되는지 알고 싶을 때 사용</li>
</ul>
</li>
<li><p><code>Git diff branchA branchB</code> : 두 브랜치의 차이를 비교하기 위해 사용</p>
<ul>
<li>PR이나 병합 이전 충돌을 파악할 때 유용하게 활용 가능</li>
</ul>
</li>
<li><p><code>git diff --check</code> : 공백 문자를 체크하는데 유용하게 사용
<img src="https://velog.velcdn.com/images/violet_evgadn/post/94eef0e2-8f77-4eb9-acac-ce6f7b968bfb/image.png" alt=""></p>
<blockquote>
<p>위 이미지를 보면 <code>git diff origin/main main</code> 명령어를 입력했을 때 총 2가지 변경사항이 있음을 알 수 있다.
문제는 변경 사항 중 하나는 &quot;Pull Request 창&quot; 문구 옆에 그저 공백(whiltespace)만 있는 것으로 (일부러 공백을 만든 것이 아닌 이상) 필수적이지 않은 쓰레기 값이다.
이런 값을 원격 저장소에 Push 하기 전에 미리 확인하여 처리해두면 좋을 것이다.
그리고 <code>--check</code> 옵션을 활용할 경우 보다시피 공백의 차이만 존재하는 변경 사항을 볼 수 있으며 해당 변경사항들을 찾아 수정해 준다면 조금 더 깔끔한 Commit을 생성할 수 있을 것이다.</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 작업 중 알면 좋은 것들]]></title>
            <link>https://velog.io/@violet_evgadn/Git-%EC%9E%91%EC%97%85-%EC%A4%91-%EC%95%8C%EB%A9%B4-%EC%A2%8B%EC%9D%80-%EA%B2%83%EB%93%A4</link>
            <guid>https://velog.io/@violet_evgadn/Git-%EC%9E%91%EC%97%85-%EC%A4%91-%EC%95%8C%EB%A9%B4-%EC%A2%8B%EC%9D%80-%EA%B2%83%EB%93%A4</guid>
            <pubDate>Mon, 25 Sep 2023 14:47:33 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenunstaging-시키기"><span style="color: lightgreen">Unstaging 시키기</h1>
<h3 id="span-stylecolor-lightbluerestore-활용-"><span style="color: lightblue">restore 활용 ***</h3>
<pre><code class="language-bash">git restore --staged [File Name]</code></pre>
<p>웬만하면 이 방법을 활용하도록 하자.</p>
<h3 id="span-stylecolor-lightbluerm-활용"><span style="color: lightblue">rm 활용</h3>
<pre><code class="language-bash">git rm --cached [File Name]</code></pre>
<h3 id="span-stylecolor-lightbluereset-활용"><span style="color: lightblue">reset 활용</h3>
<pre><code class="language-bash">git reset [File Name]</code></pre>
<hr>
<h1 id="span-stylecolor-lightgreen커밋-내용-삭제하기"><span style="color: lightgreen">커밋 내용 삭제하기</h1>
<blockquote>
<p>만약 실수로 개인정보나 Key값을 원격 저장소에 Push했다면 어떻게 해야할까?
실수로 등록했던 중요 정보를 지운 뒤 다시 커밋하더라도 중요 정보를 등록했던 커밋은 Log상 남아있기 떄문에 커밋 자체를 삭제해야 한다.
이 방법을 알아보자.</p>
</blockquote>
<h3 id="span-stylecolor-lightblue1-reset-수행"><span style="color: lightblue">1. reset 수행</h3>
<pre><code class="language-bash">git reset [커밋ID]</code></pre>
<p>중요 정보를 저장하고 있는 커밋 직전에 위치해있는 커밋 ID를 입력한다.
<code>HEAD~&lt;숫자&gt;</code>를 사용해도 되지만 이전에 말했듯 개인적으로 좋아하는 방법은 아니다.</p>
<h3 id="span-stylecolor-lightblue2-git-reset-내역-push"><span style="color: lightblue">2. Git Reset 내역 Push</h3>
<pre><code class="language-bash">git push -f origin [Branch Name]</code></pre>
<p>여기서 가장 중요한 점이 <code>-f</code> 옵션이다.</p>
<p>결과적으로 Git Log가 변경되는 Git 명령어 같은 경우 무조건 <code>-f</code> 옵션과 같이 활용할 필요가 있다.
(엄밀히 말하면 존재하던 커밋을 삭제하는 것이므로 강제로 Push하지 않으면 Git 측에서 에러가 발생한 것으로 인지하기 때문이다)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 고급]]></title>
            <link>https://velog.io/@violet_evgadn/Git-%EA%B3%A0%EA%B8%89</link>
            <guid>https://velog.io/@violet_evgadn/Git-%EA%B3%A0%EA%B8%89</guid>
            <pubDate>Mon, 25 Sep 2023 14:46:12 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenrebase--i"><span style="color: lightgreen">Rebase -i</h1>
<h3 id="span-stylecolor-lightbluerebase--i란"><span style="color: lightblue"><code>rebase -i</code>란?</h3>
<p>이전에 말했듯 필자는 <code>rebase</code>라는 명령어를 그렇게 좋아하지 않는다.
하지만 <code>rebase -i</code>는 가끔 활용하는데 이 명령어를 통해 과거의 커밋을 수정할 수 있기 때문이다.</p>
<p><code>git rebase -i</code>를 수행하면 HEAD와 지정한 커밋 사이의 커밋들의 히스토리를 수정할 수 있다.
<code>git rebase -i</code>를 수행하면 에디터에는 커밋들의 목록이 보이며 각 커밋 앞에 옵션들 중 하나를 활용함으로써 커밋을 선택 편집할 수 있다.</p>
<p><code>rebase -i</code> 명령으로 출력되는 커밋들은 Git Log와 달리 아래쪽으로 갈수록 최신 커밋이다.
또한 <code>rebase -i</code>는 &quot;지정한 커밋과 HEAD 사이의 커밋들&quot;을 수정할 수 있는 명령어이므로 최초 커밋인 init 커밋은 수정이 불가능하다는 특징을 가진다.</p>
<h3 id="span-stylecolor-lightbluerebase--i-옵션"><span style="color: lightblue"><code>rebase -i</code> 옵션</h3>
<ul>
<li><p>p(pick) : 커밋을 변경 없이 활용</p>
<ul>
<li>기본 옵션</li>
</ul>
</li>
<li><p>r(reword) : 커밋 메시지를 편집</p>
</li>
<li><p>e(edit) : 커밋을 수정(amend) 할 수 있도록 일시 정지 상태가 됨</p>
</li>
<li><p>s(squash) : 커밋이 부모 커밋에 합쳐져 커밋이 사라진 것처럼 보임</p>
</li>
<li><p>d(drop) : 해당 커밋을 제거함</p>
</li>
</ul>
<h3 id="span-stylecolor-lightbluerebase--i-창"><span style="color: lightblue"><code>rebase -i</code> 창</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/f7f0612c-2995-4256-8f37-7f379d4549e2/image.png" alt=""></p>
<p>위에서 말했듯 아래로 갈수록 최신 커밋이며 <code>pick</code> 부분을 원하는 옵션으로 바꾸어 원하는 동작을 수행할 수 있다.</p>
<hr>
<h1 id="span-stylecolor-lightgreen히스토리에서-파일-삭제하기"><span style="color: lightgreen">히스토리에서 파일 삭제하기</h1>
<h3 id="span-stylecolor-lightblue1-파일의-히스토리-조회"><span style="color: lightblue">1. 파일의 히스토리 조회</h3>
<pre><code class="language-bash">git blame [-L &lt;시작 줄, 끝줄&gt;]</code></pre>
<p>해당 파일을 변경했던 커밋 히스토리를 보여준다.
<code>-L</code> 옵션을 사용할 경우 시작 줄과 끝 줄을 지정하여 특정 범위를 누가 변경했는지에 대한 히스토리도 볼 수 있다.</p>
<p>해당 명령어를 통해 삭제해야 할 내용(혹은 파일)이 어떤 커밋에서 최초로 추가되었는지 확인할 수 있다.</p>
<h3 id="span-stylecolor-lightblue2-히스토리의-파일-삭제"><span style="color: lightblue">2. 히스토리의 파일 삭제</h3>
<pre><code class="language-bash">git filter-branch --tree-filter &#39;rm -f &lt;파일이름&gt;&#39; HEAD</code></pre>
<p>HEAD로부터 모든 히스토리에서 지정한 파일을 삭제하는 명령어이다.
<code>git filter-branch</code> 명령은 다양한 기능을 가지고 있는데 그 \중 <code>--tree-filter</code> 옵션은 히스토리 전체에서 원하는 파일을 삭제할 수 있게 된다.</p>
<p>추가로 원격 저장소에도 이 설정을 적용해야 한다면 로컬 저장소에서 먼저 위 명령어로 파일 삭제 처리를 한 뒤 <code>git push -f</code> 명령을 통해 변경 사항을 적용해 줘야 한다.</p>
<p>참고로 “BFG”라는 프로그램이 있는데 이 프로그램을 통해 더욱 쉽게 히스토리에서 파일을 삭제할 수 있다.</p>
<hr>
<h1 id="span-stylecolor-lightgreengit-단축-명령-만들기"><span style="color: lightgreen">Git 단축 명령 만들기</h1>
<p>git alias를 사용하면 git 명령어를 조금 더 쉽게 사용할 수 있다.
보통 <code>--global</code> 옵션과 함께 사용하는 게 좋다.</p>
<h3 id="span-stylecolor-lightbluealias-지정-방법"><span style="color: lightblue">Alias 지정 방법</h3>
<pre><code class="language-bash"># st라는 이름을 가진 git 단축 명령 생성
git config --global alias.st status</code></pre>
<p>위와 같이 <code>alias.&lt;별칭&gt;</code>으로 별칭을 지정하면 그 옆에 있는 명령어(위에선 <code>status</code>)가 <code>git</code> 명령어 뒤의 옵션이나 명령어로 입력되는 것과 동일하게 동작한다.</p>
<p>즉, 위와 같이 지정한 후 <code>git st</code>를 입력하면 <code>git status</code>를 입력한 것과 동일하게 동작하는 것이다.</p>
<p>만약 Option까지 포함하고 싶다면 모든 명령어를 큰따옴표(&quot;&quot;)로 묶어주면 된다.</p>
<pre><code class="language-bash"># git graph라는 단축 명령어 생성
git config --global alias.graph “log –oneline – graph –all”</code></pre>
<hr>
<h1 id="span-stylecolor-lightgreenglobal-gitignore-만들기"><span style="color: lightgreen">Global .gitignore 만들기</h1>
<p>일반적으로 <code>.gitignore</code>파일은 .git 파일이 위치한 폴더(Git 작업 폴더)에 생성한다.</p>
<p>하지만 OS별로 무조건적으로 생기는 필요 없는 파일이나 보안적으로 민감한 파일들은 설정 없이도 무조건 커밋 되지 않도록 설정하고 싶을 수 있다.
이때 <code>global_gitignore</code>를 활용할 수 있다.</p>
<p>방법은 간단하다.</p>
<ol>
<li><p><code>global_gitignore</code>라는 파일을 사용자의 홈 폴더에 생성</p>
</li>
<li><p>파일에 커밋 시키고 싶지 않은 파일들 입력</p>
<ul>
<li><code>.gitignore</code> 파일을 생성하는 것과 동일하게 만들면 된다.</li>
</ul>
</li>
<li><p><code>git config --global core.excludesfile [global_gitignore 파일 절대 경로]</code></p>
<ul>
<li>위 명령어를 통해 <code>global_gitignore</code> 파일을 Global .gitignore 폴더로 설정할 수 있음</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 기타 명령어]]></title>
            <link>https://velog.io/@violet_evgadn/Git-%EA%B8%B0%ED%83%80-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@violet_evgadn/Git-%EA%B8%B0%ED%83%80-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Mon, 25 Sep 2023 14:40:14 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreengit-기타-명령어"><span style="color: lightgreen">Git 기타 명령어</h1>
<h3 id="span-stylecolor-lightbluegit-status"><span style="color: lightblue">git status</h3>
<pre><code class="language-bash">git status</code></pre>
<p>Git 워킹트리의 상태를 보는 명령어로 많이 활용된다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/ac0a201a-5b55-4179-866a-317737aff8b5/image.png" alt=""></p>
<p>사진에서 보듯 현재 Branch 및 커밋 가능 대상, Working Tree를 보여준다.
<code>-s</code> 옵션을 붙임으로써 <code>git status</code>를 요약한 Git 상태를 볼 수도 있다.</p>
<h3 id="span-stylecolor-lightbluegit-명령어-옵션-설정"><span style="color: lightblue">Git 명령어 옵션 설정</h3>
<pre><code class="language-bash"># 지정한 전역 옵션 내용 보기
git config --global &lt;옵션명&gt;

# 지정한 전역 옵션 값을 (새로) 설정
git config --global &lt;옵션명&gt; &lt;Value&gt;

# 지정한 전역 옵션 삭제
git config --global --unset &lt;옵션명&gt;</code></pre>
<ul>
<li><p>지역 옵션 : 위 명령어에서 <code>--global</code> ➙ <code>--local</code>로 변경</p>
</li>
<li><p>시스템 옵션 : 위 명령어에서 <code>--global</code> ➙ <code>--system</code>으로 변경</p>
</li>
</ul>
<blockquote>
<p>Git 계정 설정을 위해 <code>user.name</code>(사용자 이름), <code>user.email</code>(사용자 이메일) 정도는 꼭 설정해주자.</p>
</blockquote>
<h4 id="span-stylecolor-orange현재-프로젝트의-모든-git-옵션-출력하기"><span style="color: orange">현재 프로젝트의 모든 Git 옵션 출력하기</h4>
<pre><code class="language-bash">git config --list</code></pre>
<p>설정된 Git 옵션이 없다면 아무것도 출력되지 않는다.</p>
<h3 id="span-stylecolor-lightblueworking-directory를-로컬-저장소로-만들기"><span style="color: lightblue">Working Directory를 로컬 저장소로 만들기</h3>
<pre><code class="language-bash">git init -b main</code></pre>
<p>기본 브랜치를 main으로 지정하여 현재 Working Directory를 로컬 저장소로 만든다.</p>
<h3 id="span-stylecolor-lightbluegit-log-보기"><span style="color: lightblue">Git Log 보기</h3>
<pre><code class="language-bash"># 커밋 이력 보기
git log

# 전체 커밋 중 최신 N개의 커밋만 보기
git log -n &lt;숫자&gt;

# 모든 브랜치들에 대한 커밋 이력을 보고 싶을 떄 사용
git log --oneline --graph --all --decorate</code></pre>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/51184560-b0b7-488b-bb9a-a804b0029654/image.png" alt=""></p>
<p>참고로 Git Log는 위 명령어를 통해 볼 수도 있지만 실제 Git을 사용할 땐 GUI 환경으로 Log를 확인하는 경우가 더 많다.
(실제 업무를 진행할 땐 GUI와 CLI를 동시에 사용한다)</p>
<ul>
<li><p><code>--graph</code> : 브랜치 흐름을 그래프로 보여줌</p>
</li>
<li><p><code>--all</code> : 현재 HEAD와 관계없는 커밋들도 보여줌</p>
</li>
</ul>
<h3 id="span-stylecolor-lightblue원격-저장소-관련-명령어"><span style="color: lightblue">원격 저장소 관련 명령어</h3>
<pre><code class="language-bash"># 원격 저장소 등록(일반적으로 origin으로 지정)
git remote add &lt;원격 저장소 이름&gt; &lt;원격 저장소 주소&gt;

# 원격 저장소 목록 보기
git remote -v

# 원격 저장소 별칭 갱신
git remote rename &lt;이전 Alias&gt; &lt;현재 Alias&gt;

# 원격 저장소 삭제
git remote remove &lt;저장소 Alias&gt;</code></pre>
<p>개인적으론 원격 저장소 등록을 여러 개 할 필요가 있나 생각이 든다.</p>
<p>책에서는 여러 원격 저장소를 이용한 분산 관리 기능이 Git의 필수적인 기능이라고 했지만, 이를 과도하게 사용할 경우 오히려 보안적인 문제나 코드 유실 등의 문제가 발생할 것 같다. </p>
<h3 id="span-stylecolor-lightblueuntracked-파일-및-폴더-한번에-삭제"><span style="color: lightblue">Untracked 파일 및 폴더 한번에 삭제</h3>
<pre><code class="language-bash">git clean -f -d &lt;파일 또는 폴더 이름&gt;</code></pre>
<hr>
<h1 id="span-stylecolor-lightgreen기본-git-명령어-복습"><span style="color: lightgreen">기본 Git 명령어 복습</h1>
<h3 id="span-stylecolor-lightbluestaging"><span style="color: lightblue">Staging</h3>
<pre><code class="language-bash">git add &lt;파일명&gt;</code></pre>
<h3 id="span-stylecolor-lightbluecommit"><span style="color: lightblue">Commit</h3>
<pre><code class="language-bash">git commit</code></pre>
<p><code>-a</code> 옵션을 붙여 <code>git add</code> 명령(Staging 과정)을 생략하고 바로 커밋 할 수 있다.
(단, 이때 Untracked 파일은 커밋 되지 않는다)</p>
<h3 id="span-stylecolor-lightbluepush"><span style="color: lightblue">Push</h3>
<pre><code class="language-bash">git push [-u] [원격 저장소 Alias] [브랜치 이름]</code></pre>
<p><code>-u</code> 옵션을 사용할 경우 브랜치의 <code>upstream</code>을 지정할 수 있다.
원격 저장소를 한 번이라도 등록했다면 이후에는 <code>git push</code>만 입력해도 동작한다.</p>
<h3 id="span-stylecolor-lightbluepull"><span style="color: lightblue">Pull</h3>
<pre><code class="language-bash">git pull</code></pre>
<h3 id="span-stylecolor-lightbluemerge"><span style="color: lightblue">Merge</h3>
<pre><code class="language-bash">git merge &lt;대상 브랜치&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 용어 정리]]></title>
            <link>https://velog.io/@violet_evgadn/Git-%EC%B6%94%EA%B0%80-%EC%84%A4%EB%AA%85</link>
            <guid>https://velog.io/@violet_evgadn/Git-%EC%B6%94%EA%B0%80-%EC%84%A4%EB%AA%85</guid>
            <pubDate>Mon, 25 Sep 2023 13:43:25 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightbluegit-용어-정리"><span style="color: lightblue">Git 용어 정리</h1>
<h3 id="span-stylecolor-lightbluegit-작업-공간-관련-용어"><span style="color: lightblue">Git 작업 공간 관련 용어</h3>
<h4 id="span-stylecolor-orangeworking-treeworking-directory"><span style="color: orange">Working Tree(Working Directory)</h4>
<ul>
<li><p>개발자가 일반적으로 작업하는 장소</p>
</li>
<li><p>공식 문서에서는 &quot;커밋을 체크아웃하면 생성되는 파일과 디렉터리&quot;로 정의하고 있음</p>
</li>
<li><p>작업 폴더 중 <code>.git 폴더</code>(로컬 저장소)를 제외한 나머지 부분을 의미한다.</p>
</li>
</ul>
<h4 id="span-stylecolor-orange로컬-저장소"><span style="color: orange">로컬 저장소</h4>
<ul>
<li><p><code>.git 폴더</code>를 의미하며 커밋이 저장되는 장소</p>
</li>
<li><p>커밋을 구성하는 객체, 스테이지 그리고 커밋 자체가 저장되는 공간</p>
</li>
</ul>
<h4 id="span-stylecolor-orange원격-저장소"><span style="color: orange">원격 저장소</h4>
<ul>
<li><p>로컬 저장소 작업물을 업로드하는 공용 저장소</p>
</li>
<li><p>대표적인 원격 저장소 사이트 : Github, Bitbucket</p>
</li>
</ul>
<h4 id="span-stylecolor-orangegit-저장소"><span style="color: orange">Git 저장소</h4>
<ul>
<li><p>공식 문서 : Only 로컬 저장소</p>
</li>
<li><p>일반적으로 생각되는 Git 저장소 : Working Tree + 로컬 저장소</p>
</li>
<li><p>Git 명령을 통해 관리할 수 있는 폴더 전체를 의미</p>
</li>
</ul>
<h3 id="span-stylecolor-lightbluegit-작업-관련-용어"><span style="color: lightblue">Git 작업 관련 용어</h3>
<blockquote>
<p>지금까지 Git을 공부했다면 이해했겠지만 Git은 결국 &quot;커밋 히스토리를 관리하는 시스템&quot;이라는 것을 알 수 있다.  </p>
</blockquote>
<p>다른 말로 커밋 히스토리를 통해 코드 형상을 관리하는 시스템이라 할 수 있으며 이를 토대로 깃 용어를 아래와 같이 해석 가능하다.</p>
<ul>
<li><p>저장소 : 모든 커밋의 모음</p>
</li>
<li><p>브랜치 : 특정 히스토리를 가지는 커밋의 모음</p>
</li>
<li><p>스테이지 : 미래의 커밋</p>
</li>
<li><p>커밋 : Git 기본 저장 단위로 작업 파일 묶음</p>
</li>
<li><p>작업 폴더 : 스테이지를 최신화하거나 스테이지에 파일을 추가하기 위한 준비 영역</p>
</li>
<li><p>스태시 : 커밋들이 임시로 저장되는 임시 진열장</p>
</li>
</ul>
<p>기존에 &quot;Working Tree&quot;와 &quot;Stage&quot;를 중요시했을 수도 있겠지만 앞으로는 <code>Git = 커밋</code>이라고 이해하고 활용하도록 하자.</p>
<h3 id="span-stylecolor-lightbluegit-옵션-용어"><span style="color: lightblue">Git 옵션 용어</h3>
<blockquote>
<p>Git 옵션 우선순위 : 지역 &gt; 전역 &gt; 시스템</p>
</blockquote>
<ul>
<li><p>시스템 환경 옵션 : PC를 사용하는 모든 Git 사용자를 위한 옵션</p>
</li>
<li><p>전역 옵션 : 현재 Git 사용자를 위한 옵션</p>
</li>
<li><p>지역 옵션 : 현재 Git 저장소에서만 유효한 옵션</p>
</li>
</ul>
<p>대부분의 경우 전역 옵션을 설정하여 Git을 사용하지만 가끔 공용 PC나 다른 설정으로 Git을 사용해야 할 경우 지역 옵션을 사용할 때도 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[swith & restore]]></title>
            <link>https://velog.io/@violet_evgadn/checkout%EC%9D%84-%EB%8C%80%EC%B2%B4%ED%95%A0-swith</link>
            <guid>https://velog.io/@violet_evgadn/checkout%EC%9D%84-%EB%8C%80%EC%B2%B4%ED%95%A0-swith</guid>
            <pubDate>Thu, 07 Sep 2023 04:16:40 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenswitch--restore"><span style="color: lightgreen">Switch &amp; Restore</h1>
<h3 id="span-stylecolor-lightblueswitch"><span style="color: lightblue">switch</h3>
<p>Git Switch는 브랜치를 변경하는 명령어이다.</p>
<p><code>git switch</code> 명령을 수행하면 브랜치가 이동되는데 이 과정에서 먼저 <code>.git/HEAD</code> 값이 원하는 브랜치의 커밋 ID 값으로 변경되는 과정이 수행된다.
앞에서 말했듯 <code>.git</code> 폴더는 로컬 저장소로 여러 가지 파일을 가지고 있다. 이 중 <code>HEAD</code> 값은 현재 Git 시스템이 가리키고 있는 커밋 ID를 의미한다.
브랜치 이동은 Git HEAD를 원하는 브랜치의 최신 커밋을 가리키게 하는 동작이기 때문에 왜 <code>.git/HEAD</code> 값만 변경함으로써 브랜치가 변경되는지도 이해할 수 있을 것이다.</p>
<p>이후 <code>git switch</code> 명령은 <code>git reset --hard</code> 명령어를 통해 Stage 및 Working Tree 작업 내용을 HEAD가 가리키는 내용으로 초기화시켜준다.
만약 Staging 된 변경 사항들을 유지시킨다면 HEAD는 다른 브랜치를 가리키고 있는데 정작 내용물은 기존 브랜치의 작업물을 가지고 있는 어지러운 상황이 될 수 있다.</p>
<p>정리하자면 <code>git switch</code> 명령은 <code>.git/HEAD</code> 값을 변경시켜 HEAD의 값을 원하는 브랜치의 최신 커밋 ID 값으로 변경하고 <code>git reset --hard</code> 명령어를 통해 Stage 및 Working Tree 작업 내용을 초기화시켜주는 작업이 수행되는 것이다.
(따라서 <code>git switch</code>를 수행하면 Working Directory의 작업물도 해당 브랜치의 작업물로 변환되는  것이다)</p>
<h3 id="span-stylecolor-lightbluerestore"><span style="color: lightblue">restore</h3>
<p><code>git restore</code>는 git의 파일 조작(특정 커밋으로 되돌리기, Unstaging 시키기 등)을 위해 만들어진 명령어이다.</p>
<p>조금 더 간단히 말하자면 몇 개의 파일들을 특정 커밋이 가지고 있는 파일의 상태로 변경하는 명령어이다.
반대로 이를 조금 전문적으로 말하면 특정 파일을 워킹 트리에 존재하는 상태 중 하나로 복원해 주는 명령어라고 할 수 있다.</p>
<h3 id="span-stylecolor-lightblue그렇다면-왜-2개를-한번에-설명했을까"><span style="color: lightblue">그렇다면 왜 2개를 한번에 설명했을까?</h3>
<p>바로 <code>git restore</code>와 <code>git switch</code>가 <code>git checkout</code>을 대체하기 위해 나온 명령어이기 때문이다.</p>
<blockquote>
<p><code>git checkout</code> = <code>git restore</code> + <code>git switch</code></p>
</blockquote>
<p>사실 이전까지 브랜치를 이동하거나 특정 파일을 복원할 때 <code>git checkout</code>을 사용하는 것이 더 일반적이었을 것이다.</p>
<ul>
<li><p>브랜치 이동 : <code>git checkout &lt;브랜치명&gt;</code></p>
</li>
<li><p>파일 복원 : <code>git checkout &lt;커밋 ID&gt; &lt;파일 이름&gt;</code></p>
</li>
</ul>
<p>하지만 git 시스템이 계속해서 업그레이드되면서 점차 <code>git checkout</code>이 가진 기능이 너무 많아졌다.
이렇게 한 명령어가 너무 많은 기능을 가지는 것은 객체 지향적으로 봤을 때 SRP(한 클래스는 하나의 책임만 가져야 한다)라는 원칙에 위배되고 잘못하면 <a href="https://en.wikipedia.org/wiki/God_object">God Object</a>와 같은 잘못된 설계의 명령어가 될 수도 있다.</p>
<p>따라서 Git 시스템은 여러 버전 업그레이드를 거치며 <code>checkout</code>이라는 명령어를 복원 역할의 <code>restore</code>와 브랜치 이동의 <code>switch</code>로 쪼갰고 이를 나타내고자 관계도 없을 것 같아 보이는 2개 명령어를 한 Section에서 설명하게 되었다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenrestore"><span style="color: lightgreen">restore</h1>
<ul>
<li><p><code>git restore [File Name]</code> : 지정한 파일을 HEAD가 가리키고 있는 Commit 상태로 복구</p>
</li>
<li><p><code>git restore --source [커밋 ID] [File Name]</code> : 특정 파일을 특정 Commit 상태로 복구</p>
</li>
<li><p><code>git restore --staged [File Name]</code> :  Staging된 파일을 다시 Unstaging 시킴</p>
<ul>
<li><code>git add</code> 명령어로 Staging Area에 등록된 파일을 다시 Staging Area에서 내리는 동작을 수행한다.</li>
</ul>
</li>
</ul>
<hr>
<h1 id="span-stylecolor-lightgreenswitch"><span style="color: lightgreen">switch</h1>
<ul>
<li><p><code>git switch [Branch Name]</code> : 지정한 브랜치로 이동</p>
</li>
<li><p><code>git switch -c [Branch Name]</code> : 브랜치를 새로 생성한 뒤 생성한 브랜치로 이동</p>
<ul>
<li><code>git checkout -b [Branch Name]</code> 명령어와 동일하게 동작한다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[fatal : The current branch main has no upstream branch.]]></title>
            <link>https://velog.io/@violet_evgadn/fatal-The-current-branch-main-has-no-upstream-branch.-To-pus-hthe-current-branch-and-set-the-remote-as-upstream</link>
            <guid>https://velog.io/@violet_evgadn/fatal-The-current-branch-main-has-no-upstream-branch.-To-pus-hthe-current-branch-and-set-the-remote-as-upstream</guid>
            <pubDate>Thu, 07 Sep 2023 02:45:56 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreengit-push-에러"><span style="color: lightgreen">Git Push 에러</h1>
<h3 id="span-stylecolor-lightblueupstream"><span style="color: lightblue">upstream</h3>
<p>위 에러 메시지를 이해하기 위해선 Git의 &quot;upstream&quot;이라는 개념을 알아야 한다.</p>
<p><code>upstream</code>은 <code>origin</code>과 마찬가지로 원격 저장소의 위치를 나타내는 용어이다.</p>
<p>결론부터 말해보자.
<code>origin</code>은 현재 레포지토리를 기준으로 현재 레포지토리를 받아온 원격 저장소를 의미한다.
그리고 <code>upstream</code>이란 <code>origin</code>의 <code>origin</code>이 되는 원격 저장소를 의미한다.</p>
<p>이미지를 통해 알아보자.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/b6d1b185-7206-40ad-8c72-9d7d6e0519d8/image.png" alt=""></p>
<p>오픈 소스 프로젝트를 Fork 하여 내 Github 계정의 원격 저장소에 저장한 뒤 나의 원격 저장소를 Clone 하여 로컬 저장소를 만들고 싶다고 가정하자.</p>
<p>이런 상황에서 Working Directory가 보기엔 자신에게 코드를 준 내 Github 계정의 원격 저장소는 <code>origin</code>이 되며 이는 이전에도 설명했다.
이런 상황에서 Working Directory가 보기엔 실제 코드를 다운로드한 오픈 소스 프로젝트는 &quot;원격 저장소의 조상 원격 저장소&quot;라는 의미를 가진다. 하지만 이 오픈 소스 프로젝트를 저장하고 있는 원격 저장소를 &quot;origin의 부모 원격 저장소&quot;로 부르기엔 직관적이지도 않고 불편하다.</p>
<p>따라서 이런 상황을 대비해 원격 저장소의 조상 원격 저장소에 <code>upstream</code>이라는 이름을 달아준 것이다.</p>
<h3 id="span-stylecolor-lightblueerror가-발생하는-이유"><span style="color: lightblue">Error가 발생하는 이유</h3>
<p>일단 위 에러 메시지를 직독직해 해보자.</p>
<blockquote>
<p>fatal : 현재 브랜치인 Main은 upstream Branch를 가지고 있지 않습니다.</p>
</blockquote>
<p>&quot;<code>upstream</code>이 원격 저장소다&quot;라는 개념을 알고 있다면 위 문구가 왜 발생했을지 쉽게 이해할 수 있을 것이다.</p>
<p>&quot;로컬 저장소의 현재 브랜치와 연결되어 있는 원격 저장소 브랜치가 없기 때문&quot;에 해당 에러가 발생한다.</p>
<p>로컬 저장소의 현재 브랜치와 연결되어 있는 원격 저장소 브랜치가 존재하지 않기 때문에 Git 입장에선 로컬 저장소의 커밋을 어느 장소에 Push 해야 할지 알 수 없다.
따라서 Git 입장에선 Push 명령을 받았으나 Push의 목적지를 알 수 없고, 이를 알리기 위해 위와 같은 에러 메시지를 던지는 것이다.</p>
<blockquote>
<p>(뇌피셜)
그렇다면 왜 <code>origin</code>이 아닌 <code>upstream</code>으로 에러 문구를 정해놨을까?
대부분의 경우 로컬 저장소에서 <code>origin</code>으로 지정한 원격 저장소에 Git Push를 진행할 텐데 말이다.</p>
</blockquote>
<p>개인적으로는 Git Pull이나 Push를 <code>origin</code>뿐만 아니라 <code>upstream</code>에도 수행할 수 있기 때문이라고 생각한다.</p>
<blockquote>
</blockquote>
<p>Git에서는 원격 저장소의 위치에 관계 없이 Pull 받거나 Push 할 수 있기 때문에 <code>upstream</code>과 <code>origin</code> 모두 위와 같은 문제가 발생할 수 있다.
(즉, <code>upstream</code>에 Push 하려 했는데 <code>upstream</code> 쪽에 로컬과 연결되어 있는 브랜치가 존재하지 않을 수 있다)
<code>upstream</code>과 <code>origin</code> 모두 상대적인 위치가 다를 뿐 &quot;원격 저장소&quot;를 나타내는 용어임은 변하지 않으므로 더 상위 저장소인 <code>upstream</code>을 에러 메시지에 포함시킴으로써 더 넓은 범위 개념을 사용해 유사한 에러를 한 번에 처리할 수 있게 한 것이 아닐까 싶다.</p>
<h3 id="span-stylecolor-lightblueerror-해결-방법"><span style="color: lightblue">Error 해결 방법</h3>
<p>위 에러의 해결 방법은 에러 문구에 이어 적혀 있는 문장에 명시되어 있다.</p>
<blockquote>
<p>To push the current branch and set the remote as upstream, use git push --set-upstream origin main</p>
</blockquote>
<p>즉, 단순히 <code>git push</code> 명령어에 <code>--set-upstream</code> 옵션을 붙여 로컬 브랜치와 원격 브랜치를 연결해 주면 되며 이를 위해 아래와 같은 코드를 입력해 주면 될 것이다.</p>
<pre><code class="language-bash">git push --set-upstream origin main</code></pre>
<p>추가로 <code>--set-upstream</code> 옵션은 <code>-u</code>이라는 단축 옵션도 가지고 있으므로 둘 중 하나를 활용하면 된다.</p>
<h3 id="span-stylecolor-lightblue추가-설명"><span style="color: lightblue">추가 설명</h3>
<p>위에서 <code>git push --set-upstream origin main</code> 명령어를 입력하라고 했지만, 사실 <code>main</code>이 고정 입력값은 아니다.
오히려 <code>main</code>이 아닌 다른 로컬 브랜치에서 작업을 수행하다가 위와 같은 에러가 났다면 <code>main</code>이 아닌 다른 값을 입력해 줘야 한다.</p>
<p>필수 사항은 아니지만 대부분 로컬 저장소의 브랜치와 해당 브랜치와 연결되어 있는 원격 저장소의 브랜치 이름은 동일하게 하는 것이 암묵적인 룰이다
사실 암묵적인 룰이라기보단 편의성을 위해 이렇게 하는 게 당연한데 만약 연동되어 있는 로컬 브랜치와 원격 브랜치 이름이 다르다면 해당 연결 관계를 파악하는데 추가적인 노력을 기울여야 하므로 매우 비효율적일 것이다.</p>
<p>이런 점을 고려했을 때 사실 <code>--set-upstream</code>의 제대로 된 사용 방법은 아래와 같을 것이다.</p>
<pre><code class="language-bash">git push --set-upstream origin &lt;로컬 브랜치 이름&gt;</code></pre>
<p>실제로 GUI에서 (원격 저장소에 로컬 저장소 이름을 가진 브랜치가 없을 경우) Git Push를 수행하면 자동으로 &quot;로컬 브랜치와 동일한 이름의 브랜치&quot;가 원격 저장소에 생성된 뒤 Push가 진행됨을 볼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Stash]]></title>
            <link>https://velog.io/@violet_evgadn/Stash</link>
            <guid>https://velog.io/@violet_evgadn/Stash</guid>
            <pubDate>Thu, 07 Sep 2023 02:23:34 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenstash"><span style="color: lightgreen">Stash</h1>
<h3 id="span-stylecolor-lightbluestash란"><span style="color: lightblue">Stash란?</h3>
<p>Git Stash는 현재의 작업 내용을 임시 저장하는 기능이다.</p>
<p>현재의 작업물을 잠깐 서랍에 넣어두고 특정 커밋으로 이동하여 작업을 완료한 뒤 서랍에 넣어둔 작업물을 다시 꺼내 쓸 수 있게 해주는 기능이라고 이해하면 편하다.</p>
<p>그렇다면 이러한 Stash는 왜 필요할까?</p>
<p>현업에서 일을 하다 보면 항상 내가 하고 있는 일이 완료된 뒤 다음 일을 수행한다는 보장이 없다.
A라는 기능을 개발하고 있는데 이 A라는 기능을 위해 변경 파일 10개가 로컬에 생성되어 있고 이 상황에서 현재 운영되고 있는 서비스에 핫픽스 해야 하는 버그가 생겼다고 가정하자.
이 버그를 해결하려면 main 브랜치로 이동해야 할 텐데 만약 main 브랜치로 이동(<code>checkout</code>)한다면 A 기능을 위한 10개의 변경 파일이 없어질 것이다.
그렇다고 10개의 변경 파일을 커밋 하기엔 아직 파일들이 미완성된 파일들이기에 쓰레기 커밋을 생성하게 될 것이다.</p>
<p>이 경우 <code>git stash</code>를 통해 10개의 변경 파일들을 임시 저장시켜 놓은 뒤 main 브랜치에 checkout하여 작업을 수행하면 된다.
이렇게 된다면 버그를 핫픽스 한 뒤 원래 작업하던 브랜치로 돌아와 Stash에 저장한 임시 파일을 불러옴으로써 계속해서 A 기능에 대한 작업을 수행할 수 있을 것이다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenintellij를-활용한-stash"><span style="color: lightgreen">IntelliJ를 활용한 Stash</h1>
<blockquote>
<p>Git Stash 같은 경우 CLI를 통해 활용하는 경우가 더 많다.
필자도 Git Stash를 CLI로만 활용하다 이번 정리를 위해 처음 IntelliJ에서 활용해 보았다.
IntelliJ에서의 활용법은 한 번 훑어만 보고 CLI를 통한 Stash 활용법에 조금 더 집중하는 것을 추천한다.</p>
</blockquote>
<h2 id="span-stylecolor-lightbluestash-생성"><span style="color: lightblue">Stash 생성</h2>
<h3 id="span-stylecolor-orange0-stash-테스트를-위한-변경-사항-생성"><span style="color: orange">0. Stash 테스트를 위한 변경 사항 생성</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/2f06ee54-b81e-4399-816b-a378a1bd7809/image.png" alt="">
<code>Stash가 제대로 될까?</code>라는 문구를 추가하였다.
(절대로 Commit 하지는 말자. Stash는 &quot;커밋 하지 않은 변경사항&quot;들을 저장하는 기능이다)</p>
<h3 id="span-stylecolor-orange1-git--uncommitted-changes--stash-changes-선택"><span style="color: orange">1. Git &gt; Uncommitted Changes &gt; Stash Changes 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/57500f1a-eee0-4f42-af79-dccc5580727e/image.png" alt=""></p>
<h3 id="span-stylecolor-orange2-create-stash"><span style="color: orange">2. Create Stash</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/c8c88bb7-40cd-4a0d-8d8c-253213fb3723/image.png" alt=""></p>
<p>Message에 Stash를 구별할 수 있을만한 문구를 기입하자.
어떤 기능을 개발하고 있던 중인지 입력하는 것을 추천한다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/19a79e9b-ad1c-4698-be4f-945ddcdcfd8a/image.png" alt=""></p>
<p>추가했던 문구가 삭제된 것을 볼 수 있다.
현재 상황은 마지막 Commit의 상황이기 때문에 마음 놓고 다른 브랜치에 Checkout 하거나 다른 작업을 수행할 수 있다.</p>
<h2 id="span-stylecolor-lightbluestash-가져오기"><span style="color: lightblue">Stash 가져오기</h2>
<p>작업이 완료되어 다시 Stash에 저장했던 변경 사항을 가져오고 싶다.
어떻게 가져올 수 있는지 알아보자.</p>
<h3 id="span-stylecolor-orange3-git--uncommitted-changes--unstash-changes-선택"><span style="color: orange">3. Git &gt; Uncommitted Changes &gt; Unstash Changes 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/b2a27dbc-d026-41ea-bd73-6f365c3b60b6/image.png" alt=""></p>
<h3 id="span-stylecolor-orange4-원하는-stash-선택--apply-stash-선택"><span style="color: orange">4. 원하는 Stash 선택 &gt; <code>Apply Stash</code> 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/cd2fa3fb-1a9f-4c0b-a844-5a4daa4fbfc9/image.png" alt=""></p>
<p>Stashes란에 이전에 생성했던 stash가 존재하고 있음을 볼 수 있다.</p>
<p><code>View</code>는 Stash가 저장한 변경 사항 보기, <code>Drop</code>은 Stash 삭제, <code>clear</code>은 Stash 목록 전부 초기화를 의미한다.
<code>Pop stash</code> 같은 경우 CLI Stash를 설명할 떄 조금 더 자세히 설명하겠다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/311281fb-0cf0-450d-9307-a39cba97eefd/image.png" alt=""></p>
<p>삭제되었던 <code>Stash가 제대로 될까?</code>문구가 다시 불러와졌음을 볼 수 있다.</p>
<hr>
<h1 id="span-stylecolor-lightgreencli를-통한-stash"><span style="color: lightgreen">CLI를 통한 Stash</h1>
<pre><code class="language-bash">git stash [Option]</code></pre>
<h2 id="span-stylecolor-lightblueindex"><span style="color: lightblue">Index</h2>
<p>Git Stash를 공부하기 앞서 Index에 대해 알고 갈 필요가 있다.
IntelliJ GUI에서 Stash 목록을 보면 앞에 <code>stash@{0}</code>이라는 이상한 문구가 있음을 알 수 있다.</p>
<p>여기에서 0에 해당하는 값({} 사이에 있는 수)이 바로 Index이다.
최근에 생성된 Stash일수록 Index가 작고 오래될수록 Index가 커진다.
(즉 가장 최근에 생성된 Stash Index는 0일 것이다)</p>
<p>추가로 저장한 Stash를 불러올 때 특정한 언급이 없다면 <code>stash@{0}</code>, 즉 가장 최근 Stash를 불러오게 된다.</p>
<h2 id="span-stylecolor-lightbluestash-저장--조회"><span style="color: lightblue">Stash 저장 &amp; 조회</h2>
<h4 id="span-stylecolor-orangegit-stash-git-stash-save-message"><span style="color: orange"><code>git stash</code>, <code>git stash save &lt;Message&gt;</code></h4>
<p><code>git stash</code>와 <code>git stash save</code> 모두 현재 변경된 내용들을 Stash를 활용하여 저장하는 명령어이다.</p>
<p>둘의 차이점은 &quot;Stash의 이름을 지정할 수 있는가&quot;여부이다.</p>
<p><code>git stash</code>를 사용할 경우 생성할 Stash의 이름을 지정할 수는 없다.
만약 이름을 지정하기 위해선 <code>git stash save &lt;Stash Message&gt;</code> 명령어를 활용하여 Stash 저장을 수행해야 한다.</p>
<p><code>git stash save</code>를 통해 Stash Message 지정 없이도 변경사항을 저장할 수는 있지만 이렇게 사용할 거면 <code>git stash</code>를 활용하는 것이 더 편할 것이다.</p>
<h4 id="span-stylecolor-orangegit-stash---keep-index"><span style="color: orange"><code>git stash --keep-index</code></h4>
<p>IntelliJ에서 stash 저장을 수행할 때 <code>Keep Index</code>라는 체크박스가 있었는데 이 체크박스가 <code>--keep-index</code> 옵션을 의미한다.</p>
<p>(위에서 봤듯) Stash를 저장한다면 변경사항들이 모두 삭제되고 마지막 Commit 상태로 원복 된다.
하지만 <code>--keep-index</code>를 사용하면 변경사항을 Stash에 저장하더라도 변경사항들이 모두 Working Directory에 남아 있게 된다.</p>
<h4 id="span-stylecolor-orangegit-stash-list"><span style="color: orange"><code>git stash list</code></h4>
<p>Stash 목록을 조회하는 명령이다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/3e81e0cf-c7b6-43fd-a1f8-5ca99805b426/image.png" alt=""></p>
<p>재미있는 것이 <code>git stash</code>와 <code>git stash save &lt;Message&gt;</code>를 통해 생성한 Stash가 목록에 조금 다르게 표시된다는 것이다.
(<code>On main :</code>, <code>WIP on main :</code>으로 표시됨)</p>
<h4 id="span-stylecolor-orangegit-stash-show-stashindex"><span style="color: orange"><code>git stash show [stash@{index}]</code></h4>
<p><code>stash@{index}</code>에 해당하는 Stash에 저장된 내용을 확인하는 명령어이다.</p>
<p>만약 <code>stash@{index}</code>가 없다면 가장 최근 Stash(<code>stash@{0}</code>)에 저장된 내용을 확인한다.</p>
<h4 id="span-stylecolor-orangegit-stash-rename-stashindex"><span style="color: orange"><code>git stash-rename [stash@{index}]</code></h4>
<p>지정한 Stash의 Message(Stash 이름)을 수정하는 명령어이다.</p>
<h2 id="span-stylecolor-lightbluestash-가져오기-1"><span style="color: lightblue">Stash 가져오기</h2>
<h4 id="span-stylecolor-orangegit-stash-apply-stashindex"><span style="color: orange"><code>git stash apply [stash@{index}]</code></h4>
<p><code>git stash apply</code>는 Stash List에서 Stash를 가져와 Working Directory에 반영하는 명령어이다.</p>
<p><code>git stash apply</code>로 Stash를 가져오면 Stash List에 해당 Stash는 삭제되지 않고 그대로 유지된다.</p>
<p>만약 Stash를 가져온 뒤 해당 Stash를 Stash List에서 삭제하고 싶다면 아래에서 배울 <code>git stash pop</code>으로 변경사항을 가져오거나 <code>git stash apply</code> 이후 <code>git stash drop</code>을 활용하여 Stash List에 Stash를 삭제하는 과정이 추가 수행되어야 한다.</p>
<h4 id="span-stylecolor-orangegit-stash-pop-stashindex"><span style="color: orange"><code>git stash pop [stash@{index}]</code></h4>
<p><code>git stash pop</code>은 가장 최근에 생성된 Stash를 가져오는데 이때 가져온 Stash를 Stash List에서 자동으로 삭제한다.</p>
<p><code>pop</code> 이후 <code>[stash@{index}]</code>를 사용한다면 지정한 Stash를 Stash List에서 가져와 Working Directory에 변경사항을 적용한 뒤 가져온 Stash를 리스트에서 삭제한다.</p>
<p>(개인적으론 <code>git stash apply</code>보다 <code>git stash pop</code>을 더 많이 활용하는 것 같다. Stash를 한번 가져왔다면 굳이 해당 Stash를 다시 사용할까라는 생각이 있기 때문이다)</p>
<h4 id="span-stylecolor-orangegit-stash-drop-stashindex"><span style="color: orange"><code>git stash drop [stash@{index}]</code></h4>
<p>지정한 Stash를 제거하는 명령어이다.
만약 <code>[stash@{index}]</code>가 없다면 최근 생성된 Index(<code>[stash@{index}]</code>)를 삭제한다.</p>
<h4 id="span-stylecolor-orangegit-stash-clear"><span style="color: orange"><code>git stash clear</code></h4>
<p>Stash List에 있는 모든 Stash들을 삭제한다.</p>
<h4 id="span-stylecolor-orangegit-stash-pop---index--git-stash-apply---index"><span style="color: orange"><code>git stash pop --index</code> | <code>git stash apply --index</code></h4>
<p>Stash를 가져올 때 <code>--index</code> 옵션을 사용할 수 있다.</p>
<p>Stash를 공부하며 아래와 같은 의문점이 생겼다면 Git 공부를 제대로 하고 있는 것이다.
&quot;Stash가 Commit 되지 않은 변경 사항을 임시 저장한다는 것은 알겠는데, 과연 Staging된 변경 사항은 어떻게 처리할까?&quot;</p>
<p>결론부터 말하자면 기본적으로 Stash는 Staging 관계없이(파일 상태 관계없이) Stash에 저장된 모든 변경사항들을 가져온다.</p>
<p>하지만 변경 사항을 가져올 때 Staging 되어 있는 상태까지 가져오고 싶을 수 있다.
이때 활용하는 것이 바로 <code>--index</code> 옵션이다.</p>
<p><code>--index</code> 옵션을 사용할 경우 Staging 되어 있던 변경사항들은 그대로 Staging 된 상태로 불러와진다.
단, 변경사항이 새로 추가된 파일이라면 해당 파일은 <code>--index</code> 옵션 없이도 바로 Staging된 상태로 불러오게 된다.</p>
<blockquote>
<p>(뇌피셜)
개인적인 생각으로는 새 파일은 Staging된 상태로 불러오는 것이 편의성 때문이 아닐까라고 생각한다.</p>
</blockquote>
<p>만약 새로운 파일이 Staging된 상태가 아니라면 Untracked 상태라는 것인데 Untracked 상태일 경우 GUI를 통해 Commit하거나 <code>git add</code>와 <code>commit</code>을 동시에 해주는 명령어를 활용할 때 추가된 파일이 누락될 위험성이 존재하기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Revert]]></title>
            <link>https://velog.io/@violet_evgadn/Revert</link>
            <guid>https://velog.io/@violet_evgadn/Revert</guid>
            <pubDate>Thu, 07 Sep 2023 02:23:04 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenrevert"><span style="color: lightgreen">Revert</h1>
<h3 id="span-stylecolor-lightbluerevert란"><span style="color: lightblue">Revert란?</h3>
<p>실수로 수행한 커밋이 아니라면 대부분의 커밋을 취소하는 데에는 이유가 있을 것이다.
예를 들어 A라는 기능을 개발한 후 커밋 했는데 보안이나 법적인 문제로 해당 기능을 삭제해야 한다면 해당 커밋을 삭제해야 할 것이다.</p>
<p>이러한 커밋을 취소하는 과정 또한 중요한 업무 과정 중 하나이다.
협업을 조금 더 원활히 하기 위해선 이런 커밋을 취소했다는 것도 기록에 남기면서 커밋을 삭제하고 싶을 것이다.</p>
<p>이를 위한 기능이 바로 &quot;리버트(Revert)&quot;이다.</p>
<p>리버트는 커밋을 삭제시키며 기록을 남기지 않는 &quot;Reset&quot;과는 달리 커밋을 삭제했다는 기능까지 남기는 &quot;되돌리기 기능(<code>Ctrl + Z</code>)&quot;이다.</p>
<p>실무를 수행할 땐 대부분 커밋을 수행하기 전 많은 고민을 할 것이고 커밋 삭제 시에는 외부적 요인이 있을 가능성이 크므로 Revert가 (Reset보다) 유용한 경우가 많을 것이다.</p>
<blockquote>
<p>정말로 강조하는 내용인데 협업을 하는 원격 저장소에서는 절대 Git Reset을 활용하지 말자.
Git Reset은 언제나 혼자만 사용하는 브랜치에서나 수행하는 동작이다. 왜냐하면 --hard 옵션을 사용할 경우 복구하기가 힘들기 때문에 만약 다른 사람과 같이 활용하는 브랜치에서는 커다란 문제를 가져올 수도 있다.</p>
</blockquote>
<hr>
<h1 id="span-stylecolor-lightgreenintellij에서의-revert"><span style="color: lightgreen">IntelliJ에서의 Revert</h1>
<h3 id="span-stylecolor-lightblue0-revert-시킬-커밋-생성"><span style="color: lightblue">0. Revert 시킬 커밋 생성</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/1f5a9814-87a0-4500-9639-87b5c919bb62/image.png" alt=""></p>
<p>필자는 &quot;실수로 수행해버린 커밋&quot;이라는 문구를 추가한 뒤 커밋을 생성했다.</p>
<h3 id="span-stylecolor-lightblue1-git-log--revert-하고-싶은-커밋-선택--마우스-오른쪽-클릭"><span style="color: lightblue">1. Git Log &gt; Revert 하고 싶은 커밋 선택 &gt; 마우스 오른쪽 클릭</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/c3212338-bf62-4eef-aa9a-878cabd3aef8/image.png" alt="">
여러 선택지 중 <code>Revert Commit</code> 버튼을 클릭하자.</p>
<h3 id="span-stylecolor-lightblue2-git-log--결과-확인"><span style="color: lightblue">2. Git Log &amp; 결과 확인</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/5f1dd4b9-2678-4467-babb-edfe599d04cc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/d0f2b99e-bb15-4ff9-a2cf-2e36127b1eae/image.png" alt=""></p>
<p><code>Revert &quot;Git Revert 테스트 커밋&quot;</code>이라는 Log가 추가되었으며 추가했던 문구가 삭제되었음을 확인할 수 있다.
즉, 0번 과정에서 생성한 커밋의 변경 사항이 취소됨과 동시에 Revert를 통해 커밋 삭제 과정이 Log 상에도 남았음을 알 수 있다.</p>
<hr>
<h1 id="span-stylecolor-lightgreencli를-통한-revert"><span style="color: lightgreen">CLI를 통한 Revert</h1>
<pre><code class="language-bash">git revert [Option] [커밋 ID]</code></pre>
<h3 id="span-stylecolor-lightblue명령어-설명"><span style="color: lightblue">명령어 설명</h3>
<p><code>git reset</code>과 마찬가지로 커밋 ID를 입력하면 커밋 ID에 해당하는 커밋을 Revert 시킬 것이다.
<code>git revert</code>에서 사용한 <code>HEAD^</code>나 <code>HEAD~&lt;숫자&gt;</code> 또한 커밋 ID 자리에 입력함으로써 사용할 수 있다.</p>
<p>하지만 이전에 말했듯 필자는 HEAD 사용을 그렇게 좋아하지 않으므로 앞으로는 커밋 ID만 명령어에서 활용하도록 하겠다.</p>
<h3 id="span-stylecolor-lightblueoption"><span style="color: lightblue">Option</h3>
<h4 id="span-stylecolor-orangegit-revert---no-commit-커밋-id"><span style="color: orange"><code>git revert --no-commit [커밋 ID]</code></h4>
<p>Revert 한 결과를 바로 Commit 시키고 싶지 않을 때 사용하는 명령어이다.</p>
<p>IntelliJ에서 Revert를 시키면 <code>Revert &quot;Git Revert 테스트 커밋&quot;</code>라는 커밋 메시지가 자동으로 생긴 뒤 바로 커밋 됨을 알 수 있다. </p>
<p>하지만 Revert 시 생기는 커밋의 메시지도 개발자가 직접 입력하고 싶을 수 있다. 
이때 <code>--no-commit</code> 옵션을 활용해 Revert 결과를 Staging만 시키고 커밋 하지 않을 수 있다.</p>
<p>(이후 <code>git commit -m &quot;커밋 메시지&quot;</code>를 통해 Revert 시 생성되는 커밋의 메시지를 입력할 수 있을 것이다)</p>
<h4 id="span-stylecolor-orangegit-revert-커밋id1커밋id2"><span style="color: orange"><code>git revert [커밋ID1]..[커밋ID2]</code></h4>
<p>여러 개의 커밋을 한 번에 Revert 시킬 수도 있다.</p>
<p><code>[커밋ID1]..[커밋ID2]</code>를 입력하면 커밋 ID1에 해당하는 커밋부터 커밋ID2에 해당하는 커밋까지 모두 Revert 된다.
이때 Revert는 &quot;커밋 ID2&quot;를 가진 커밋부터 취소시키기 때문에 이 점을 고려하여 커밋ID1과 커밋ID2를 지정하도록 하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Reset]]></title>
            <link>https://velog.io/@violet_evgadn/Reset</link>
            <guid>https://velog.io/@violet_evgadn/Reset</guid>
            <pubDate>Thu, 07 Sep 2023 02:22:40 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenreset"><span style="color: lightgreen">Reset</h1>
<h3 id="span-stylecolor-lightbluereset이란"><span style="color: lightblue">Reset이란?</h3>
<p>Git을 사용하다 보면 여러 개의 커밋을 생성한다.
이렇게 여러 개의 커밋을 생성하는 도중 특정 커밋 이전 상황으로 돌아가고 싶을 수도 있을 것이다.</p>
<p>예를 들어 A라는 기능을 만들었는데 법적 규제 때문에 A 기능을 사용할 수 없게 되었다. 이때 개발자는 A라는 기능을 개발하기 전 상황으로 돌아가야 할 것이다.</p>
<p>이때 활용하는 Git의 기능이 Reset이다.
(참고로 Git Reset 활용 시 Untracked 파일은 건드리지 않는다)</p>
<h3 id="span-stylecolor-lightbluegit-reset-모드"><span style="color: lightblue">Git Reset 모드</h3>
<h4 id="span-stylecolor-orangesoft-mixed"><span style="color: orange">Soft, Mixed</h4>
<p>Soft와 Mixed 모드는 지정한 커밋 상태로 커밋 이력을 되돌리지만 워킹 디렉터리에 작업했던 내용은 그대로 유지시킨다.</p>
<p>그렇다면 동일한 동작 과정인 것 같은데 왜 Soft와 Mixed로 나누어놨을까?</p>
<p>Soft와 Mixed의 차이는 아래와 같다.</p>
<ul>
<li>Soft : Reset 시킨 커밋과 비교했을 때 새로 생성된 파일을 Staging 상태로 둠</li>
<li>Mixed : Reset 시킨 커밋과 비교했을 때 새로 생성된 파일은 Unstaging 시킴</li>
</ul>
<h4 id="span-stylecolor-orangehard"><span style="color: orange">Hard</h4>
<p>Hard Reset은 특정 커밋과 현재 상황을 완전히 일치시킴으로써 깔끔하게 모든 중간 작업물들을 리셋 시키는 것을 의미한다.</p>
<p>다른 git reset 옵션은 명령어를 수행하더라도 워킹 디렉터리에는 작업했던 내용이 남아 있다.
하지만, 유일하게 Hard 옵션은 커밋과 더불어 작업했던 내용까지 워킹 디렉터리에서 초기화시킨다.</p>
<p>이러한 점에서 git reset의 <code>--hard</code> 옵션은 <code>reset</code> 명령을 위험하게 만드는 유일한 옵션이다.</p>
<h4 id="span-stylecolor-orange예시를-통해-본-hard-mixed-soft"><span style="color: orange">예시를 통해 본 Hard, Mixed, Soft</h4>
<p>만약 내가 A 파일을 커밋 했었는데 git reset을 통해 A 파일의 작업물을 커밋에서 제외하고 싶다 가정하자.</p>
<p>각각의 옵션으로 git reset을 시키면 아래와 같은 결과가 나온다.</p>
<ul>
<li><p><code>--mixed</code> : A 파일이 삭제되지는 않지만 Unstaging 상태로 변경됨</p>
<ul>
<li>만약 추후 A 파일을 다시 커밋 하고 싶다면 <code>git add</code>를 통해 Staging 할 필요가 있음</li>
<li><code>git reset</code>의 Default Option</li>
</ul>
</li>
<li><p><code>--soft</code> : A 파일이 삭제되지 않고 Staging된 상태로 변경됨</p>
<ul>
<li>단순히<code>git commit</code>만 수행하더라도 A 파일은 Staging된 상태이므로 커밋에 반영된다.</li>
<li>단, <code>git reset</code>을 수행했으므로 현재 HEAD가 가리키는 커밋에는 A 파일이 존재하지 않을 것이다.</li>
</ul>
</li>
<li><p><code>--hard</code> : A 파일이 현재 커밋에 존재하지 않고 워킹 디렉터리에서도 삭제되어 있음</p>
</li>
</ul>
<h4 id="span-stylecolor-orange표로-보는-hard-mixed-soft"><span style="color: orange">표로 보는 Hard, Mixed, Soft</h4>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="center">Soft</th>
<th align="center">Mixed(기본)</th>
<th align="center">Hard</th>
</tr>
</thead>
<tbody><tr>
<td align="center">HEAD</td>
<td align="center">초기화</td>
<td align="center">초기화</td>
<td align="center">초기화</td>
</tr>
<tr>
<td align="center">스테이지</td>
<td align="center">유지</td>
<td align="center">초기화</td>
<td align="center">초기화</td>
</tr>
<tr>
<td align="center">Working Tree 변경사항</td>
<td align="center">유지</td>
<td align="center">유지</td>
<td align="center">초기화</td>
</tr>
</tbody></table>
<hr>
<h1 id="span-stylecolor-lightgreenintellij에서-git-reset-수행"><span style="color: lightgreen">IntelliJ에서 git reset 수행</h1>
<h3 id="span-stylecolor-lightblue0-새로운-파일을-생성한-뒤-커밋"><span style="color: lightblue">0. 새로운 파일을 생성한 뒤 커밋</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/ab24f38b-bbab-45dd-a133-665b4e98169b/image.png" alt=""></p>
<h2 id="span-stylecolor-lightbluereset-수행"><span style="color: lightblue">Reset 수행</h2>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/bb78161e-34a0-470f-8759-72e509949575/image.png" alt=""></p>
<p>Git Log &gt; Reset 후 상태로 만들고 싶은 커밋 선택 &gt; 마우스 오른쪽 클릭 &gt; <code>Reset Current Branch to Here...</code>을 클릭하면 git reset을 수행할 수 있다.</p>
<p>그럼 아래와 같은 창이 나올 것이다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/26cc066d-f39a-4b18-bcf7-2ea5a82a5474/image.png" alt=""></p>
<p>이제 하나씩 클릭해서 어떻게 동작하는지 알아보자.</p>
<h3 id="span-stylecolor-orangesoft-선택--soft-옵션"><span style="color: orange">Soft 선택(<code>--soft</code> 옵션)</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/a88e7c74-703f-400a-a1ca-e7964c733649/image.png" alt=""></p>
<p>일단 현재 main 브랜치의 HEAD가 가리키는 커밋은 <code>Cherrypick으로 가져올 커밋</code>이라는 메시지를 가진 커밋으로 성공적으로 Reset 되었음을 확인할 수 있다.
(<code>Git Reset 테스트를 위한 파일 커밋</code> 메시지를 가진 커밋이 삭제됨)</p>
<p>이제 <code>reset_test_file.md</code> 파일을 보자.
이미지에서 볼 수 있듯 초록색 글씨로 되어 있는 것을 볼 수 있는데 이는 IntelliJ에서 &quot;Staging된 파일이다&quot;라는 것을 나타낸다.</p>
<p>그렇다면 바로 Commit 할 수 있을까?
한 번 commit 해보자.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/5b062871-8fe4-4165-82ce-4ec0c9608b16/image.png" alt=""></p>
<p>딱히 <code>git add</code>를 통해 Staging 하지도 않았는데 커밋이 가능함을 볼 수 있다.</p>
<p>커밋 시킨 뒤 Mixed reset을 수행해 보자.</p>
<h3 id="span-stylecolor-orangemixed-선택--mixed-옵션"><span style="color: orange">Mixed 선택(<code>--mixed</code> 옵션)</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/c2f22933-0c84-4a79-93b4-3e6497e28a5d/image.png" alt=""></p>
<p>마찬가지로 정상적으로 git reset 되었음을 확인할 수 있다.</p>
<p>하지만 큰 차이점이 있는데 바로 <code>reset_test_file.md</code> 파일명이 빨간색 글씨로 되어 있다는 것이다.</p>
<p>IntelliJ에서 빨간색 글씨는 해당 파일이 Staging 되지 않은 Untracked 파일임을 의미한다.
그렇다면 Commit 시 어떤 동작이 수행될까? 커밋 해보자.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/57f9a684-de39-4343-a1cf-9a44e13c6596/image.png" alt=""></p>
<p><code>--soft</code> 옵션과 다르게 <code>reset_test_file.md</code> 파일이 커밋 후보 파일에 없음을 알 수 있다.
즉, <code>--mixed</code> 옵션을 사용하면 새로 생성된 파일은 Unstaging 됨을 확인할 수 있다.</p>
<p>마지막으로 <code>--hard</code> 옵션을 테스트하기 위해 <code>git add</code>를 통해 Staging 시킨 뒤 커밋 시키고 다시 git reset을 수행하자.</p>
<h3 id="span-stylecolor-orangehard-옵션--hard-옵션"><span style="color: orange">Hard 옵션(<code>--hard</code> 옵션)</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/9bf1ae6b-7839-446a-9f07-3365b89dbb75/image.png" alt=""></p>
<p>git reset이 정상적으로 수행되었다.</p>
<p>하지만 큰 차이점이 있는데 분명 <code>README.md</code> 파일과 <code>settings.gradle</code> 파일 사이에 있던 <code>reset_test_file.md</code> 파일이 아예 워킹 디렉터리에서 삭제되었음을 볼 수 있다.</p>
<p>이런 상황이 된다면 (원격 저장소에 해당 파일을 Push 하지 않았다면) 삭제된 파일을 복구할 방법이 없다.
따라서 <code>--hard</code> 옵션을 사용할 경우 매우 큰 주의를 기울이며 사용하도록 하자.</p>
<hr>
<h1 id="span-stylecolor-lightgreencli를-통한-git-reset"><span style="color: lightgreen">CLI를 통한 git reset</h1>
<pre><code class="language-bash"># 방법 1 : 커밋 ID 활용
git reset [--hard | --mixed | --soft] &lt;커밋 ID&gt;

# 방법 2 : HEAD 예약어 활용
git reset [--hard | --mixed | --soft] HEAD~&lt;숫자&gt; # 방법 2-1
git reset [--hard | --mixed | --soft] HEAD^&lt;숫자&gt; # 방법 2-2</code></pre>
<h3 id="span-stylecolor-lightblue커밋-id를-통한-reset"><span style="color: lightblue">커밋 ID를 통한 reset</h3>
<p>단순히 내가 Git Reset을 통해 돌아가고 싶은 커밋 ID를 뒤에 입력해 주면 된다.</p>
<p>필자는 이 방법을 선호하는데 아래에서 설명할 HEAD 활용 방법 같은 경우 몇 번째 커밋인지 숫자를 세야 하는 것도 있고 직접 수행하기 전까지 어떤 결과가 나올지 모호한데 커밋 ID를 활용하면 확실하고 안전하게 reset 시킬 수 있기 때문이다.</p>
<h3 id="span-stylecolor-lightbluehead를-활용한-reset"><span style="color: lightblue">HEAD를 활용한 reset</h3>
<p>Git에서는 HEAD에 <code>^</code> 기호나 <code>~</code> 기호 뒤에 숫자를 붙임으로써 현재 HEAD가 가리키는 커밋을 기준으로 특정 커밋을 가리킬 수 있다.(상대 참조)</p>
<p><code>^</code>와 <code>~</code>의 의미는 아래와 같다.</p>
<ul>
<li><p><code>HEAD~&lt;숫자&gt;</code> : n 번째 부모 커밋</p>
</li>
<li><p><code>HEAD^</code> : 현재 커밋의 부모 브랜치</p>
</li>
</ul>
<blockquote>
<p>위 2가지 상황에서 부모 커밋은 모두 &quot;현재 브랜치&quot;를 기준으로 찾아야 한다.</p>
</blockquote>
<p>벌써부터 어렵다. 이미지를 통해 알아보자.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/de541dbe-64e5-4a8f-bf29-ab1f6b92d41f/image.png" alt=""></p>
<p>현재 7번 커밋이 HEAD라고 가정하자.
과연 <code>HEAD^</code>은 어떤 커밋을 가리킬까?</p>
<p>이를 파악하기 위해선 현재 브랜치가 어디인지를 알아야 한다.
만약 보라색 브랜치가 현재 브랜치라면 4번 커밋을, 노란색 브랜치가 현재 브랜치라면 6번 커밋을 나타낼 것이다.</p>
<p>만약 3번이나 5번 커밋과 같이 부모가 아닌 N번째 조상 커밋을 나타내고 싶다면 <code>~</code>를 사용하면 될 것이다.
<code>HEAD~2</code>를 활용하면 보라색 브랜치가 현재 브랜치일 경우 3번 커밋을, 노란색 브랜치가 현재 브랜치라면 5번 커밋을 나타낼 수 있다.</p>
<p>위 설명을 보면 알겠지만 HEAD를 활용해 특정 커밋을 나타내기엔 너무 어렵고 모호하며 현재 상황에 큰 의존성을 가진다.
그러니 특수한 상황이 아니라면 웬만하면 커밋 ID를 활용하는 것을 추천한다.</p>
<h3 id="span-stylecolor-lightblue번외"><span style="color: lightblue">번외</h3>
<p>위에서 <code>--hard</code> 옵션을 사용하면 파일이 삭제되고 복구할 수 없으니 위험하다는 말은 했지만, 사실 엄밀히 말하자면 복구 방법이 존재한다.</p>
<p><code>git reset --hard</code>를 통해 reset시키더라도 로컬 저장소에서 커밋은 삭제되는 것이 아닌 사라진 것처럼 안 보일 뿐이다.</p>
<p>이해하기 쉽게 말하자면(엄밀히 따지자면 다르지만) 컴퓨터에서 특정 파일을 삭제할 경우 영구 삭제되었다고 생각하겠지만 사실 휴지통에는 존재하는 상황이라고 생각하면 편하다.
이런 상황에서 만약 내가 복구하고 싶은 파일명을 알고 있다면 파일을 다시 복구할 수도 있을 것이다</p>
<p>이처럼 만약 내가 복구하고 싶은 파일이 존재하는 커밋 ID를 알고 있다면 해당 커밋 ID를 통해 삭제된 파일을 복구할 수도 있다.
하지만 대부분의 경우 커밋 ID를 외워놓고 있지 않을 것이므로 복구 방법이 존재하지 않는 것과 유사하다고 판단하여 이렇게 설명하는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cherrypick]]></title>
            <link>https://velog.io/@violet_evgadn/Cherrypick</link>
            <guid>https://velog.io/@violet_evgadn/Cherrypick</guid>
            <pubDate>Thu, 07 Sep 2023 02:22:13 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreencherrypick"><span style="color: lightgreen">Cherrypick</h1>
<h3 id="span-stylecolor-lightbluecherrypick이란"><span style="color: lightblue">Cherrypick이란?</h3>
<p>Cherrypick은 내가 Git을 제대로 공부해야겠다고 마음먹은 계기가 된 개념이다.
회사에서 Cherrypick에 대한 질문을 했는데 제대로 된 대답을 하지 못했었다.</p>
<p>체리픽(Cherry-pick)은 내가 원하는 다른 브랜치의 커밋을 선별하여 내 브랜치에 적용시키는 Git 기능을 의미한다.</p>
<p>체리픽에 대한 개념은 조금 어렵기 때문에 이미지를 통해 알아보자.
설명하기 앞서 beta 브랜치는 실제 서비스를 하기 전 베타 버전 코드를 올리는 브랜치이고 main 브랜치에는 실제 서비스로 제공하는 코드가 등록된다고 가정하자.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/f7aeaf5e-7ed8-4175-be3c-70a48dbc80bf/image.png" alt=""></p>
<p>현재 main 브랜치와 beta 브랜치의 커밋은 위 이미지와 같은 상황이다.
beta 버전의 3번째 커밋까지 실제 서비스에 적용되어 있으며 4, 5, 6번째 beta 커밋은 아직 main 브랜치에 등록되지 않았다.</p>
<p>그런데 이 상황에서 실제 서비스에 문제가 발생하였다. 그리고 그 문제를 해결할 수 있는 코드가 위 이미지 중 노란색 커밋(5번째 커밋)에 존재한다고 가정해 보자.
아직 4번째 커밋과 6번째 커밋은 실제 서비스에 적용해도 될지 안될지 검증이 완료되지 않았다.
이런 상황이라면 4번째 커밋과 6번째 커밋을 무시한 채 오직 5번째 커밋의 변경사항을 main 브랜치에 연결시키고 싶을 것이다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/e66af7f5-9bed-4d17-b1bb-25f057b2a5ec/image.png" alt=""></p>
<p>최종적으론 위 이미지와 같은 작업이 수행되어야 할 것이다.
이렇듯 이전 혹은 이후 커밋을 무시한 채 특정 커밋의 변경사항만을 &quot;체리픽(Cherrypick)&quot;을 통해 가져올 수 있는 것이다.</p>
<p>체리픽의 이름이 어디에서 나왔는지 안다면 조금 더 이해가 쉬울 것이다.
체리픽은 Cherry + pick의 합성어로 직역하자면 &quot;체리를 고른다&quot;라는 의미를 가진다.</p>
<p>이를 풀어 해석하면 체리를 수확할 때 내가 원하는 체리(상품성이 있는 체리나 먹을 수 있는 체리)만 선별하여 수확한다는 의미를 가지며 Git에서 또한 내가 따길 원하는 체리(커밋)를 선별한 후 가져온다는 의미에서 이런 이름을 지었다.</p>
<p>체리픽에서 주의할 점은 커밋 ID가 변경된다는 점이다.
체리픽은 특정 커밋을 원하는 브랜치의 가장 최신 커밋으로 가지고 오는데 이 때 커밋 ID를 새로 생성하게 된다.
즉, 체리픽을 할 커밋과 체리픽을 통해 브랜치의 가장 마지막에 붙은 커밋은 다른 커밋이라는 것을 알아두자.</p>
<h3 id="span-stylecolor-lightblue체리픽-왜-사용할까"><span style="color: lightblue">체리픽, 왜 사용할까?</h3>
<p>그렇다면 이런 모호한 개념인 체리픽은 왜 사용할까?</p>
<p>위 예시에서 눈치챘을 수도 있겠지만 체리픽은 코드나 서비스에 문제가 발생하였을 경우 이를 해결하기 위해 많이 활용된다.</p>
<p>실제로 검증까지 끝난 커밋이더라도 실제 서비스 과정에서 문제가 발생하는 경우는 생각보다 자주 일어난다.
(사람은 신이 아니기에...)</p>
<p>이런 상황에서 문제를 먼저 해결하고 푸시 하기엔 main 브랜치의 커밋과 현재 커밋 사이에 검증되지 않은 기능을 가진 커밋이 main 브랜치에 반영되어 실제 서비스에 추가될 가능성이 있다.</p>
<p>만약 체리픽을 활용한다면 발생한 문제를 해결할 수 있는 커밋을 생성한 뒤 해당 커밋만 main 브랜치에 반영시키면 될 것이다.
그렇다면 검증되지 않은 커밋이 실제 서비스에 반영될 위험성이 매우 적어지므로 안전한 서비스 관리가 가능해질 것이다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenintellij에서-체리픽-하기"><span style="color: lightgreen">IntelliJ에서 체리픽 하기</h1>
<h3 id="span-stylecolor-lightblue1-새로운-브랜치-생성"><span style="color: lightblue">1. 새로운 브랜치 생성</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/74fa2c54-23c5-4fee-b6d3-0ff1d3500c30/image.png" alt=""></p>
<p><code>cherrypick_branch</code> 브랜치를 생성한 후 해당 브랜치로 이동(checkout)하자.</p>
<h3 id="span-stylecolor-lightblue2-아래와-같은-방식으로-커밋-2개-생성"><span style="color: lightblue">2. 아래와 같은 방식으로 커밋 2개 생성</h3>
<h4 id="span-stylecolor-orange"><span style="color: orange"></h4>
<p>2-1. cherrypick.md 파일 생성 &amp; 파일 커밋
<img src="https://velog.velcdn.com/images/violet_evgadn/post/380f8307-9a9e-4131-ad19-77c63b989a16/image.png" alt="">
<code>cherrypick_branch</code> 마지막 커밋을 통해 <code>cherrypick.md</code> 파일이 추가되었음을 볼 수 있다.</p>
<h4 id="span-stylecolor-orange-1"><span style="color: orange"></h4>
<p>2-2. Readme.md 파일 수정 &amp; 커밋
<img src="https://velog.velcdn.com/images/violet_evgadn/post/986d0236-80a9-46c8-8330-69fc75e79910/image.png" alt=""></p>
<p>이제 우리는 Cherrypick을 통해 첫번째 커밋의 <code>cherrypick.md</code> 파일은 가져오지 않고 <code>README.md</code> 파일의 변경 사항만을 가져올 것이다.</p>
<h3 id="span-stylecolor-lightblue3-main-브랜치로-checkout"><span style="color: lightblue">3. main 브랜치로 checkout</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/ffce63b8-8320-4466-9f68-35524ed71c16/image.png" alt=""></p>
<p>현재 브랜치는 <code>main</code>이며 <code>cherrypick_branch</code>에서 생성한 2개 커밋이 <code>main</code> 브랜치에 반영되지 않았음을 볼 수 있다.</p>
<p>이제 <code>Cherrypick으로 가져올 커밋</code>이라는 메시지를 가진 커밋만 Cherrypick을 통해 main 브랜치에 가져와보자.</p>
<h3 id="span-stylecolor-lightblue4-git-log--cherrypick을-통해-가져올-커밋-마우스-오른쪽-클릭--cherrypick-선택"><span style="color: lightblue">4. Git Log &gt; Cherrypick을 통해 가져올 커밋 마우스 오른쪽 클릭 &gt; Cherrypick 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/ae322a37-f08b-4af1-b43e-40ecce9d1b16/image.png" alt=""></p>
<p>버튼을 클릭하면 main 브랜치에는 <code>cherrypick.md</code> 파일은 존재하지 않지만 &quot;군침 싹~도는 커밋&quot;이라는 README.md 파일에 추가한 문구가 반영되었음을 볼 수 있다.</p>
<p>즉, 성공적으로 cherrypick을 통해 원하는 커밋의 변경사항만을 가져왔음을 볼 수 있다.</p>
<p>cherrypick_branch에서 가져온 커밋과 main 브랜치에 추가된 커밋의 커밋 ID가 다른 것도 확인해보자.</p>
<blockquote>
<p>만약 동일한 파일에 대해 2개의 커밋을 생성한 뒤 체리픽을 한다면 충돌이 날 것이다.
만약 동일한 파일에 2가지 변경 사항이 있는데 마지막 변경 사항만 가져오려 한다면 마지막 변경 이전에 생성된 변경 사항은 Git에서 어떻게 처리해야 하는지 도대체 알 수 없을 것이다.</p>
</blockquote>
<p>예를 들어 첫 번째 커밋에 &quot;Hello&quot;를 생성했고 두번째 커밋에 &quot;World&quot;를 생성한 후 두번째 커밋을 가져온다면 &quot;World&quot;를 가져와야 할지 &quot;Hello&quot;와 &quot;World&quot; 2가지 모두를 가져와야 할지 모호해질 것이다.</p>
<hr>
<h1 id="span-stylecolor-lightgreencli를-통해-체리픽-하기"><span style="color: lightgreen">CLI를 통해 체리픽 하기</h1>
<pre><code class="language-bash">git cherry-pick [커밋 ID]</code></pre>
<p>위에서 실습하며 알았겠지만 Cherrypick을 하기 위해선 일단 &quot;Cherrypick을 통해 커밋을 가져올 브랜치&quot;에 체크아웃이 선행되어 있어야 한다.</p>
<p>이후 내가 Cherrypick을 통해 가져오고 싶은 커밋 ID(해시 체크섬) 값을 확인 후 복사해 둬야 한다.</p>
<p>마지막으로 이 커밋 ID를 위 명령어에 넣으면 (충돌이 발생하지 않는 한) 성공적으로 Cherrypick이 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Amend]]></title>
            <link>https://velog.io/@violet_evgadn/Amend</link>
            <guid>https://velog.io/@violet_evgadn/Amend</guid>
            <pubDate>Thu, 07 Sep 2023 02:21:14 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenamend"><span style="color: lightgreen">Amend</h1>
<h3 id="span-stylecolor-lightblueamend란"><span style="color: lightblue">Amend란?</h3>
<p>git에서 생각보다 유용하게 쓰이는 기능이 바로 이번에 설명할 기능, <code>amend</code>이다.</p>
<p>git에서 <code>amend</code>란 직전에 했던 커밋에 추가적인 변경사항을 덮어쓰는 기능을 의미한다.</p>
<p>방금 했던 커밋을 원하는 대로 수정할 수 있다는 의미인데, 원격 저장소에 Push를 했더라도 <code>amend</code>를 통해 수정사항을 반영할 수 있다.</p>
<p>예를 들어 파일 A, B를 커밋 했어야 했는데 실수로 파일 A만 커밋 했다고 가정하자.
만약 파일 B 커밋을 추가로 수행한다면 Git log가 더러워질 뿐만 아니라 다른 협업자들은 파일 A와 파일 B가 따로 커밋 된 데는 이유가 있지 않을까라는 오해를 할 수 있다.
따라서 이 경우 파일 A를 반영한 커밋에 &quot;파일 B를 추가하여&quot; 커밋을 수정함으로써 보강하는 저장 버튼 같은 역할이 있으면 좋을 것이고 이 버튼이 바로 <code>amend</code>인 것이다.</p>
<p><code>amend</code>를 쓰는 경우는 아래와 같다.</p>
<ul>
<li>커밋 메시지를 바꾸고 싶은 경우</li>
<li>이전 커밋 시 일부 파일을 반영하지 않은 경우</li>
<li>이전 커밋 시 반영한 파일에 수정할 부분이 있는데 새로운 커밋을 만들 정도의 작업은 아닌 경우<ul>
<li>ex) 변수 이름을 <code>FINANCIAL</code>이라고 했는데 회의 결과 <code>FI</code>로 바꾸기로 했다.</li>
</ul>
</li>
</ul>
<p>마지막으로 <code>amend</code>시 해시 체크섬 값이 변한다는 사실도 알고 가자.</p>
<p>amend를 &quot;덮어쓰기&quot;라고는 말했지만 동작 과정을 더 정확히 말하자면 &quot;새로운 커밋을 생성하고 그곳에 변경사항과 이전 커밋을 포함시킨 뒤 이전 커밋을 대체하는&quot; 과정을 거친다.
따라서 amend를 수행할 경우 커밋의 해시 체크섬 값도 바뀌게 된다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenintellij에서의-amend"><span style="color: lightgreen">IntelliJ에서의 Amend</h1>
<h3 id="span-stylecolor-lightblue1-커밋-1개-생성"><span style="color: lightblue">1. 커밋 1개 생성</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/223d07d5-c7e5-4a80-883e-7fe2e6edd92e/image.png" alt=""></p>
<p>필자는 <code>Amend를 하기 전 커밋</code>이라는 문구를 추가하여 커밋했다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/c8ddb3f6-c8cc-4016-b3a3-16962e56a1c5/image.png" alt=""></p>
<p>Git Log에 해당 커밋이 생성되었음을 볼 수 있다.</p>
<h3 id="span-stylecolor-lightblue2-amend-시킬-변경-사항-생성"><span style="color: lightblue">2. Amend 시킬 변경 사항 생성</h3>
<p>누락된 문구가 직전 커밋(Amend 이전 커밋)에 포함되어야 한다고 가정하자.</p>
<p>커밋할 파일 내용은 아래와 같다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/268dcf12-2beb-4718-ae82-e129f626d153/image.png" alt=""></p>
<h3 id="span-stylecolor-lightblue3-git--commit-버튼-클릭"><span style="color: lightblue">3. Git &gt; Commit 버튼 클릭</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/9ab469ca-2b95-4c5a-8cae-4f149f8a20bb/image.png" alt=""></p>
<h3 id="span-stylecolor-lightblue4-commit-message-생성--amend-commit-선택"><span style="color: lightblue">4. Commit Message 생성 &amp; Amend commit 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/b00275bf-8bee-4a07-97ad-c38daf82df2c/image.png" alt=""></p>
<p>위 사진에서 볼 수 있듯이 Message도 &quot;Amend 이후 커밋&quot;이라고 명시했다.
체크 표시하고 커밋 메시지까지 기록했다면 <code>Commit</code> 버튼을 클릭하자.</p>
<h3 id="span-stylecolor-lightblue5-git-log-확인"><span style="color: lightblue">5. Git Log 확인</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/86373916-1a11-42d2-a595-f44b0313c845/image.png" alt=""></p>
<p>위 사진에서 볼 수 있듯 <code>Amend 이전 커밋</code>이었던 커밋 메시지가 <code>Amend 이후 커밋</code>으로 변경되었음을 볼 수 있다.
(실제 커밋 내용도 변경되었음을 확인할 수 있다)</p>
<hr>
<h1 id="span-stylecolor-lightgreencli를-통한-amend"><span style="color: lightgreen">CLI를 통한 amend</h1>
<h3 id="span-stylecolor-lightbluelocal-저장소-커밋-amend"><span style="color: lightblue">Local 저장소 커밋 Amend</h3>
<pre><code class="language-bash"># 1. 변경 된 파일들 Staging
git add .   # &#39;.&#39; 대신 Staging할 파일들을 리스트업 해도 됨

# 2. Staging 된 파일들 Amend
git commit --amend</code></pre>
<p>정리하자면 수정한 내용을 Staging Area에 올린 뒤(Staging 한 뒤) Commit 한다는 전체적인 구조는 바뀌지 않으나 <code>--amend</code> 옵션을 활용해 Amend를 수행할 수 있는 것이다.</p>
<h3 id="span-stylecolor-lightblueamend한-커밋을-원격-저장소에-반영"><span style="color: lightblue">Amend한 커밋을 원격 저장소에 반영</h3>
<pre><code class="language-bash">git push -f # -f 대신 --force 옵션을 사용해도 됨</code></pre>
<p><code>amend</code>를 통해 커밋을 수정한 후 <code>git push</code>를 수행하면 바로 변경된 커밋이 원격 저장소에 반영된다.....라는 것은 정말 말도 안 되는 틀린 말이다.</p>
<p><code>--amend</code>를 사용한다면 위에서 말했듯 커밋 아이디(해시 체크섬)도 바뀐다.</p>
<p>즉, Git 입장에선 원래 존재하던 커밋이 없어지고 갑자기 그 자리에 이상한 커밋이 새로 생성된 것이다.
이를 Git에서는 &quot;현재 Push할 커밋과 원격 저장소의 HEAD 커밋이 연결되어 있지 않다&quot;라고 보고 에러를 발생시킨다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/3d1c9927-e5f1-4eea-9f63-e908dd756190/image.png" alt=""></p>
<p>따라서 Amend 커밋을 반영하기 위해선 <code>-f</code>나 <code>--force</code> 옵션을 활용해 강제로 push 시켜주어야 한다.
(추가로 앞으로 원격 저장소 Git Log가 변경되는 모든 작업에 대해선 무조건 <code>-f</code>나 <code>--force</code> 옵션이 필요하다는 것을 알아두면 좋다)</p>
<blockquote>
<p>Amend부터는 사실 IntelliJ 같은 개발 툴에서 GUI를 통해 작업하기엔 조금 까다롭다.
실제로 IntelliJ에서 Amend 한 커밋을 Push 할 경우 Git Log를 깔끔히 만들기 상당히 까다롭다는 것을 알 수 있다.
여기부터 공부하며 왜 필자가 GUI를 애용하다 Git 명령어를 하나씩 배우고 CLI로 넘어가고 있는지 조금이라도 알았으면 좋겠다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rebase]]></title>
            <link>https://velog.io/@violet_evgadn/Rebase</link>
            <guid>https://velog.io/@violet_evgadn/Rebase</guid>
            <pubDate>Thu, 07 Sep 2023 02:20:08 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenrebase"><span style="color: lightgreen">Rebase</h1>
<h3 id="span-stylecolor-lightbluerebase란"><span style="color: lightblue">Rebase란?</h3>
<p>Git에서 브랜치를 다른 브랜치에 병합하는 방법은 &quot;Merge&quot;이다.
Git에서는 다른 방법으로 브랜치를 병합하는 방법을 제공하는데, 이것이 바로 &quot;Rebase&quot;이다.</p>
<p>Rebase는 커밋의 베이스를 띄어 다른 커밋(브랜치) 뒤로 붙이는 것을 의미한다.</p>
<p>이 Rebase 작업은 원래 병합 커밋(Merge Commit)으로 Merge 해야 하는 브랜치를 빨리 감기 병합(Fast-forward Commit) 방식으로 병합시켜 커밋의 이력을 조작함으로써 조금 더 깔끔한 Git Log를 남길 수 있다.</p>
<p>조금 어려운데 그림으로 알아보자.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/a8340f38-cbbd-475b-84b6-a962e27bc886/image.png" alt="">
커밋들이 위와 같이 병합된다고 가정하자.
이런 방식으로 병합할 경우 &quot;6번 커밋&quot;이라는, 어떻게 보면 큰 의미 없이 오직 &quot;<em><strong>Merge를 위한 커밋</strong></em>&quot;이 새로 생성된다.</p>
<p>이러한 Merge를 위한 커밋을 Git Log에 남기고 싶지 않아 아래와 같은 방식으로 병합을 실시할 수 있다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/b1dd73a1-db68-4d7c-bf86-1fcabbbd1393/image.png" alt=""></p>
<p>커밋3과 커밋4를 가지고 있는 브랜치를 뚝 띄어 커밋5 뒤에 붙임으로써 마치 커밋5가 존재하는 브랜치에서 작업한 것처럼 이력을 조작하는 것이다.
이러한 방식을 바로 &quot;Rebase&quot;라고 한다.</p>
<p>Rebase는 병합 커밋(Merge Commit)과 달리 Merge를 위한 커밋을 생성하지 않고 존재하는 커밋에 다른 브랜치들의 커밋을 덮어쓰는 형식으로 Git Log가 깔끔하게 남는다는 장점이 있다.</p>
<h3 id="span-stylecolor-lightbluerebase에-대한-개인적인-고찰"><span style="color: lightblue">Rebase에 대한 개인적인 고찰</h3>
<p>과연 &quot;Git Log를 깔끔하게 남긴다&quot;라는 것이 장점일까?</p>
<p>개인적으로는 &quot;A와 B의 작업물을 병합(Merge) 했다&quot;라는 것도 훌륭한 기록이라고 생각한다.
이 병합이라는 기록은 대충 생각해도 아래와 같은 의미를 가질 수 있을 것 같다.</p>
<ul>
<li>병합 커밋이 생성되었을 때 작업이 완료되어 실제 사용할 브랜치에 작업물이 병합되었다.</li>
<li>만약 병합한 작업물에 문제가 있을 경우 누구의 작업물에서 발생한 문제인지 파악할 기준이 될 수 있다.</li>
<li>A의 작업물(혹은 B의 작업물) 만 가지고 오고 싶을 때 어떤 커밋을 가져와야 할지 명확하다.</li>
</ul>
<p>Git 명령어를 배우다 보면 알겠지만 Git Log를 깔끔하게 변경하는 명령어에는 무조건 <code>-f</code>, 혹은 <code>--force</code> 옵션이 들어간다.
즉, Git은 Git Log를 변경할 때 명령어를 통해 &quot;강제로&quot; 명령을 수행시켜야 한다는 것이다.
그리고 필자는 &quot;시스템 상에서 막아둔 것을 강제로 수행시킨다&quot;라는 것이 사용을 권장하는 것은 아니라고 생각한다.</p>
<blockquote>
<p> <a href="https://medium.com/@fredrikmorken/why-you-should-stop-using-git-rebase-5552bee4fed1">https://medium.com/@fredrikmorken/why-you-should-stop-using-git-rebase-5552bee4fed1</a></p>
</blockquote>
<p>위 사이트에선 Git Rebase 사용을 멈춰야 하는 이유를 설명한다.
물론 나의 생각이 무조건 옳다는 것도 아니고 위 글을 쓴 사람의 의견이 100% 옳다는 것도 아니다.
하지만 읽다 보면 꽤나 합리적인 의견이기도 하고, <code>git rebase</code>의 위험성에 비해 장점이 크지 않다고 생각해 아마 필자는 사용하지 않을 것 같다.</p>
<p><del>그러한 의미로 CLI 명령어도 정리하지 않을 것이다. 절대 귀찮아서 정리하지 않은 것이 아니다!</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Fork]]></title>
            <link>https://velog.io/@violet_evgadn/Fork</link>
            <guid>https://velog.io/@violet_evgadn/Fork</guid>
            <pubDate>Thu, 07 Sep 2023 02:14:18 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenfork"><span style="color: lightgreen">Fork</h1>
<h3 id="span-stylecolor-lightbluefork란"><span style="color: lightblue">Fork란?</h3>
<p>Git Fork란 원격 저장소를 복사하여 새로운 원격 저장소를 생성하는 작업을 말한다.
그렇다면 왜 Fork가 필요할까?</p>
<p>Git의 등장으로 시/공간에 관계없는 협업이 강화되었고 덕분에 &quot;오픈 소스 프로젝트&quot;가 매우 발전했다.</p>
<p>그런데 이 오픈 소스 프로젝트의 원본 저장소(Github) 소유자 입장에선 협력자가 많아질수록 저장소 관리가 어려워진다는 단점이 존재했다.
오픈 소스 프로젝트를 공부하거나 Contributor로써 기여하고 싶을 때 오픈 소스 프로젝트에 직접 Branch를 생성하고 작업물을 push 하기엔 위험성이 존재하기 때문이다.</p>
<p>만약 오픈 소스 프로젝트에 대한 작업을 수행하는 모든 개발자가 각자의 브랜치를 생성하고 작업해버린다면 관리해야 할 브랜치가 너무 많아지며 심지어 관리자가 모르는 Pull Request가 발생하여 관리자가 추적하지 못한 기능들이 추가, 변경 혹은 삭제될 위험성도 존재한다.</p>
<p>이런 위험성을 줄이기 위해 활용하는 것이 <code>git fork</code>이다.</p>
<p>fork를 활용하면 다른 계정의 원격 저장소를 나의 Github 계정 원격 저장소로 복사해 가지고 올 수 있다.
이후 나의 원격 저장소에서 작업을 수행한다면 실수로 기존 오픈 소스 코드를 날리거나 훼손시키더라도 다시 복구할 수 있고 복구가 안될 것 같으면 다시 오픈 소스 프로젝트를 Fork 하면 된다.</p>
<p>또한 원격 저장소에서의 작업이 완료되었다면 Pull Request 요청을 다른 계정의 원격 저장소(오픈 소스 프로젝트 원격 저장소)에 날림으로써 프로젝트 관리자가 프로젝트를 관리하기가 더욱 수월해진다.</p>
<h3 id="span-stylecolor-lightblue브랜치-vs-포크"><span style="color: lightblue">브랜치 VS 포크</h3>
<table>
<thead>
<tr>
<th align="center">명령</th>
<th align="center">의의</th>
<th align="center">장점</th>
<th align="center">단점</th>
</tr>
</thead>
<tbody><tr>
<td align="center">브랜치</td>
<td align="center">하나의 원격 저장소에 여러 개의 분기를 나눔</td>
<td align="center">하나의 원본 저장소에서 커밋 이력 파악이 쉽게 가능</td>
<td align="center">다수의 사용자가 협업할 시 위험성 증가</td>
</tr>
<tr>
<td align="center">포크</td>
<td align="center">원격 저장소 한 개를 통째로 다른 원격 저장소에 복사</td>
<td align="center">원본 저장소에 영향을 미치지 않으므로 안전한 협업 가능</td>
<td align="center">원본 저장소의 이력을 보려면 따로 주소를 추가해야 함</td>
</tr>
</tbody></table>
<h3 id="span-stylecolor-lightblue-포크와-클론clone"><span style="color: lightblue"> 포크와 클론(Clone)</h3>
<p>이전 Section 중 &quot;원격 저장소에서 내려받기&quot;에서 Clone에 대해 배운 적이 있다.</p>
<blockquote>
<p><a href="https://velog.io/@violet_evgadn/%EC%9B%90%EA%B2%A9-%EC%A0%80%EC%9E%A5%EC%86%8C%EC%97%90%EC%84%9C-%EB%82%B4%EB%A0%A4%EB%B0%9B%EA%B8%B0">https://velog.io/@violet_evgadn/%EC%9B%90%EA%B2%A9-%EC%A0%80%EC%9E%A5%EC%86%8C%EC%97%90%EC%84%9C-%EB%82%B4%EB%A0%A4%EB%B0%9B%EA%B8%B0</a></p>
</blockquote>
<p>Clone과 Fork는 비교할 수도 없을 만큼 다른 작업이다.
Fork는 <code>다른 원격 저장소 -&gt; 나의 원격 저장소</code>로 코드를 가져오는 작업이며 Clone은 <code>원격 저장소 -&gt; 나의 컴퓨터</code>로 코드를 가져온 뒤 해당 파일을 로컬 저장소로 만드는 작업이기 때문이다.</p>
<p>단지 <code>clone</code>과 <code>fork</code>를 동시에 묶은 것은 이 둘이 합쳐져 하나의 흐름을 만들기 때문이다.</p>
<p>내가 오픈 소스 프로젝트에 대한 작업을 수행하고 싶을 경우 일단 <code>fork</code>를 통해 나의 Github 원격 저장소로 프로젝트를 가지고 올 것이다.
이후 <code>clone</code>을 통해 나의 원격 저장소에 저장되어 있는 오픈 소스 프로젝트를 Local Machine(나의 컴퓨터)에 다운로드한 뒤 해당 파일을 로컬 저장소로 만듦으로써 오픈 소스 프로젝트에 대한 작업을 할 준비가 완료될 것이다.</p>
<p>Fork와 Clone을 &quot;다른 공간으로 소스 코드를 복제한다&quot;라는 점에 집중하여 비교하려 하지 말고 작업의 흐름으로 이해하는 것을 추천한다.</p>
<hr>
<h1 id="span-stylecolor-lightgreengithub-fork-실습"><span style="color: lightgreen">Github Fork 실습</h1>
<h3 id="span-stylecolor-lightblue0-fork-받을-github-계정-생성"><span style="color: lightblue">0. Fork 받을 Github 계정 생성</h3>
<p>새로운 메일 계정으로 회원가입할 수도 있을 것이다.
(그리고 이렇게 테스트하는 것이 조금 더 구별이 쉽다)</p>
<p>하지만 만약 여러 계정을 사용하기 싫다면 Gmail의 <code>+</code> 기능을 사용한다면 하나의 계정으로도 여러 Github 계정을 생성할 수 있다.</p>
<p>만약 <code>test@gmail.com</code> 주소를 가지고 있다면 <code>test+1@gmail.com</code>, <code>test+main@gmail.com</code> 같은 형식으로 <code>+</code> 뒤에 아무 글자나 붙여 가입한다면 모든 메일이 <code>test@gmail.com</code>으로 오도록 여러 계정을 생성할 수 있다.</p>
<p>어떤 방식으로 만들지는 선택이다.
(필자는 그냥 다른 Github 계정을 만들었다)</p>
<h3 id="span-stylecolor-lightblue1-새로-생성한-github-계정으로-로그인"><span style="color: lightblue">1. 새로 생성한 Github 계정으로 로그인</h3>
<p>이 작업을 수행하기 전 Fork 할 Github 원격 저장소의 URL을 복사해두자.</p>
<p>URL을 복사해두었다면 이후 Github 계정으로 로그인하자.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/25084fb3-c702-4f6c-8684-59d5d2a5b9b6/image.png" alt=""></p>
<blockquote>
<p>새로운 Github 계정 프로필 사진</p>
</blockquote>
<h3 id="span-stylecolor-lightblue2-복사한-github-원격-저장소-url로-이동--fork-버튼-클릭"><span style="color: lightblue">2. 복사한 Github 원격 저장소 URL로 이동 &amp; Fork 버튼 클릭</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/fd7f6213-5874-445d-9867-ed053484a619/image.png" alt=""></p>
<h3 id="span-stylecolor-lightblue3-copy-the-main-branch-only-체크-해제--create-fork-버튼-클릭"><span style="color: lightblue">3. Copy the main branch only 체크 해제 &amp; Create Fork 버튼 클릭</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/42a2e447-de7b-4a4f-aa8a-e67a0e136360/image.png" alt=""></p>
<p>Main 브랜치만 받고 싶다면 체크 해제를 하지 않아도 되지만 이왕이면 완벽히 동일하게 원격 저장소를 가져오고 싶을 것이므로 <code>Copy the main branch only</code> 버튼 체크를 해제해 주자.</p>
<p>이후 <code>Create Fork</code> 버튼을 클릭해 주면 Fork가 완료된다.</p>
<h3 id="span-stylecolor-lightblue4-fork를-통해-복사한-새로운-계정-원격-저장소-프로젝트를-수정"><span style="color: lightblue">4. Fork를 통해 복사한 (새로운 계정) 원격 저장소 프로젝트를 수정</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/8f7b87e7-686d-4102-a686-3949112ddd02/image.png" alt=""></p>
<p>아래 내용을 깔끔히 지우고 <code>Fork를 통한 기여</code> 문구를 추가했다.</p>
<h3 id="span-stylecolor-lightblue5-contribute--open-pull-request-선택"><span style="color: lightblue">5. Contribute &gt; Open Pull request 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/d41cbafb-6603-4df5-97d0-c5ac8c0c3596/image.png" alt=""></p>
<p>이후 Pull request를 생성하듯 <code>Create pull request</code> 버튼을 클릭하면 된다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/c0d47ec5-e3f5-47ed-9ebf-8174c9c3e5ca/image.png" alt=""></p>
<h3 id="span-stylecolor-lightblue6-기존-원격-저장소-계정으로-로그인-후-프로젝트-접속"><span style="color: lightblue">6. 기존 원격 저장소 계정으로 로그인 후 프로젝트 접속</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/b0fb1b4d-457a-4db8-a7ac-6e9f70136d04/image.png" alt=""></p>
<p>새로 생성한 계정에서 만들었던 <code>Fork를 통한 기여</code> Pull Request가 생성되었음을 볼 수 있다.</p>
<p>추가로 만약 <code>Pull request</code>에 대한 피드백을 기존 원격 저장소에서 했더라도 Fork를 통해 복사한 원격 저장소에선 이를 확인할 수 없으므로 피드백 자체는 기존 원격 저장소에서 확인해야 한다.</p>
<p>기존 원격 저장소 계정 주인이 <code>Pull request</code>를 승인한다면 <code>Insights &gt; Contributors</code>에 새로운 Github 계정이 추가되는 것을 볼 수 있다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/f07181f6-012c-4361-a3be-22e9a71a8a19/image.png" alt=""></p>
<hr>
<h1 id="span-stylecolor-lightgreen부록--push-권한-부여"><span style="color: lightgreen">부록 : Push 권한 부여</h1>
<p>기본적으로 원격 저장소에 커밋을 직접 푸시 할 수 있는 사람은 원격 저장소를 만든 본인뿐이다.</p>
<p>하지만 협업을 위해선 다른 사람들도 원격 저장소에 Push를 수행할 수 있어야 하며 이를 위해 다른 계정을 협력자로 등록해야 한다.</p>
<p>방법은 <code>Settings -&gt; Collaborators</code> 페이지에 들어가 <code>Add people</code> 버튼을 클릭한 뒤 Github 계정의 user name, full name, 혹은 email을 입력해 주면 된다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/9c56a8ca-531c-408b-991b-8b300fb37cb3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/6c932559-5ea1-4a9a-8ad3-77f502b840fa/image.png" alt=""></p>
<blockquote>
<p>이름을 입력하면 후보가 될 수 있는 계정들을 Github 자체적으로 찾아 보여준다.</p>
</blockquote>
<p>추가할 계정을 선택한 뒤 <code>Select a collaborator above</code>를 클릭하면 해당 계정의 Email로 초대 문자가 오며 <code>View invitation</code>을 클릭한 뒤 Github에서 <code>Accept invitation</code>을 클릭하면 협업자로 등록할 수 있으며 기존 원격 저장소에 대한 Push 및 수정이 가능해진다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/c8bbff90-6638-4a56-b714-1a6966c23c80/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/343c4b4d-d95c-42b7-8699-d909866ce6af/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Tag(태그)]]></title>
            <link>https://velog.io/@violet_evgadn/Git-Tag</link>
            <guid>https://velog.io/@violet_evgadn/Git-Tag</guid>
            <pubDate>Thu, 07 Sep 2023 02:02:01 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreentag"><span style="color: lightgreen">Tag</h1>
<h3 id="span-stylecolor-lightblue버전"><span style="color: lightblue">버전</h3>
<p>프로그램을 출시하거나 업그레이드하면 이에 해당하는 &quot;버전&quot;을 같이 명시한다.
Git에서도 코드 수정 과정 중 의미 있는 특정 시점에 숫자를 활용하여 버전을 명시할 수 있다.</p>
<p>그리고 Git에서는 주로 &quot;<strong>태그</strong>&quot;라는 기능을 활용하여 버전을 명시한다.</p>
<p>태그를 알기 전 태그의 일반적인 Naming Rule부터 알아보자.
(모든 Naming Rule이 그렇듯 필수사항은 아니고 대부분 이런 방식으로 이름 짓는다 정도의 선택 사항이라는 것을 알아두자)</p>
<blockquote>
<p>[메이저 버전].[마이너 버전].[메인터넌스 버전]</p>
</blockquote>
<ul>
<li>메이저 : 사용자가 크게 느낄 변화를 변경</li>
<li>마이너 : 작은 기능적 변화가 있을 때 변경</li>
<li>메인터넌스 : 버그나 유지 보수를 수행한 후 변경</li>
</ul>
<h3 id="span-stylecolor-lightbluetag란"><span style="color: lightblue">Tag란?</h3>
<p>Tag의 사전적 의미는 &quot;어떠한 항목을 보충 설명하는 낱말 혹은 키워드&quot;이다.
이런 의미를 보았을 때 Git Tag는 &quot;커밋에 대한 보충 설명을 해주는 낱말 혹은 키워드&quot;라고 할 수 있다.</p>
<p>조금 쉽게 비유해 보자면 Git Tag는 특정 커밋에 포스트잇을 붙이는 느낌이다.</p>
<p>Commit 시 태그에 버전을 달아주거나 주요 커밋에 대해서 태그를 달아준다면 다른 협업자들은 태그를 통해 중요 커밋을 확인하거나 버전을 통해 소스 코드 검색을 조금 더 쉽게 할 수 있을 것이다.</p>
<p>하지만 개인적으로는 Git Tag를 사용해 본 경험이 많이 없어서 실제로 유용하게 활용되는 개념인지 잘 모르겠다.
그냥 이런 것이 있다 정도로만 알고 넘어가자.</p>
<h3 id="span-stylecolor-lightbluetag의-종류"><span style="color: lightblue">Tag의 종류</h3>
<p>Git의 태그에는 &quot;Lightweight 태그&quot;와 &quot;Annotated 태그&quot;로 나뉜다.</p>
<p>Lightweight 태그는 특정 커밋에 대한 포인터의 역할로 단순히 태그에 이름만 달 수 있다.</p>
<p>Annotated 태그는 태그 이름뿐만 아니라 태그 생성자 정보, 태그 생성 날짜 및 주석까지 추가할 수 있다.</p>
<p>대부분의 경우 Annotated 태그로 만들어 해당 커밋의 자세한 정보를 알려주는 것이 좋지만 단순히 Tag로 커밋의 버전만 입력할 것이라면 Ligthweight 태그를 추천한다.</p>
<hr>
<h1 id="span-stylecolor-lightgreencli를-통한-태그"><span style="color: lightgreen">CLI를 통한 태그</h1>
<blockquote>
<p>IntelliJ에서도 git tag를 활용할 수 있지만 그렇게까지 많이 활용하는 기능은 아니므로 CLI를 통한 태그 활용법만 기록하겠다.</p>
</blockquote>
<h2 id="span-stylecolor-lightbluegit-tag"><span style="color: lightblue">Git Tag</h2>
<pre><code class="language-bash">git tag [Option] &lt;Tag Name&gt; [branch or Checksum]</code></pre>
<p>브랜치 혹은 Checksum 입력을 생략할 경우 현재 HEAD가 가리키고 있는 커밋에 태그가 추가된다.</p>
<h3 id="span-stylecolor-lightblueoption--사용법"><span style="color: lightblue">Option &amp; 사용법</h3>
<ul>
<li><p><code>git tag</code> : 현재 커밋에 달린 Git Tag를 알려줌</p>
</li>
<li><p><code>git tag &lt;Tag Name&gt;</code> : Lightweight 태그 생성</p>
</li>
<li><p><code>git tag -a &lt;Tag Name&gt; -m &lt;Tag Message&gt;</code> : Annotated Tag 생성</p>
<ul>
<li>Tag Name : 태그 제목, Tag Message : 태그에 대한 주석(설명)</li>
</ul>
</li>
<li><p><code>git tag &lt;Tag Name&gt; [Branch명]</code> : 지정한 Branch의 최신 커밋에 태그 추가</p>
</li>
<li><p><code>git tag &lt;Tag name&gt; [Checksum]</code> : 지정한 체크섬을 가진 커밋에 태그 추가</p>
<ul>
<li>Branch명에 태그를 달기보다는 Checksum을 활용해 태그를 다는 경우가 더 많다.</li>
</ul>
</li>
</ul>
<h3 id="span-stylecolor-lightbluetag-원격-저장소에-업로드"><span style="color: lightblue">Tag 원격 저장소에 업로드</h3>
<pre><code class="language-bash">git push &lt;원격 저장소 이름&gt; --tags</code></pre>
<p><code>--tags</code> 옵션을 활용하면 로컬 저장소에 등록된 모든 태그가 원격 저장소에 업로드된다.</p>
<p><code>git push &lt;원격 저장소 이름&gt; &lt;태그 이름&gt;</code>을 통해 태그를 1개씩 원격 저장소에 업로드할 수도 있긴 하지만 이 경우 업로드할 태그 이름을 외워놔야 하기 때문에 웬만하면 <code>--tags</code> 옵션 사용을 추천한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Github Pull Request 창]]></title>
            <link>https://velog.io/@violet_evgadn/Github-Pull-Request-%EC%B0%BD</link>
            <guid>https://velog.io/@violet_evgadn/Github-Pull-Request-%EC%B0%BD</guid>
            <pubDate>Thu, 07 Sep 2023 01:43:52 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenpull-request-생성-창1"><span style="color: lightgreen">Pull Request 생성 창(1)</h1>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/ec68e5b3-5d05-4f25-b1bc-78397fd84432/image.png" alt=""></p>
<h3 id="span-stylecolor-lightbluemain---pull_request_window노란색-네모"><span style="color: lightblue"><code>main &lt;- pull_request_window</code>(노란색 네모)</h3>
<h4 id="span-stylecolor-orangebase--main"><span style="color: orange"><code>base : main</code></h4>
<p>어느 브랜치를 Base로 하여 Pull Request를 진행할지 결정하는 창으로 원하는 브랜치를 선택할 수 있다.</p>
<p>베이스란 말이 어려울 수 있는데 &quot;어떤 브랜치에 내가 작업할 내용을 추가할 것인가&quot;에 대한 질문에서 &quot;어떤 브랜치&quot;에 해당하는 브랜치를 지정하면 된다.</p>
<h4 id="span-stylecolor-orangecompare--pull_request_window"><span style="color: orange"><code>compare : pull_request_window</code></h4>
<p>내가 작업한 작업물이 존재하는 브랜치, 혹은 Base 브랜치에 병합시킬 작업물을 가진 브랜치를 의미한다.</p>
<p><code>base</code>와 <code>compare</code>를 동시에 생각해 본다면 <code>compare</code>에 지정된 브랜치의 작업물을 <code>main</code> 브랜치에 Push 하는 작업이 수행되는 것이다.</p>
<h4 id="span-stylecolor-orangeable-to-merge"><span style="color: orange">Able to merge.</h4>
<p>충돌(Conflict) 없이 병합(Merge)이 가능하다는 의미를 가진다.</p>
<p>만약 병합 시 Conflict가 예측된다면 아래와 같은 창이 발생한다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/503ffae9-8912-4c15-8be0-3e2fb9235c04/image.png" alt=""></p>
<p>이러한 충돌은 Github에서 Pull Request를 생성한 후에도 해결할 수 있지만 필자는 로컬 저장소에서 미리 이러한 충돌을 해결한 뒤 Pull Request를 생성하는 것을 추천한다.
(충돌이 예상되더라도 Github에서는 <code>Create pull request</code> 버튼이 활성화된다)</p>
<h3 id="span-stylecolor-lightbluecommits-on-sep-25-2023주황-네모"><span style="color: lightblue">Commits on Sep 25, 2023(주황 네모)</h3>
<p>PR 결과를 통해 원격 저장소 main 브랜치(base 브랜치)의 HEAD에 어떠한 커밋들이 추가되는지를 알려주는 공간이다.</p>
<p>위 사진에선 Pull Request를 수행할 경우 원격 저장소의 <code>main</code> 브랜치에 <code>Pull Request 창 확인을 위한 커밋</code>이라는 메시지를 가진 커밋이 추가됨을 알 수 있다.</p>
<p>그 아래 창에서는 Pull Request가 진행될 경우 어떤 부분이 달라지는지를 볼 수 있는데 이는 많이 활용되지 않으므로 넘어가겠다.</p>
<h3 id="span-stylecolor-lightbluecreate-pull-request"><span style="color: lightblue"><code>Create pull request</code></h3>
<p>Pull Request를 생성하는 창이다.
Conflict 발생 유무에 상관없이 활성화되며 누를 경우 Pull Request가 생성된다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenpull-request-생성-창2"><span style="color: lightgreen">Pull Request 생성 창(2)</h1>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/81821131-6253-4775-9279-fb453cf80691/image.png" alt=""></p>
<p>위 단계(1번 창)에서 <code>Create pull request</code>창을 선택했다면 2번 창이 나올 것이다.</p>
<p>이 창에선 Pull Request에 대한 Comment와 제목을 생성할 수 있다.</p>
<p>PR의 제목으론 해당 PR이 어떤 이유로 생성되었는지(ex. A 기능 개발, 버그 핫픽스 등) 입력하는 곳이 좋으며 Comment로는 그를 위해 어떤 작업을 수행했는지(ex. NPE가 발생하므로 null 체크 로직을 추가함) 간단히 입력해 주면 좋다.</p>
<h3 id="span-stylecolor-lightblueconventional-commit"><span style="color: lightblue">Conventional commit</h3>
<p>Commit이나 PR에 대한 Comment를 달 때 Convention이 존재한다.
물론 이 Convention은 필수 사항은 아니고 회사마다 혹은 프로젝트 그룹마다 다를 순 있지만 일단 대표적인 Convention에 대해서는 알아보자.</p>
<ul>
<li><p>feat : 새로운 기능을 구현했거나 기존 서비스를 변경했을 때</p>
</li>
<li><p>fix : 버그 수정</p>
</li>
<li><p>perf : 성능 개선</p>
</li>
<li><p>refactor : 단순 코드 리팩토링</p>
</li>
<li><p>test : 테스트 추가 혹은 테스트 강화</p>
</li>
<li><p>build : 빌드 시스템이나 npm 배포에 대한 수정</p>
</li>
<li><p>ci : CI(Jenkins, Travis 등) 설정 수정</p>
</li>
<li><p>chore : 실제 코드엔 영향이 없는 단순 수정</p>
<ul>
<li>README.md 수정</li>
</ul>
</li>
</ul>
<blockquote>
<p>위 단어를 앞에 붙인 뒤 <code>:</code> 뒤에 PR에 대한 제목을 달아주면 된다.
예를 들어 A 기능을 개발했다면 Commit Message는 <code>feat : A 기능 개발</code>로 지어질 것이다.</p>
</blockquote>
<hr>
<h1 id="span-stylecolor-lightgreenpr-병합-창"><span style="color: lightgreen">PR 병합 창</h1>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/bdfd14a1-6ab1-4264-b595-9c5a61a32b5e/image.png" alt=""></p>
<h3 id="span-stylecolor-lightblue오른쪽-pr-설정-창주황색-네모"><span style="color: lightblue">오른쪽 PR 설정 창(주황색 네모)</h3>
<h4 id="span-stylecolor-orangereviewrs"><span style="color: orange">Reviewrs</h4>
<p>Project의 작업물을 리뷰해 줄 사람들을 지정해 주면 된다.</p>
<p>Test Code 및 Test Case를 생성하여 QA를 진행할 사람들을 추가시켜도 되고, Code Review를 수행해 줄 사람들을 추가시켜도 된다.</p>
<h4 id="span-stylecolor-orangeassignees"><span style="color: orange">Assignees</h4>
<p>해당 PR 목적을 달성하기 위해 작업할 실무자들을 등록해 주면 된다.
Assignees 존재 이유를 이해하기 위해선 PR의 특이점에 대해 알아야 한다.</p>
<p>Github는 PR이 생성된 이후 <code>compare</code>로 지정한 브랜치에 추가 커밋이 Push 되었다면 Push 된 추가 커밋 또한 (Merge pull request를 수행하지 않았다면) PR에 추가된다는 특징을 가진다.
따라서 PR을 먼저 생성하고 해당 PR을 위한 작업물을 저장할 브랜치와 실무자들을 등록해놓는다면 업무자들이 브랜치에 커밋을 수행할 때마다 PR에도 자동으로 커밋이 추가될 것이므로 실시간으로 업무 상황을 파악할 수 있게 된다.</p>
<blockquote>
<p>그 외의 Labels, Projects, Milestone, Development, Notification은 큰 활용도가 없다고 생각하여 설명을 생략하겠다.</p>
</blockquote>
<h3 id="span-stylecolor-lightbluemerge-pull-request-버튼"><span style="color: lightblue"><code>Merge pull request</code> 버튼</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/1ff9c7bb-7151-43df-8358-41833001275e/image.png" alt=""></p>
<h4 id="span-stylecolor-orange병합-커밋-생성create-a-merge-commit"><span style="color: orange">병합 커밋 생성(Create a merge commit)</h4>
<p>가장 기본적인 방법으로써 두 브랜치 상태를 비교하여 새로운 커밋을 만들면서 코드를 병합하는 방법이다.
Merge Commit(병합 커밋)과 동일한 과정이며 단지 이 과정이 원격 저장소에서 일어났을 뿐이다.</p>
<h4 id="span-stylecolor-orange스쿼시-해서-병합squash-and-merge"><span style="color: orange">스쿼시 해서 병합(Squash and merge)</h4>
<p>합병할 브랜치의 변경사항들을 하나로 묶어버린 후 병합하는 방법이다.</p>
<p>Rebase와 유사하다.
단지 Rebase의 경우 브랜치에 &quot;커밋2, 커밋3&quot;이 추가되었을 때 2개의 커밋을 다른 브랜치에 이어붙이지만 Squash and merge에서는 커밋2와 커밋3의 변경사항을 커밋4라는 새로운 커밋으로 묶어버림으로써 커밋4만 다른 브랜치에 이어붙인다.</p>
<p>Base 브랜치의 히스토리가 한 줄로 깔끔하게 남는 PR 방법이다.</p>
<h4 id="span-stylecolor-orange리베이스-후-병합rebase-and-merge"><span style="color: orange">리베이스 후 병합(Rebase and merge)</h4>
<p>이전에 언급했던 Rebase와 동일하며 단지 Rebase가 원격 저장소에서 진행될 뿐이다.
Merge Commit(병합 커밋)처럼 병합 결과를 저장할 커밋을 새로 생성하지 않으므로 Log는 깔끔히 남으면서도 병합시킨 브랜치의 작업 내용(커밋 이력) 또한 유지시킬 수 있다는 특징을 가진다.</p>
<h4 id="span-stylecolor-orangerebase-vs-squash"><span style="color: orange">Rebase VS Squash</h4>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/a81c9a53-800c-40d8-98e1-2dd4cd64f2c9/image.png" alt=""></p>
<h4 id="span-stylecolor-orangepr-중-conflict-발생-상황"><span style="color: orange">PR 중 Conflict 발생 상황</h4>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/336b9558-e18c-440a-9350-fa3c2463b7f5/image.png" alt=""></p>
<h2 id="span-stylecolor-lightbluecommits-섹션"><span style="color: lightblue">Commits 섹션</h2>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/f2e5a3da-12c7-4648-b3ef-8024881ef539/image.png" alt="">
해당 PR을 통해 Base 브랜치에 추가될 커밋들을 확인할 수 있는 섹션이다.</p>
<h2 id="span-stylecolor-lightbluefile-changed-섹션"><span style="color: lightblue">File Changed 섹션</h2>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/a1cea77e-ce07-4917-b6c6-f7daa3f78e1b/image.png" alt=""></p>
<p>PR을 수행함으로써 Base 브랜치의 HEAD와 비교했을 때 몇 개의 파일이 변경되었는지, 최종적으로 어떻게 변경되는지 확인할 수 있는 창이다.</p>
<p>이 섹션에선 몇 가지 재미있는 동작을 수행할 수 있는데 코드의 문제점을 알려주거나 코드 리뷰를 도와주는 기능들이다.</p>
<h3 id="span-stylecolor-orangereview-comment"><span style="color: orange">Review comment</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/e7869176-732e-4ffe-a88a-bd61f366a5f7/image.png" alt=""></p>
<p>변경된 파일의 라인에 마우스를 갔다 대보면 파란색 <code>+</code> 버튼이 활성화되며 이를 클릭하면 위 이미지와 같이 Comment 창이 발생한다.</p>
<p>여기에서 해당 코드에 대한 커멘트를 달 수 있다.</p>
<h3 id="span-stylecolor-orangereview-changes"><span style="color: orange">Review changes</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/974211be-7a5e-4886-a679-3c448096cd99/image.png" alt=""></p>
<p>오른쪽 위를 보면 <code>Reveiw Changes</code> 버튼이 존재하며 이를 클릭하면 위와 같은 창이 나온다.
이 버튼은 &quot;Review Comment&quot;를 통해 피드백한 내용(커멘트)들을 어떻게 PR에 반영할지 선택할 수 있게 해준다.</p>
<ul>
<li><p>Comment : Merge를 수행하지 않고 Comment만 추가한 채로 PR 상태를 변경</p>
<ul>
<li><p><code>Review changes</code>의 Comment는 <code>Review comment</code> 전체를 설명하는 Head Comment라고 보면 된다.</p>
<ul>
<li>(ex) Review Comment : NPE에 대한 검증 로직 추가 / Review Changes Comment : 1차 코드 리뷰</li>
</ul>
</li>
</ul>
</li>
<li><p>Approve : Comment는 남기되 PR을 수용함으로써 브랜치 2개를 Merge 시킴</p>
</li>
<li><p>Request changes : Feedback(Comment)를 모두 확인해야지 Merge를 수행할 수 있음</p>
<ul>
<li>많이 활용되지 않는 것 같은 옵션</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CLI를 통한 Pull & Fetch]]></title>
            <link>https://velog.io/@violet_evgadn/CLI%EB%A5%BC-%ED%86%B5%ED%95%9C-Pull-Fetch</link>
            <guid>https://velog.io/@violet_evgadn/CLI%EB%A5%BC-%ED%86%B5%ED%95%9C-Pull-Fetch</guid>
            <pubDate>Wed, 06 Sep 2023 15:42:49 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreencli-명령"><span style="color: lightgreen">CLI 명령</h1>
<h2 id="span-stylecolor-lightbluepull"><span style="color: lightblue">Pull</h2>
<p><code>git pull [Option] [원격 저장소 이름] &lt;branch명&gt;</code></p>
<p>이전에도 설명했지만 원격 저장소 이름은 대부분 origin이므로 사실상 <code>git pull [Option] origin &lt;branch명&gt;</code>이 규칙이라고 볼 수도 있다.</p>
<h3 id="span-stylecolor-orangepull-부가-설명"><span style="color: orange">Pull 부가 설명</h3>
<p>이전에 설명했듯 <code>git pull</code>은 원격 저장소의 코드를 로컬 저장소로 가지고 오는 명령어이다.
그리고 이를 Git 명령어를 통해 설명하자면 <code>git pull</code> = <code>git fetch</code> + <code>git merge</code>라고 할 수 있다.</p>
<ul>
<li><code>git fetch</code> : Git log 및 히스토리를 최신화</li>
<li><code>git merge</code> : 커밋을 하나로 합치는 작업</li>
</ul>
<p><code>git pull</code>이 일어날 경우 <code>git fetch</code>는 자동으로 이루어진다는 것은 개념적으로 외워두고 <code>git merge</code>에 대해서는 조금 더 알아보자.</p>
<p>만약 다른 협업자들이 Pull 받을 브랜치에 대해 작업을 수행했다면 원격 브랜치의 최신 버전(커밋) 같은 경우 로컬 저장소의 최신 커밋에서 추가적인 작업 내용이 추가된 상태일 것이다.
이를 병합 상황으로 파악한다면 Fast-forward 병합 상태라는 것을 알 수 있다.
따라서, <code>git pull</code>을 받는다는 것은 곧 &quot;<strong>로컬 저장소의 최종 커밋을 원격 저장소의 커밋으로 만들겠다</strong>&quot;라는 의미라고 볼 수 있는 것이다.</p>
<p><code>git pull</code> 같은 경우 동일한 브랜치에 대해 Pull 작업을 수행한다면 Fast-forward 병합 상황이므로 충돌이 발생할 가능성이 적지만 가끔 다른 브랜치에서 Pull을 수행할 때 버전 관리를 소홀히 했었다면 충돌이 발생할 가능성도 있다.
이 경우엔 <code>git pull</code> 대신 <code>git merge</code> 명령어를 통해 원격 저장소 커밋을 가져와 충돌을 해결해야 한다.</p>
<h3 id="span-stylecolor-orangeoption-및-사용법"><span style="color: orange">Option 및 사용법</h3>
<p>설명에 앞서 개인적으로 <code>git pull</code>을 사용하며 Option을 사용했던 적은 거의 없는 것 같다.
Option을 외우기보단 이런 것이 있구나 정도만 생각하고 넘어가도 될 것 같다.</p>
<ul>
<li><p><code>git pull --rebase origin &lt;branch명&gt;</code> : History가 정리된 상태로 git pull을 수행</p>
<ul>
<li>Rebase에 대해서는 나중에 자세히 배우겠지만 Git History를 변경시키는 명령어는 생각보다 매우 위험하다. 따라서 조심히 사용하도록 하자.</li>
<li>개인적으로는 필요 없어 보이는 커밋도 모두 History이기 때문에 굳이 history를 정리할 필요가 있나 싶긴 하다.</li>
</ul>
</li>
<li><p><code>git pull --ff-only origin &lt;branch명&gt;</code> : Fast-forward 병합일 때만 <code>git pull</code>을 수행</p>
</li>
</ul>
<h2 id="span-stylecolor-lightbluefetch"><span style="color: lightblue">Fetch</h2>
<pre><code class="language-bash">git fetch [Option] [원격 저장소 이름] &lt;branch명&gt;</code></pre>
<h3 id="span-stylecolor-orangeoption-및-사용법-1"><span style="color: orange">Option 및 사용법</h3>
<ul>
<li><p><code>git fetch --all</code> : 모든 Remote에서 Git History 및 Log를 가지고 옴</p>
</li>
<li><p><code>git fetch -t</code>, <code>git fetch --tags</code> : 지정한 remote의 모든 Tag를 가지고 온다.</p>
<ul>
<li>Git Tag에 대해선 나중에 자세히 설명하겠다.</li>
</ul>
</li>
</ul>
<h2 id="span-stylecolor-lightblue부가-설명"><span style="color: lightblue">부가 설명</h2>
<p>왜 Pull과 Fetch는 설명했는데 <code>Pull Request</code>는 명령어로 설명하지 않냐는 의문이 들 수 있다.</p>
<p>풀 리퀘스트는 엄밀히 따지면 단순한 Merge에 불과하다.
단지 이 Merge가 원격 저장소에서 일어나기 때문에 다른 협업자들에게 병합 소식을 알리기 위해 새로 만들어진 단어에 불과하다.</p>
<p>즉, 풀 리퀘스트는 작업 그 자체보다는 &quot;알림&quot;의 목적이 더 크고 이 때문에 CLI로 굳이 알 필요도 없으며 CLI로 수행할 수 있다 하더라도 &quot;알림&quot;의 기능을 하지 못한다면 의미가 없으므로 공부할 필요가 없는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[풀 리퀘스트, Pull & Fetch]]></title>
            <link>https://velog.io/@violet_evgadn/%ED%92%80-%EB%A6%AC%ED%80%98%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@violet_evgadn/%ED%92%80-%EB%A6%AC%ED%80%98%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 06 Sep 2023 13:44:13 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreenpull-request"><span style="color: lightgreen">Pull Request</h1>
<h3 id="span-stylecolor-lightbluepull-request란"><span style="color: lightblue">Pull Request란?</h3>
<p>우리는 이제 명령어나 IntelliJ를 활용해 브랜치를 언제든 생성하고, 통합시킬 수 있다.
하지만 지금까지는 &quot;로컬 저장소&quot;에서의 작업만 수행했다.</p>
<p>결국 여러 개발자와의 협업을 위해 &quot;git&quot;이라는 툴을 활용하기 위해선 원격 저장소를 잘 활용해야 할 필요가 있다.</p>
<p>그런데 이 원격 저장소에서는 내 마음대로 작업을 해서는 안 된다.
왜냐하면 원격 저장소는 협업하는 모든 사용자가 동시에 사용하는 공간이기 때문이다.</p>
<p>예를 들어 개발자 A가 branch A에 작업을 수행한 뒤 원격 저장소에 Push 했다고 가정하자.
그런데 개발자 B가 branch A를 맘대로 삭제시켜버리거나 아직 완성되지 않은 branch A 작업물을 main 브랜치에 머지 시켜버리면 안 될 것이다.</p>
<p>따라서 개발자는 원격 저장소에서 작업을 수행할 때 다른 협업자에게 작업 수행 여부 및 작업 내용을 알릴 필요가 있으며 특히 브랜치 병합(Merge)을 수행할 땐 필수적으로 다른 협업자에게 이를 알려야 한다. </p>
<p>풀 리퀘스트(Pull Request)는 다른 협업자에게 원격 저장소 브랜치 병합을 수행하겠다 알리는 메시지를 보내는 작업이다.</p>
<p>이러한 원격 저장소의 작업은 원격 저장소에서만 수행할 수 있다.
아마 대부분은 Github나 Bitbucket 같은 소스코드 호스팅 사이트를 사용할 것이므로 Github나 Bitbucket에 가야지만 Pull Request를 수행할 수 있을 것이다.</p>
<h3 id="span-stylecolor-lightblue풀pull--패치fetch"><span style="color: lightblue">풀(Pull) &amp; 패치(Fetch)</h3>
<p>풀 리퀘스트(Pull Request)는 원격 저장소에서 2개의 브랜치를 합치는 과정이라고 요약할 수 있을 것이다.
그런데 2개의 브랜치를 합치는 과정에서 &quot;<strong>충돌(Conflict)</strong>&quot;가 발생할 수 있다.</p>
<p>로컬 저장소에서 충돌이 발생하지 않는다면 원격 저장소에서도 충돌이 발생하지 않을 것이고, 원격 저장소에서의 충돌 해결은 로컬 저장소에서 IntelliJ나 VSCode 등의 툴을 활용하는 방법보다 어렵기 때문에 무조건 로컬에서 정상적으로 병합(Merge)가 되는지 확인한 뒤 작업물을 원격 저장소에 Push 하는 것이 좋다.</p>
<p>그리고, 이 과정에서 필수적으로 수행해야 하는 것이 Pull과 Fetch이다.</p>
<p>풀(Pull)은 원격 저장소에 있는 코드를 내려받는 과정이고 패치(Fetch)는 Git log와 그래프(업데이트 이력)을 최신화하는 과정이다.</p>
<p>IntelliJ 같은 툴에서는 일정 시간이 지나면 자동으로 git Fetch를 진행하긴 하지만 Git push 이전 무조건 수행하는 것이 좋다.</p>
<p>특히, <code>git pull</code> 과정은 무조건 거쳐야 한다.</p>
<p>내가 작업을 하고 있는 과정에도 여러 협업자들은 각자의 작업을 하였고, 이를 다른 브랜치에 병합(Merge) 시켰을 것이다.
그리고 내가 병합하고 싶은 <code>main 브랜치</code>나 <code>develop 브랜치</code>에도 자신의 작업 내용을 반영했을 수도 있다.</p>
<p>따라서 충돌을 로컬 저장소에서 모두 해결한 뒤 원격 저장소에 Push하기 위해선 먼저 원격 저장소의 코드를 <code>git pull</code>을 통해 최신화한 뒤 커밋 및 Push를 진행해야 한다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenintellij에서의-pull-request"><span style="color: lightgreen">IntelliJ에서의 Pull Request</h1>
<h3 id="span-stylecolor-lightblue0-원격-저장소와-로컬-저장소-동기화시키기"><span style="color: lightblue">0. 원격 저장소와 로컬 저장소 동기화시키기</h3>
<p><code>git push</code>를 수행해도 되고 동기화가 어려우면 로컬 저장소를 새로 만들어 Github 작업물을 받아오자.</p>
<h3 id="span-stylecolor-lightblue1-새로운-브랜치-생성--파일-수정-후-커밋"><span style="color: lightblue">1. 새로운 브랜치 생성 &amp; 파일 수정 후 커밋</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/e9994ac6-43ca-463d-bcb6-acf98aa23bfa/image.png" alt=""></p>
<h3 id="span-stylecolor-lightblue2-github에서-원격-저장소-파일-수정--커밋"><span style="color: lightblue">2. Github에서 원격 저장소 파일 수정 &amp; 커밋</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/b3d4a763-e0ed-466d-9e51-74446c98ba99/image.png" alt=""></p>
<p>충돌이 발생하도록 1번에서 수정한 파일과 같은 파일을 수정하는 것을 추천한다.
(그래야 실습이 더욱 와닿는다)</p>
<h3 id="span-stylecolor-lightblue3-main-브랜치-이동checkout--pull-받기"><span style="color: lightblue">3. main 브랜치 이동(<code>checkout</code>) &amp; Pull 받기</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/f2cc6f2a-5f34-4ac6-9177-13d3ab9f9b89/image.png" alt=""></p>
<p>우리는 main 브랜치에 우리의 작업물을 반영하고 싶다.
따라서 main 브랜치로 <code>checkout</code> 한 뒤 <code>git pull</code>을 통해 원격 저장소 파일로 로컬 저장소의 파일을 최신화하자.</p>
<h3 id="span-stylecolor-lightblue4-pull-받기"><span style="color: lightblue">4. Pull 받기</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/53592060-032c-4617-a59d-9dab0fba7b6c/image.png" alt=""></p>
<p><code>Pull</code> 버튼을 누른 뒤 오른쪽 아래에 빨간색 글씨가 없다면 성공적으로 원격 저장소 작업물을 로컬 저장소에 가지고 온 것이다.</p>
<h3 id="span-stylecolor-lightblue5-로컬-저장소에서-merge-해보기"><span style="color: lightblue">5. 로컬 저장소에서 Merge 해보기</h3>
<p>우리가 Push할 작업물은 1번 과정에서 생성한 <code>pull_request_branch 브랜치</code>에 존재한다.
즉, 우리는 <code>pull_requeste_branch 브랜치</code>에서 원격 저장소로 Push 작업을 진행할 것이다.</p>
<p>이런 점을 고려했을 때 충돌 해결을 위해선 <code>pull_request_branch 브랜치</code>로 이동(<code>checkout</code>) 한 뒤 <code>main 브랜치</code>에 대해 Merge(병합) 요청을 수행하자.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/1b9ba79d-b0be-4085-b7a8-1282870c3a7c/image.png" alt=""></p>
<p>만약 과정을 잘 따라왔다면 위와 같이 Conflict 해결 팝업 창이 떴을 것이고, 이전 Section처럼 충돌을 해결하면 된다.</p>
<h3 id="span-stylecolor-lightblue6-git-push"><span style="color: lightblue">6. Git Push</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/033c2dce-d933-4e0c-9320-6bb0b3bff606/image.png" alt=""></p>
<p>Git &gt; Push를 클릭하면 아래와 같은 팝업 창이 뜬다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/310ab778-8b00-4419-bb48-6c09cf695374/image.png" alt=""></p>
<p>만약 작업물을 Push할 원격 저장소 Branch를 변경하고 싶다면 origin 옆에 있는 &quot;pull_request_branch&quot;을 클릭해 보자.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/e9389f34-c1b6-4133-b17c-854ee6a154f1/image.png" alt=""></p>
<p>그럼 원격 저장소 브랜치 글씨가 입력 가능한 입력창으로 바뀐다.
이 때 원하는 원격 브랜치 명으로 수정하면 된다.</p>
<p>지금은 <code>pull_request_branch 브랜치</code>에 Push할 것이므로 수정하지 않고 바로 Push 버튼을 누르자.</p>
<h3 id="span-stylecolor-lightblue7-github-접속--pull-requests-선택"><span style="color: lightblue">7. Github 접속 &amp; Pull Requests 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/39fc7f0e-6b6b-4f4a-b3a8-60984ea8b59b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/579d7431-74ca-4b3c-b9fd-85c61254fb1a/image.png" alt=""></p>
<p>첫 번째 이미지의 빨간색 네모 중 하나를 클릭하면 Pull Request를 생성할 수 있다.
만약 위쪽 Pull Requests 버튼을 클릭했다면 2번째 이미지에서 빨간색 네모 안에 있는 <code>New Pull request</code> 버튼을 클릭하여 Pull Requests를 생성할 수 있다.</p>
<h3 id="span-stylecolor-lightblue8-pull-requests-생성-창---pull-request-창"><span style="color: lightblue">8. Pull Requests 생성 창  &amp; Pull Request 창</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/ff7c7907-8fe0-4ddb-8b23-2bda6d5443ce/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/16c5c22d-4f7f-4848-8552-ff56f2311b1b/image.png" alt=""></p>
<p>2개 창에 대해선 다음 Section에서 자세히 알아보자.
일단 지금은 이런 창이 생성된다는 것 정도만 알고 넘어가자.</p>
<p>첫 번째 이미지에서 <code>Create pull request</code> 버튼을 누르면 두 번째 이미지의 창이 뜨고, 여기서 <code>Merge pull request</code> 버튼을 누르면 <code>Confirm merge</code> 버튼으로 바뀐다.
<code>Confirm merge</code> 버튼을 누르면 원격 저장소에서 <code>pull_request_branch 브랜치</code>를 <code>main 브랜치</code>에 병합시킬 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/d9f16e0d-5e92-43ce-8e93-a628d602c836/image.png" alt=""></p>
<p><code>Confirm merge</code> 버튼을 누르면 위 이미지와 같은 창이 뜰 텐데 이는 원격 저장소에서 <code>pull_request_branch 브랜치</code>를 삭제할지 물어보는 것이다.
더 이상 원격 저장소에서 해당 브랜치를 사용할 것 같지 않다면 <code>Delete branch</code> 버튼을 클릭하여 브랜치를 삭제하자.</p>
<h3 id="span-stylecolor-lightblue9-상태-확인"><span style="color: lightblue">9. 상태 확인</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/78338a2c-d80a-4080-bb89-7ff94777540f/image.png" alt=""></p>
<p>main 브랜치에 정상적으로 작업물이 반영되었음을 볼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[충돌(Conflict) & Pull Request]]></title>
            <link>https://velog.io/@violet_evgadn/%EC%B6%A9%EB%8F%8CConflict-Pull-Request</link>
            <guid>https://velog.io/@violet_evgadn/%EC%B6%A9%EB%8F%8CConflict-Pull-Request</guid>
            <pubDate>Wed, 06 Sep 2023 12:43:45 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolor-lightgreen충돌"><span style="color: lightgreen">충돌</h1>
<h3 id="span-stylecolor-lightblue충돌의-발생-이유"><span style="color: lightblue">충돌의 발생 이유</h3>
<p>드디어 git의 발암물질, 충돌에 대해 알아볼 차례이다.
충돌이 무엇인지는 이전 섹션에서 간단히 설명했으므로, 충돌이 어째서 발생하는지에 대해 조금 더 설명하도록 하겠다.</p>
<p>이제 Git에 대해서도 많이 공부했으니 Git에서 Commit은 버전을 의미하고 각 Commit은 Parent Commit(이전 커밋)의 ID를 저장하고 있는 LinkedList 형식으로 이루어졌다는 것을 알고 있을 것이다</p>
<p>Git은 협업을 위한 도구이며 당연히 1개 커밋에서 여러 개의 브랜치를 생성해 여러 명의 유저가 작업을 수행할 수 있다.</p>
<p>커밋 A를 기준으로 Branch B1과 Branch B2가 만들어졌고 협업이 수행되었다고 가정하자.
이후 Branch B1이 먼저 커밋 A에 Push 하여 최신 브랜치를 B1으로 만들었다고 치자.
이후 Branch B2가 작업하면 분명 Branch B2가 만들어졌을 때만 해도 커밋A 기준으로 만들었으니 커밋A가 최신 브랜치여야 할 텐데, 웬 이상한 Branch B1 작업물이 최신 브랜치가 된 것이다.</p>
<p>Git에서는 변경된 부분만 Staging Area에 등록되기 때문에 만약 Branch B1과 B2의 작업물이 겹치지 않는다면 정상적으로 병합 커밋(Merge Commit)이 발생할 것이다.
하지만, 동일한 파일에 대하여 작업이 수행되었다면 커밋 A를 기준으로 만들어진 Branch B2는 B1의 작업물을 알지 못하는 상태이므로 충돌이 발생하는 것이다.</p>
<hr>
<h1 id="span-stylecolor-lightgreenintellij에서의-충돌-해결"><span style="color: lightgreen">IntelliJ에서의 충돌 해결</h1>
<h3 id="span-stylecolor-lightblue충돌-해결-방법-설명에-앞서"><span style="color: lightblue">충돌 해결 방법 설명에 앞서</h3>
<p>이런 충돌은 Git에서 생각보다 빈번하게 일어난다.
빈번하게 일어나는 만큼 충돌의 해결법도 알아둬야 한다.</p>
<p>지금까지 Git에서 충돌이 발생했다면 일단 머지를 시도한 뒤 Github나 VSCode 같은 툴에서 <code>&lt;&lt;&lt;&lt;&lt;&lt;</code>, <code>======</code>, <code>&gt;&gt;&gt;&gt;&gt;</code> 같은 기호 사이에 있는 코드를 잘 조합하는 걸로 해결했을 것이다.
필자도 원래는 그렇게 했지만 이전 회사에서 사용했던 호스팅 사이트 Bitbucket에는 머지 시 충돌을 Bitbucket 사이트에서 해결할 수가 없었다.</p>
<p>그래서 회사 선배에게 배웠던 이런 상황에서도 충돌을 해결할 수 있는 현업 맞춤용 충돌 해결법을 설명하도록 하겠다.</p>
<p>추가로, 충돌은 CLI로 해결하기엔 너무 까다롭다. 특히 프로젝트의 규모가 커질수록 CLI로 충돌을 해결하는 것은 사실상 불가능해진다.
따라서, 충돌 해결은 IntelliJ나 VSCode 같은 작업 툴에서 하도록 하자.</p>
<h3 id="span-stylecolor-lightblue0-충돌이-일어나도록-1개-브랜치-생성"><span style="color: lightblue">0. 충돌이 일어나도록 1개 브랜치 생성</h3>
<p>필자는 README 파일을 수정하였고 main 브랜치는 <code>Main 브랜치 등장!</code> 문구를, 새로 생성한 branch_b1 브랜치에는 <code>B1 브랜치 등장!</code>이라는 문구를 추가한 뒤 각자 커밋 해줬다.
(무조건 충돌이 일어나도록 두 브랜치 파일 동일한 Line에 해당 문구를 추가했다. 요즘 Git이 많이 발전해서 Line이 다르면 충돌이 아니라고 판단하는 경우도 있다)</p>
<h3 id="span-stylecolor-lightblue1-병합-시킬-브랜치-중-베이스로-할-브랜치로-이동checkout"><span style="color: lightblue">1. 병합 시킬 브랜치 중 베이스로 할 브랜치로 이동(<code>checkout</code>)</h3>
<p>협업을 할 때는 베이스로 할 브랜치가 main 브랜치 혹은 develop 브랜치인 경우가 많다.
문제는 대부분 그 경우 main 브랜치나 develop 브랜치는 개발 서버, 혹은 운영 서버와 연결되어 있고 조금 좋은 회사로 가면 CI/CD 자동화까지 잘 되어 있어 함부로 머지 시키기도 힘들다.</p>
<p>따라서 이 경우에는 베이스로 할 브랜치를 기반으로 새로운 브랜치를 만든 뒤 새로 생성한 브랜치로 <code>checkout</code>하는 것을 추천한다.</p>
<p>필자는 main 브랜치를 기반으로 <code>merge_main</code> 브랜치를 새로 생성한 뒤 이동했다.</p>
<h3 id="span-stylecolor-lightblue2-git--merge-선택"><span style="color: lightblue">2. Git &gt; Merge 선택</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/f27c4669-16a4-48d5-9b61-e2de90ccf718/image.png" alt=""></p>
<p>1번 과정에서 Main을 기반으로 만든 브랜치에 <code>branch_b1</code> 브랜치를 병합하자.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/f3b6933d-7ed6-498e-b820-52fb5f2ec683/image.png" alt=""></p>
<p>위와 같은 창이 나온다면 충돌이 성공적으로(?) 발생한 것이다.</p>
<h3 id="span-stylecolor-lightblue3-팝업-창에서-충돌이-발생한-파일명-더블-클릭"><span style="color: lightblue">3. 팝업 창에서 충돌이 발생한 파일명 더블 클릭</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/7eda30b0-4955-4764-9fb2-2c2fd1290cba/image.png" alt=""></p>
<p>물론 2번 과정에서 <code>Accept Yours</code>, 혹은 <code>Accept Theris</code>를 클릭해도 해결은 된다.
문제는 저 둘 중 하나를 선택한다면 다른 개발자가 작업한 작업물이 날아갈 위험성이 있다는 것이다.</p>
<p>예를 들어 <code>Accept Yours</code>를 선택하면 (Main 브랜치에서 병합을 시켰으니) <code>Main 브랜치 등장!</code> 문구만 최종적으로 남을 것이고 <code>Accept Theirs</code>를 선택하면 <code>B1 브랜치 등장!</code>이라는 문구만 최종적으로 남을 것이다.
이런 리스크는 너무 위험하기 때문에 위험을 줄이기 위하여 파일 하나하나 꼼꼼히 더블클릭한 후 충돌이 어디서 발생했는지 확인해 보자.</p>
<h3 id="span-stylecolor-lightblue3-2-충돌-해결"><span style="color: lightblue">3-2. 충돌 해결</h3>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/e15d01e3-51d8-45ce-a60f-9d20dcee0976/image.png" alt="">
아마 파일명을 더블 클릭하면 위 사진과 같이 &quot;어떤 부분에서 충돌이 발생했는지&quot;가 뜰 것이다.
위 사진을 보면 <code>Main 브랜치 등장!</code> 부분에서 병합 시 충돌이 발생했을 것이라고 직관적으로 이해 가능할 것이다.</p>
<p>여기에서 개발자는 2가지 선택을 할 수 있는데, <code>&gt;&gt;</code>와 <code>X</code>이다.
<code>&gt;&gt;</code>는 병합이 발생한 부분을 최종 결과물에 반영하겠다는 것이고 <code>X</code>는 병합 후 최종 결과물에 충돌이 발생한 부분을 삭제하겠다는 의미이다.
우리는 <code>Main 브랜치 등장!</code>과 <code>B1 브랜치 등장!</code>이라는 문구 2개를 모두 살리고 싶기 때문에 <code>&gt;&gt;</code>와 <code>&lt;&lt;</code> 버튼을 클릭하도록 하자.</p>
<p><img src="https://velog.velcdn.com/images/violet_evgadn/post/14b4d171-ade5-4e30-9a72-63a388c1cffe/image.png" alt="">
중간에 있는 창이 병합 후 최종 결과물이다.
중간 창을 보면 <code>B1 브랜치 등장!</code>과 <code>Main 브랜치 등장!</code> 문구가 모두 살아있음을 볼 수 있다.
(만약 순서가 신경 쓰이거나 새로운 내용을 추가하고 싶을 경우 가운데 창에서도 작업을 수행할 수 있으므로 직접 수정해 주도록 하자)</p>
<p>이런 방식으로 창에 빨간색 부분(충돌이 발생한 부분)이 모두 없어지면 오른쪽 아래에 있는 <code>Apply</code> 버튼을 클릭해 주면 된다.</p>
<h3 id="span-stylecolor-lightblue4-main-브랜치에-merge_main-브랜치-병합"><span style="color: lightblue">4. main 브랜치에 <code>merge_main</code> 브랜치 병합</h3>
<p>우리는 최종적으로 <code>main 브랜치</code> 혹은 <code>develop 브랜치</code>에 작업물을 반영해야 한다.
그리고 아직 우리는 <code>merge_main</code>이라는 <code>main 브랜치</code>를 기반으로 만든 브랜치에만 작업물을 반영했다.</p>
<p>따라서 <code>main 브랜치</code>로 이동한 후 Git &gt; Merge 버튼을 클릭한 뒤 <code>git merge merge_main</code>을 선택하면 충돌 없이(정확히는 충돌을 모두 해결한 상태로) 병합을 완료할 수 있다.
<img src="https://velog.velcdn.com/images/violet_evgadn/post/8892f819-3807-47e7-bf3b-9c25b4cc141f/image.png" alt=""></p>
<p>이는 <code>merge_main</code> 브랜치에 존재하는 커밋은 &quot;이미 충돌이 해결된 커밋&quot;으로 git에서 인지하기 때문에 <code>main 브랜치</code>와 <code>merge_main 브랜치</code>를 병합할 때 <code>main 브랜치</code>에 &quot;충돌이 해결된 작업물&quot;을 머지 한다고 판단하여 충돌 없이 바로 병합 가능해지는 것이다.</p>
]]></description>
        </item>
    </channel>
</rss>