<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>404 error가 뜨는 개념 찾기</title>
        <link>https://velog.io/</link>
        <description>내가 공부하기 위해 시작한 velog</description>
        <lastBuildDate>Sat, 07 Mar 2020 10:48:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>404 error가 뜨는 개념 찾기</title>
            <url>https://images.velog.io/images/404_jjuya/profile/17f19aea-c0ca-49d1-b407-7cbd26191db5/KakaoTalk_Photo_2020-02-06-15-18-18.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 404 error가 뜨는 개념 찾기. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/404_jjuya" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Git] Git merge 전략]]></title>
            <link>https://velog.io/@404_jjuya/Git-merge-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@404_jjuya/Git-merge-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Sat, 07 Mar 2020 10:48:41 GMT</pubDate>
            <description><![CDATA[<h2 id="create-a-merge-commitmerge-commit">Create a merge commit(Merge commit)</h2>
<p>보통 일반적으로 알고 있는 머지 전략이다. 이 방법은 머지 브랜치가 삭제되더라도 히스토리 그래프 상에는 다른 가지로 남아있다.&#39;어떤 브랜치에서 어떤 커밋이 진행되어 어떻게 머지 되었군&#39;을 자세하게 알 수 있는 히스토리가 남는다. 머지가 수행되면 머지커밋(merge commit)이 생긴다. 이는 &#39;어느 순간에 어떤 브랜치의 변경 사항이 머지되었다.&#39;를 알려준다. 다만 브랜치의 개수가 많아지거나 머지 횟수가 많아지면 히스토리 그래프의 가독성이 떨어진다.</p>
<h2 id="squash-and-mergesquash">Squash and merge(Squash)</h2>
<p>여기서 <code>squash</code>는 여러 개의 커밋을 하나로 합치는 기능을 말한다. 이 전략은 머지 브랜치의 커밋을 전부 하나의 커밋으로 합친 뒤 타겟 브랜치에 커밋하는 방식으로 머지가 진행된다. 여기서 발생하는 머지 커밋은 실질적인 머지로 생긴 것이 아니라, 머지 브랜치의 변경 사항을 하나로 뭉친 변경 사항에 대한 커밋이다. 그렇기 때문에 머지 브랜치의 가지가 타겟 브랜치로 들아가는 것이 아니라 타켓 브랜치에 새로운 커밋이 추가된 모습으로 히스토리 그래프에 나타난다.</p>
<p>히스토리 상에서 알아보기 쉽고, 버전 별로 어떤 것이 변경되었는지 쉽게 알 수 있다. 그리고 머지 브랜치의 자잘한 커밋이 남지 않기 때문에 &#39;머지 되었다.&#39;라는 것에 집중하기 때문에 변경 사항을 읽기 수월하다. 하지만 일반 적인 머지 커밋보다는 정보력이 떨어진다. 어떤 커밋을 통해 어떤 부분을 수정했는지는 알 수 없다.</p>
<h2 id="rebase-and-mergefast-forward">Rebase and merge(Fast forward)</h2>
<p><code>rebase</code>는 브랜치의 히스토리들의 베이스를 변경하는 방법이다. 이를 이용하여 브랜치를 머지하는 전략이다. 누가 언제, 어떤 부분을 수정했는지 머지 브랜치의 커밋을 모두 살려놓는다. 하지만 어느 시점에 머지 되었는지 알 수 없다. 이를 해결하기 위해 <code>tag</code>기능을 사용한다.</p>
<p>머지 시 충돌이 날 경우 각각의 커밋에 대해 충돌이 발생한다. 그 이유는 머지 브랜치의 히스토리 자체를 복사해서 타켓 브랜치에 박아버리는 방식이기 떄문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Babel]]></title>
            <link>https://velog.io/@404_jjuya/Babel</link>
            <guid>https://velog.io/@404_jjuya/Babel</guid>
            <pubDate>Fri, 28 Feb 2020 06:46:48 GMT</pubDate>
            <description><![CDATA[<h2 id="babel">Babel</h2>
<h3 id="js-transpiler">JS Transpiler</h3>
<p>Babel은 ES6 이상의 최신 문법을 ES5 이하의 문법으로 작성한 것 처럼 소스코드 내의 문법 형태를 변경해주는 JS transpiler. JS compiler라고 부르기도 한다.
Babel을 사용해 문법 형태가 변경된 소스 코드는 최신 문법을 지원하는 실행 환경 뿐만 아니라 아직 최신 문법들이 적용되지 않은 실행 환경에서도 작동한다.</p>
<blockquote>
<p>compile은 인간이 작성한 소스 코드를 컴퓨터가 이해할 수 있도록 머신 코드로 바꿔주는 과정을 뜻한다.
transfile은 다른 실행 환경에서도 돌아갈 수 있도록 같은 언어를 유지한체 소스 코드의 형태만 바꾸는 과정을 뜻한다.
JS는 인터프리터 언어이기 때문에 컴파일 과정이 필요 없지만 JS 커뮤니티에서는 이 두 용어가 혼용되어 사용되고 있다.</p>
</blockquote>
<h3 id="기능">기능</h3>
<ul>
<li>구문 변환</li>
<li>Polifill 지원 (<a href="https://babeljs.io/docs/en/babel-polyfill">@babel/polifill</a>)</li>
<li>소스 코드 변환</li>
<li><a href="https://babeljs.io/videos.html">+a</a></li>
</ul>
<h3 id="예시">예시</h3>
<pre><code class="language-javascript">// Babel Input: ES2015 arrow function
[1, 2, 3].map((n) =&gt; n + 1)

// Babel Output: ES5 equivalent
[1, 2, 3].map(function(n) {
  return n + 1;
})</code></pre>
<h2 id="사용해보자">사용해보자!</h2>
<h4 id="babelcore-babelcli">@babel/core, @babel/cli</h4>
<pre><code class="language-bash"># npm
$ npm install --save-dev @babel/core @babel/cli

# yarn
$ yarn add -D @babel/core @babel/cli</code></pre>
<p><code>@babel/core</code>,<code>@babel/cli</code>를 devDependencies에 추가한다. 그 이유는 Babel은 빌드 시에 필요하기 때문이다.</p>
<blockquote>
<p><code>@babel/core</code>는 항상 필요로 하는 패키지이며 transform에 필요한 도구이다.
<code>@babel/cli</code>는 터미널에서 cammand line을 통해서 transpile 할 수 있는 도구이다.</p>
</blockquote>
<h4 id="plugin--preset">plugin / preset</h4>
<p>Babel은 plugin과 preset을 통해 코드를 어떻게 변환할지 판단하고 동작한다. plugin은 규칙 하나하나 미세하게 적용할 때 사용한다. preset은 plugin의 배열으로 여러 개의 규칙을 한번에 적용한다.</p>
<p>이는 Babel의 설정 파일인 <code>babel.config.js</code> 혹은 <code>.babelrc</code>에 입력해준다.</p>
<blockquote>
<p>Babel command를 실행할 때마다 매번 옵션을 붙이기 번거로워 Babel 설정 파일을 이용한다. 설정 파일은 root에 추가하여 사용한다.</p>
</blockquote>
<p><strong>ex) babel.config.js</strong></p>
<pre><code class="language-javascript">module.exports = fuction(api) {
  api.cache(true)

  const presets = [&#39;next/babel&#39;]

  const plugins = [
    [
      &#39;@babel/plugin-proposal-decorators&#39;,
      {
        legacy: true,
      },
    ],
    [
      &#39;@babel/plugin-proposal-class-properties&#39;,
      {
        loose: true,
      },
    ],
  ]

  return { presets, plugins }
}</code></pre>
<p>위의 예시에서는 <code>nextjs</code>를 사용하고 있기 때문에 nextjs의 preset을 적용하였다. 가장 범용적으로 사용하는 preset은 <code>@babel/preset-env</code>이다.</p>
<p>plugin의 경우에는 <a href="https://babeljs.io/docs/en/plugins">Babel 공식 사이트 - plugins</a> 혹은 검색을 이용하여 적절하게 사용하는 것이 좋다.</p>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://babeljs.io/docs/en/">Babel 공식 사이트</a>
<a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/user-handbook.md#making-your-own-preset">Babel User Handbook</a>
<a href="https://jaeyeophan.github.io/2017/05/16/Everything-about-babel/">(번역) Everything you need to know about BabelJS</a>
<a href="https://www.zerocho.com/category/ECMAScript/post/57a830cfa1d6971500059d5a">BabelJS(바벨)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] Refspec]]></title>
            <link>https://velog.io/@404_jjuya/Git-Refspec</link>
            <guid>https://velog.io/@404_jjuya/Git-Refspec</guid>
            <pubDate>Wed, 26 Feb 2020 07:39:30 GMT</pubDate>
            <description><![CDATA[<pre><code>$ git push -u origin refs/heads/candidate/${_NODE_ENV}/*</code></pre><p>위 명령은 <code>origin</code>이라는 저장소의 <code>refs/heads/candidates/${_NODE_ENV}/*</code>의 브랜치에 push를 한다. 이 명령어를 보고 시작한 Refspec 개념 정리입니다.</p>
<h2 id="형식">형식</h2>
<pre><code>+ &lt;src&gt;:&lt;dst&gt;</code></pre><ul>
<li><code>+</code> : fast-forward가 아닌 업데이트를 허용한다는 의미, 생략 가능</li>
<li><code>&lt;src&gt;</code> : source 패턴, <strong>원본</strong><ul>
<li>리모트 저장소의 Refs 패턴(??)</li>
<li>기본적으로 <code>refs/heads/*</code> 로 설정</li>
</ul>
</li>
<li><code>&lt;dst&gt;</code> : destination 패턴, <strong>합쳐야 할 대상</strong><ul>
<li>리모트 저장소에 매칭되는 로컬 저장소의 Refs 패턴(??)</li>
<li>리모트 저장소는 로컬 저장소의 refs를 매핑해 <code>refs/remotes/리모트 저장소명/*</code>으로 Refs를 저장해 둔다.(로컬 저장소의 refs와 동일한 해시값을 가진다.)</li>
</ul>
</li>
</ul>
<blockquote>
<p>기본적으로 git은 <code>git remote add</code> 명령으로 생성한 설정을 참고하여 리모트 서버에서 <code>refs/heads/</code>에 있는 Refs를 가져다 로컬의 <code>refs/remotes/origin/</code>에 기록</p>
</blockquote>
<h2 id="예시">예시</h2>
<h3 id="git-log"><code>git log</code></h3>
<h4 id="로컬의-히스토리-접근">로컬의 히스토리 접근</h4>
<pre><code>$ git log master
$ git log heads/master
$ git log refs/heads/master</code></pre><h4 id="리모트의-히스토리-접근">리모트의 히스토리 접근</h4>
<pre><code>$ git log origin/master
$ git log remotes/origin/master
$ git log refs/remotes/origin/master</code></pre><h3 id="git-fetch"><code>git fetch</code></h3>
<pre><code># .git/config
fetch = +refs/heads/*:refs/remotes/origin/*</code></pre><p>이는 해당 리모트 저장소에서 <code>git fetch</code> 명령을 실행할 때 자동으로 사용되는 Refspec이다.</p>
<pre><code>$ git fetch origin master:refs/remotes/origin/mymaster</code></pre><p>리모트 브랜치 <code>master</code>(원본)를 로컬 브랜치 <code>origin/mymaster</code>(합쳐야 할 대상)로 가져온다.</p>
<h3 id="git-push"><code>git push</code></h3>
<pre><code>$ git push origin master</code></pre><p>위에서 <code>master</code>는 <code>refs/heads/master:refs/heads/master</code>를 의미한다. <code>&lt;src&gt;</code>는 푸쉬하기를 원하는 브랜치의 refs(원본), <code>&lt;dst&gt;</code>는 리모트에 푸시가 될 때 업데이트 될 브랜치의 refs(합쳐야 할 대상)이다.</p>
<pre><code>$ git push origin master:refs/heads/qa/master</code></pre><p>로컬의 <code>master</code> 브랜치를 리모트의 <code>qa/master</code>로 push한다.</p>
<h2 id="끝맺음">끝맺음</h2>
<p>정리하면서도 계속 헷갈리는 개념이다. 앞으로 cli로 삽질 하면서 익히는 수 밖에 없을 것 같다.</p>
<hr>
<p>참고
<a href="https://git-scm.com/book/ko/v2/Git%EC%9D%98-%EB%82%B4%EB%B6%80-Refspec">10.5 Git의 내부 - Refspec</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] Refs]]></title>
            <link>https://velog.io/@404_jjuya/Git-Refs</link>
            <guid>https://velog.io/@404_jjuya/Git-Refs</guid>
            <pubDate>Wed, 26 Feb 2020 02:13:49 GMT</pubDate>
            <description><![CDATA[<h2 id="refs">Refs</h2>
<p>git의 커밋은 key-value 형식으로 이루어져 있는데, key 값은 SHA-1으로 만들어진 해쉬값이다. 이를 사람들이 기억하기 어렵기 때문에 외우기 쉬운 이름의 파일에 저장되어 있는데, 이를 저장해 놓은 파일을 <code>References</code> 혹은 <code>Refs</code>라고 한다.</p>
<blockquote>
<p>모든 refs는 <code>.git/refs</code>에 저장된다.</p>
</blockquote>
<h3 id="브랜치">브랜치</h3>
<p>git의 브랜치는 <strong>어떤 작업 중 마지막 작업을 가르키는 포인터 또는 Refs</strong>이다. 브랜치는 직접 가리키는 저밋과 그 커밋으로 따라갈 수 있는 모든 커밋을 포함한다.</p>
<blockquote>
<p>git의 <code>git branch &lt;branch&gt;</code>를 실행하면 내부적으로 <code>update-ref</code>명령을 실행하고, 입력받은 브랜치 이름과 현 브랜치의 마지막 커밋의 SHA-1 값을 가져다 <code>update-ref</code>명령을 실행</p>
</blockquote>
<h3 id="head">HEAD</h3>
<p>HEAD 파일은 <strong>현 브랜치를 가리키는 간접 Refs</strong>다. 이 Refs는 다른 Refs를 가리키는 것이라서 SHA-1 값이 없다.</p>
<blockquote>
<p><code>git commit</code> 을 실행하면 커밋 개체가 만들어지는데, 지금 HEAD가 가리키고 있던 커밋의 SHA-1 값이 그 커밋 개체의 부모로 사용된다.
HEAD 파일도 손으로 직접 편집할 수 있지만 <code>git symbolic-ref</code> 라는 명령어가 있어서 좀 더 안전하게 사용할 수 있다. 이 명령으로 HEAD의 값을 읽고 변경할 수 있다.(다만 refs 형식에 맞춰야 한다.)</p>
</blockquote>
<h3 id="태그">태그</h3>
<p>태그는 커밋이랑 매우 비슷하다. 커밋처럼 누가, 언제 태그를 달았는지 태그 메시지는 무엇이고 어떤 커밋을 가리키는지에 대한 정보가 포함된다. <strong>태그는 Tree가 아니라 커밋을 가르킨다.</strong> </p>
<p>브랜치처럼 커밋을 가리키지만 옮길 수는 없다. 태그는 늘 그 이름이 뜻하는 커밋만 가리킨다.</p>
<h3 id="리모트">리모트</h3>
<p><code>refs/heads</code> 에 있는 Refs인 브랜치와 달리 리모트 Refs는 Checkout 할 수 없고 읽기 용도로만 쓸 수 있는 브랜치인 것이다. 이 리모트 Refs는 <strong>서버의 브랜치가 가리키는 커밋이 무엇인지 적어둔 일종의 북마크</strong>이다.</p>
<blockquote>
<p>리모트를 추가하고 Push 하면 Git은 각 브랜치마다 Push 한 마지막 커밋이 무엇인지 <code>refs/remotes</code> 디렉토리에 저장한다.</p>
</blockquote>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://git-scm.com/book/ko/v2/Git%EC%9D%98-%EB%82%B4%EB%B6%80-Git-Refs">10.3 Git의 내부 - Git Refs</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] Git flow, Github flow]]></title>
            <link>https://velog.io/@404_jjuya/Git-Git-flow-Github-flow</link>
            <guid>https://velog.io/@404_jjuya/Git-Git-flow-Github-flow</guid>
            <pubDate>Sat, 22 Feb 2020 08:31:30 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>원래는 Github flow를 통해 지속적인 CI/CD를 진행하였는데, 이는 앞으로 서비스에 반영될 기능들이 충분히 테스트 되지 못하고 배포되는 문제점을 해결하기 위해 flow를 어떻게 하면 좋을까를 고민하는 사수를 보며 구체화 되지 않은 개념들을 조금이나마 구체화하고, 이해하기 위해 정리해야겠다는 생각이 마구 들어서 개인적으로 정리하기 위한 글입니다.</p>
<p>잘못된 개념과 수정사항은 언제든 환영합니다!</p>
<h1 id="git-flow">Git Flow</h1>
<p><img src="https://images.velog.io/images/404_jjuya/post/73a21a62-08fd-4daa-bcec-b2680d0619d4/image.png" alt="git_flow"></p>
<h2 id="구조">구조</h2>
<ul>
<li>구조 : feature &gt; develop &gt; release &gt; hotfix &gt; master</li>
<li>develop과 master가 base가 된다.</li>
</ul>
<ol>
<li>master에서 develop을 분기한다.</li>
<li>기능 구현을 위해 develop에서 feature를 분기한다.</li>
<li>기능 구현이 완료되면 feature를 develop에 merge한다.</li>
<li>배포를 위해 develop에서 release를 분기한다.</li>
<li>테스트를 진행하면서 발생하는 버그 수정은 release 브랜치에 직접 반영한다.</li>
<li>테스트가 완료되면 release를 master와 develop에 merge 한다.</li>
</ol>
<h2 id="브랜치">브랜치</h2>
<h3 id="master">master</h3>
<ul>
<li>production을 위한 브랜치</li>
</ul>
<h3 id="develop">develop</h3>
<ul>
<li>base branch : master</li>
<li>개발을 위한 브랜치</li>
</ul>
<h3 id="feature">feature</h3>
<ul>
<li>base branch : develop</li>
<li>새로운 기능을 추가하기 위한 브랜치</li>
<li>origin에 반영되지 않으며 local repo에만 존재</li>
</ul>
<h3 id="release">release</h3>
<ul>
<li>base branch : develop</li>
<li>새로운 production 릴리즈를 위한 브랜치</li>
<li>현재까지의 기능들을 묶어서 develop에서 release를 따옴<ul>
<li>develop에는 다음번 릴리즈를 위한 기능들을 추가</li>
<li>release의 버그는 release에 직접 반영하고, 필요하다면 변경사항을 develop에도 반영해준다.</li>
</ul>
</li>
<li>릴리즈 준비가 완료되면 master에 merge 진행. 그 이후 develop에도 merge</li>
</ul>
<h3 id="hotfix">hotfix</h3>
<ul>
<li>base branch : master</li>
<li>production에서 발생한 버그들을 fix하는 브랜치</li>
<li>수정 후 master, develop에 반영 (release가 존재한다면 release에도 반영)</li>
</ul>
<h1 id="github-flow">Github flow</h1>
<p><img src="https://images.velog.io/images/404_jjuya/post/4e8d4ba6-04cd-440c-aa8f-c72a14ffef5e/image.png" alt="github flow"></p>
<h2 id="특징">특징</h2>
<ul>
<li>master의 role이 정확하다.<ul>
<li>master는 항상 최신 상태를 유지하며, stable 하다.</li>
<li>이는 master는 언제든 배포가 가능하다는 것을 의미한다.</li>
</ul>
</li>
<li>자동화의 개념이 추가</li>
<li>pull request를 통해 master에 반영(코드 리뷰 기능)</li>
<li>릴리즈의 개념이 없다.</li>
<li>hotfix와 가장 작은 기능을 구분하지 않는다.</li>
<li>원격 브랜치로 수시로 push</li>
</ul>
<h1 id="git-flow--github-flow">Git flow + Github flow</h1>
<h2 id="구조-1">구조</h2>
<ul>
<li>develop &gt; staging &gt; production</li>
<li>Github flow의 지속적인 merge와 Git flow의 테스트가 완료된 커밋들을 선별적으로 배포할 수 있는 구조</li>
<li>Github flow에 staging 브랜치를 추가하고 interactive rebase를 이용하여 develop에서 원하는 커밋들을 staging에 반영</li>
</ul>
<h2 id="브랜치-1">브랜치</h2>
<h3 id="develop-1">develop</h3>
<ul>
<li>개발을 위한 브랜치(기능 구현에 초점)<ul>
<li>pull request를 거친 커밋들이 자유롭게 올라간다.</li>
</ul>
</li>
<li>production의 배포와 관계가 없다.<ul>
<li>배포 주기에 구애받지 않는다.</li>
</ul>
</li>
</ul>
<h3 id="staging">staging</h3>
<ul>
<li>develop에서 배포가 확정된 커밋들이 존재</li>
<li>staging은 지속적으로 유지가 되는 브랜치<ul>
<li>배포 가능한 빌드를 staging 빌드로 테스트 가능</li>
</ul>
</li>
<li>실제 production 환경에서 테스트<ul>
<li>배포 기능과 버그 수정에 집중</li>
</ul>
</li>
</ul>
<h3 id="production">production</h3>
<ul>
<li>실제 배포가 되는 브랜치</li>
<li>staging에서 테스트 후 production으로 merge가 되면 배포가 완료</li>
</ul>
<h1 id="정리">정리</h1>
<p>이번 flow 정리를 통해 사수에게 미안함을 또 한번 느끼고, 이 참에 이런 정리의 시간을 가지게 해줘서 감사의 마음을 느낍니다.</p>
<p>Github flow에 develop(staging 겸용)을 추가하며, git으로 삽질을 했는데.. 이런 flow 보다도 upstream이나, rebase와 merge의 차이점에 대해 공부해야겠다는 생각도 듭니다.</p>
<hr>
<h4 id="참고">참고</h4>
<ul>
<li><a href="https://blog.ull.im/engineering/2019/06/25/git-workflow-for-ci-cd.html">지속적 통합/배포(CI/CD)를 위한 Git Workflow 전략</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>