<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>navill의 개발 블로그입니다.</title>
    <link>https://dev-navill.tistory.com/</link>
    <description>django를 이용한 백엔드 내용을 정리하기 위한 블로그입니다. pytho, Django REST Framework 및 백엔드 구성에 필요한 AWS, 여러 클라우드 플랫폼 등을 정리할 예정입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 14 Jun 2026 20:35:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>navill</managingEditor>
    <item>
      <title>Git - Branch</title>
      <link>https://dev-navill.tistory.com/32</link>
      <description>&lt;p&gt;그림이 너무 많아서 나중에 정리할 예정&lt;/p&gt;
&lt;p&gt;(일일이 복사해서 붙여넣기가 귀찮..)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.notion.so/afmadadans/Linux-Git-Branch-580e66b3da454f9381534751a74aa750&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.notion.so/afmadadans/Linux-Git-Branch-580e66b3da454f9381534751a74aa750&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1589194950530&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Linux - Git(Branch)&quot; data-og-description=&quot;Branch&quot; data-og-host=&quot;www.notion.so&quot; data-og-source-url=&quot;https://www.notion.so/afmadadans/Linux-Git-Branch-580e66b3da454f9381534751a74aa750&quot; data-og-url=&quot;https://www.notion.so/580e66b3da454f9381534751a74aa750&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NkukD/hyF0aO5F1N/dbiWlHKKNtZyjsNSaojHF0/img.png?width=2000&amp;amp;height=1088&amp;amp;face=0_0_2000_1088,https://scrap.kakaocdn.net/dn/z3j0U/hyF0ecRvj2/xf8QNLypN95e8UPNrQ0SXk/img.png?width=2000&amp;amp;height=1088&amp;amp;face=0_0_2000_1088&quot;&gt;&lt;a href=&quot;https://www.notion.so/afmadadans/Linux-Git-Branch-580e66b3da454f9381534751a74aa750&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.notion.so/afmadadans/Linux-Git-Branch-580e66b3da454f9381534751a74aa750&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NkukD/hyF0aO5F1N/dbiWlHKKNtZyjsNSaojHF0/img.png?width=2000&amp;amp;height=1088&amp;amp;face=0_0_2000_1088,https://scrap.kakaocdn.net/dn/z3j0U/hyF0ecRvj2/xf8QNLypN95e8UPNrQ0SXk/img.png?width=2000&amp;amp;height=1088&amp;amp;face=0_0_2000_1088');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Linux - Git(Branch)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Branch&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.notion.so&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Git</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/32</guid>
      <comments>https://dev-navill.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 11 May 2020 20:03:32 +0900</pubDate>
    </item>
    <item>
      <title>Git - Remote</title>
      <link>https://dev-navill.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;아래의 내용은 '&lt;/span&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2&quot;&gt;Pro-Git&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;'을 바탕으로 작성하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;Remote Repository&lt;/b&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;git clone 시 자동으로 origin(remote repo) 등록됨&lt;/p&gt;
&lt;pre class=&quot;shell&quot;&gt;&lt;code&gt;  # 단축이름 및 주소 출력
  $ git remote -v
  origin https://github.com/schacon/ticgit (fetch) 
  origin https://github.com/schacon/ticgit (push)

  # remote repo 등록
  $ git remote add [name] [url]

  # git fetch or pull
  $ git fetch [remote_name]
  $ git pull [remote_name]

  # git push 
  $ git push [remote_name] [branch_name]&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;git fetch vs git pull&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;fetch: 원격 저장소의 모든 데이터를 가져온다
&lt;ul&gt;
&lt;li&gt;로컬에 변경사항이 있을 경우 수동으로 변경하고 merge해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;pull: 원격 저장소의 모든 데이터를 가져온다.
&lt;ul&gt;
&lt;li&gt;로컬에 변경사항이 있을 경우 자동으로 merge&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;git push&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;만약, remote 저장소를 A와 내가 Clone &amp;rarr; A가 push &amp;rarr; 내가 push할 수 없음&lt;/p&gt;
&lt;p&gt;&amp;rarr; 다른 사람(A)이 push한 내용을 pull(또는 fetch 후 merge) 이후 push 할 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;원격 저장소 정보 확인&lt;/h3&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;# 등록된 원격 저장소 이름 출력
git remote show
# 해당 원격 저장소에 대한 상세 정보 출력
git remote show [remote_name]&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;원격 저장소 이름 변경 또는 삭제&lt;/h3&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;# 저장소 이름 변경
$ git remote rename [before_name] [after_name]
# 저장소 삭제
$ git remote remove [remote_name]&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tag&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# tag 확인
git tag

# lightweight tag 추가
$ git tag v1.4-lw

# annotated tag 추가
$ git tag -a v1.4 -m &quot;my version 1.4&quot;

# tag 및 커밋 정보 확인
$ git show v1.4
tag v1.4
Tagger: jihoon &amp;lt;jihoon1493@gmail.com&amp;gt;
Date:   Sat May 9 13:26:44 2020 +0000

my version 1.4

commit 6e6072736311d3bc85d1d871a0d646ea71a23cf2
Author: jihoon &amp;lt;jihoon1493@gmail.com&amp;gt;
Date:   Sat May 9 12:37:43 2020 +0000

    initial commit

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/forgotten_file b/forgotten_file
new file mode 100644
index 0000000..e69de29&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tag - 기존 히스토리에 tag 추가&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# 한줄로 log 출력
$ git log --pretty=oneline
6e60727... initial commit
9093b20... test6  # test6에 tag 추가
14d5146... test5

# annotated tag 생성(체크섬 일부로 생성할 수 있음)
$ git tag -a v1.0 9093b20 -m 'my version 1.0'

# tag 확인
$ git show v1.0
tag v1.0
Tagger: jihoon &amp;lt;jihoon1493@gmail.com&amp;gt;
Date:   Sat May 9 13:31:40 2020 +0000

my version 1.0

commit 9093b208fe279fc3a8c7bae6492c76dddf63855c
Author: jihoon &amp;lt;jihoon1493@gmail.com&amp;gt;
Date:   Fri May 8 15:25:25 2020 +0000

    test6

diff --git a/README b/README
deleted file mode 100644
index e69de29..0000000&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tag - Tag push&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tag는 자동으로 push되지 않기 때문에 별도로 push 해야함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;clone 또는 pull 시 tag도 포함됨&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;  # tag push
  $ git push origin [tag_name]

  # 모든 tag(remote에 push되지 않은) push
  $ git push origin --tags&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0u19v/btqD5JzgpeZ/E9IXzv4bx2KfrCjgYbd2Mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0u19v/btqD5JzgpeZ/E9IXzv4bx2KfrCjgYbd2Mk/img.png&quot; data-alt=&quot;v0.1 tag가 push 되었을 때 - github&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0u19v/btqD5JzgpeZ/E9IXzv4bx2KfrCjgYbd2Mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0u19v%2FbtqD5JzgpeZ%2FE9IXzv4bx2KfrCjgYbd2Mk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;v0.1 tag가 push 되었을 때 - github&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;Tag - Checkout&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tag가 가리키는 특정 커밋을 기반으로 브랜치를 생성하여 작업을 진행할 때 사용&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;  # tag checkout
  git checkout -b [branch_name] [tag_name]

  # tag가 가리키는 커밋 시점의 브랜치 생성
  $ git checkout -b branch_v0.1 v0.1
  Switched to a new branch 'branch_v0.1'
  # branch 확인
  $ git branch
  * branch_v0.1
    master
  # log 확인 - 해당 커밋(first)의 브랜치가 생성되어 체크아웃(branch_v0.1) 되었으므로
  # 한 개의 로그가 출력된다.
  git log --pretty=oneline
  cb40f891c... first&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&lt;b&gt;git Alias&lt;/b&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;git 명령어의 별칭을 만들어 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;  # 별칭 등록
  $ git config --global alias.co checkout 
  $ git config --global alias.br branch
  $ git config --global alias.ci commit
  $ git config --global alias.cim 'commit -m'
  $ git config --global alias.ciam 'commit -a -m'
  $ git config --global alias.st status
  $ git config --global alias.unstage 'reset HEAD --'
  $ git config --global alias.last 'log -1 HEAD'
  $ git config --global alias.graph 'log --oneline --decorate --graph --all'

  # 별칭 사용
  $ git co [branch_name]
  $ git br [branch_name]
  $ git ci -m 'test'
  $ git cim 'test' # 위와 동일
  # git commit -a -m 'message': git add [file] + git commit -m 'message'
  $ git ciam 'test'
  $ git st
  $ git unstage [file_name]
  $ git last  # 마지막 커밋 하나 출력
  $ git graph&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Issue &amp;amp; Pull Request&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.popit.kr/github%EB%A1%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-part1-%EC%9D%B4%EC%8A%88-%EB%B0%9C%EA%B8%89-%EB%B6%80%ED%84%B0-%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0%EA%B9%8C/&quot;&gt;GitHub로 프로젝트 관리하기 Part1 - 이슈 발급 부터 코드리뷰까지 | Popit&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Issue 작성&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# task
- [ ] task1  # 체크 박스 생성
- [ ] task2

# issue 닫기
# pull request에서 본문에 'resolved: #&amp;lt;number&amp;gt;' 사용 시
# issue가 자동으로 닫힌다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jh9XJ/btqD2u4wAkg/ruGxX3xdeXinAvfw3vNg2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jh9XJ/btqD2u4wAkg/ruGxX3xdeXinAvfw3vNg2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jh9XJ/btqD2u4wAkg/ruGxX3xdeXinAvfw3vNg2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJh9XJ%2FbtqD2u4wAkg%2FruGxX3xdeXinAvfw3vNg2K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;600&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjn6qA/btqD2GqbjTq/kCv4RjlQTaHv4zicFaOgQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjn6qA/btqD2GqbjTq/kCv4RjlQTaHv4zicFaOgQ0/img.png&quot; data-alt=&quot;task1을 체크할 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjn6qA/btqD2GqbjTq/kCv4RjlQTaHv4zicFaOgQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcjn6qA%2FbtqD2GqbjTq%2FkCv4RjlQTaHv4zicFaOgQ0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;600&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;task1을 체크할 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2&quot;&gt;https://git-scm.com/book/ko/v2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.popit.kr/github%EB%A1%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-part1-%EC%9D%B4%EC%8A%88-%EB%B0%9C%EA%B8%89-%EB%B6%80%ED%84%B0-%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0%EA%B9%8C/&quot;&gt;GitHub로 프로젝트 관리하기 Part1 - 이슈 발급 부터 코드리뷰까지 | Popit&lt;/a&gt;&lt;/p&gt;</description>
      <category>Git</category>
      <category>Alias</category>
      <category>fetch</category>
      <category>git</category>
      <category>Issue</category>
      <category>pull</category>
      <category>pull request</category>
      <category>Remote</category>
      <category>tag</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/31</guid>
      <comments>https://dev-navill.tistory.com/31#entry31comment</comments>
      <pubDate>Mon, 11 May 2020 19:48:38 +0900</pubDate>
    </item>
    <item>
      <title>Git - Local 기초</title>
      <link>https://dev-navill.tistory.com/30</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;Ubuntu(16.04 - Docker)에서 git 사용&lt;/h4&gt;
&lt;h3&gt;Docker volume 설정&lt;/h3&gt;
&lt;pre id=&quot;code_1589192411586&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker volume 생성
$ docker volume create --name dock_volume

# docker volume 확인
$ docker volume ls
DRIVER              VOLUME NAME
local               dock_volume

# docker container 생성
$ docker run -it --name ubuntu_test -v dock_volume:/root/ ubuntu:16.04
$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
32e7f7f30073        ubuntu:16.04        &quot;/bin/bash&quot;         About an hour ago   Up 57 minutes                           ubuntu_test
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;데이터를 저장할 docker volume(dock_volume)을 생성하고 이를 docker의 컨테이너(ubuntu_test)에 연결&lt;/li&gt;
&lt;li&gt;컨테이너에서 저장한 데이터는 volume에 저장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker 실행(사용할 컨테이너 이름은 ubuntu_test)&lt;/h3&gt;
&lt;pre id=&quot;code_1589192429014&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# container 확인
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                         PORTS               NAMES
10d7402a8968        ubuntu              &quot;/bin/bash&quot;         About an hour ago   Exited (0) About an hour ago                       cool_blackburn
32e7f7f30073        ubuntu:16.04        &quot;/bin/bash&quot;         About an hour ago   Exited (0) 5 minutes ago                           ubuntu_test

# container 종료
$ docker stop &amp;lt;container names 또는 conatiner ID&amp;gt;
# container 실행
$ docker start &amp;lt;container names 또는 conatiner ID&amp;gt;
# container 재실행
$ docker restart &amp;lt;container names 또는 conatiner ID&amp;gt;
# docker container에 접속
$ docker attach ubuntu_test
root@32e7f7f30073:/#

# ubuntu 설정
root@32e7f7f30073:/# apt-get update
root@32e7f7f30073:/# apt-get -y install vim &amp;amp;&amp;amp; git-all&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p&gt;아래의 내용은 '&lt;a href=&quot;https://git-scm.com/book/ko/v2&quot;&gt;Pro-Git&lt;/a&gt;'을 정리하였습니다.&lt;/p&gt;
&lt;h1&gt;Git 셋팅&lt;/h1&gt;
&lt;pre id=&quot;code_1589192483722&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 사용자 설정
$ git config --global user.name &quot;jihoon&quot;  # 이름 등록
$ git config --global user.email &quot;jihoon1493@gmail.com&quot;  # 메일 등록
$ git config --list  # 설정 리스트 확인
user.name=jihoon
user.email=jihoon1493@gmail.com
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
...
 


# home/user/my_repo
$ git init
$ ls -al
drwxr-xr-x 3 root root 4096 May  8 12:44 .
drwxr-xr-x 3 root root 4096 May  8 12:36 ..
drwxr-xr-x 8 root root 4096 May  8 12:44 .git

&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Git 개념&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;세 가지 상태
&lt;ol&gt;
&lt;li&gt;Committed: 데이터가 로컬 데이터베이스에 저장된 상태&lt;/li&gt;
&lt;li&gt;Staged: 수정된 파일을 곧 커밋할 것이라고 표시한 상태(add)&lt;/li&gt;
&lt;li&gt;Modified: 수정된 파일을 아직 커밋하지 않은 상태(not add)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CY3Eb/btqD2ciHGFR/qSLpeu5p9fookLA0K8kuZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CY3Eb/btqD2ciHGFR/qSLpeu5p9fookLA0K8kuZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CY3Eb/btqD2ciHGFR/qSLpeu5p9fookLA0K8kuZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCY3Eb%2FbtqD2ciHGFR%2FqSLpeu5p9fookLA0K8kuZ1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;세 가지 단계
&lt;ol&gt;
&lt;li&gt;Working tree: 특정 버전에 checkout된 상태(진행 작업이 해당 스냅샷에 위치 - .git에 있는 압축된 데이터베이스를 이용해 작업 트리를 생성)&lt;/li&gt;
&lt;li&gt;Staging area(.git): 커밋할 정보를 갖고 있는 파일&lt;/li&gt;
&lt;li&gt;Git directory: 프로젝트의 메타데이터 및 데이터베이스를 저장하는 곳(init으로 생성된 .git)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;작업 트리에서 파일 수정 &amp;rarr; staging area에 커밋할 스냅샷 생성(git add) &amp;rarr; .git에 영구적인 스냅샷 저장(git commit) &amp;rarr; 수정된 파일은 committed 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vv7yw/btqD5JlEneE/xFbjAe22TpV5PkNX0wgJr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vv7yw/btqD5JlEneE/xFbjAe22TpV5PkNX0wgJr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vv7yw/btqD5JlEneE/xFbjAe22TpV5PkNX0wgJr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvv7yw%2FbtqD5JlEneE%2FxFbjAe22TpV5PkNX0wgJr1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;working tree는 Tracked(Unmodified, Modified, Staged)와 Untracked로 나뉨
&lt;ul&gt;
&lt;li&gt;Tracked는 스냅샷에 올라와있는 상태를 의미(git clone 시 가져온 모든 데이터는 Tracked 상태)
&lt;ul&gt;
&lt;li&gt;Unmodified: 스냅샷에 올라와있는 최신 상태&lt;/li&gt;
&lt;li&gt;Modified: 파일을 수정한 상태&lt;/li&gt;
&lt;li&gt;Staged: git add 상태 &amp;rarr; commit 시 다시 Unmodified 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Untracked는 스냅샷에 올라와있지 않은 상태를 의미(파일은 생성되었지만 git add 되지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqhe1Q/btqD4VfAsJI/j6QF3k890pFcfzIo6gFhmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqhe1Q/btqD4VfAsJI/j6QF3k890pFcfzIo6gFhmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqhe1Q/btqD4VfAsJI/j6QF3k890pFcfzIo6gFhmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqhe1Q%2FbtqD4VfAsJI%2Fj6QF3k890pFcfzIo6gFhmK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changes to be committed: Commit이 준비된 상태(Staged)
&lt;ul&gt;
&lt;li&gt;modified: test.txt : test.txt는 수정이 일어났으며 이후 commit이 이뤄진 상태&lt;/li&gt;
&lt;li&gt;new file: test2.txt: test2.txt는 새로 생성된 후 stage(git add까지 실행된 상태)에 올라온 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Changes not staged for commit: Tracked 상태지만 stage에 올라와있지 않은 상태
&lt;ul&gt;
&lt;li&gt;modified: test2.txt: test2.txt를 수정한 상태이며 수정된 파일이 stage에 올라가지 않은 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Untracked files
&lt;ul&gt;
&lt;li&gt;README: 파일이 생성된 이후 한 번도 Stage에 올라오지 않은 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;git commit -a: Tracked 상태의 모든 파일을 한 번에 commit 단, Untracked 파일(README)는 commit되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;git 사용하기 - Local&lt;/h2&gt;
&lt;h3&gt;간단하게 git 상태 확인: git status -s&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4zcnn/btqD3cWGpUq/vVrRTyUChvz7MXTX2ODCB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4zcnn/btqD3cWGpUq/vVrRTyUChvz7MXTX2ODCB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4zcnn/btqD3cWGpUq/vVrRTyUChvz7MXTX2ODCB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4zcnn%2FbtqD3cWGpUq%2FvVrRTyUChvz7MXTX2ODCB1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;A: 새로 생성된 파일이 staged된 상태(새 파일을 git add)&lt;/p&gt;
&lt;p&gt;M: Tracked 상태의 파일이 수정되었을 때(수정된 파일 git add)&lt;/p&gt;
&lt;p&gt;??: Untracked&lt;/p&gt;
&lt;p&gt;AM: 왼쪽은 staging area의 상태, 오른쪽은 working tree에서의 상태를 의미&lt;/p&gt;
&lt;h3&gt;변경 내용 확인&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;git diff: 수정은 했지만 아직 staged되지 않은 파일을 비교한다. staging area: staged file(add된 test2.txt) vs working tree: modified file(수정은 되었지만 아직 add되지 않은 test2.txt))&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;git diff --staged(또는 --cached): staging area(add 된 파일) vs repository(committed 파일) 변경 부분 확인한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDjSny/btqD5IfZWk3/hwkHIgSnxKQq2w4A6qTBP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDjSny/btqD5IfZWk3/hwkHIgSnxKQq2w4A6qTBP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDjSny/btqD5IfZWk3/hwkHIgSnxKQq2w4A6qTBP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDjSny%2FbtqD5IfZWk3%2FhwkHIgSnxKQq2w4A6qTBP1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;800&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;파일 삭제&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;git rm: Tracked 상태(Staging Area)의 파일을 삭제(working tree의 파일(실제 파일)도 삭제됨) &amp;rarr; commit &amp;rarr; repo에 반영됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;git rm --cached &amp;lt;file name&amp;gt;: Staging area에 올라간 파일을 unstage 상태로 만들기 위해 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C542w/btqD5H2txh0/MBw2SXiBjxXFE2kEAzXtr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C542w/btqD5H2txh0/MBw2SXiBjxXFE2kEAzXtr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C542w/btqD5H2txh0/MBw2SXiBjxXFE2kEAzXtr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC542w%2FbtqD5H2txh0%2FMBw2SXiBjxXFE2kEAzXtr1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;750&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;README를 생성 &amp;rarr; Untracked files&lt;/li&gt;
&lt;li&gt;git add README &amp;rarr; changes to be committed(staged)&lt;/li&gt;
&lt;li&gt;git rm --cached README &amp;rarr; Untracked files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;파일이름 변경&lt;/h3&gt;
&lt;pre id=&quot;code_1589193247955&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 파일은 반드시 staged 상태여야한다.
$ git mv file_from file_to
# 아래와 동일(git mv는 아래의 단축 명령)
$ mv file_from file_to
$ git rm file_from
$ git add file_to&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;커밋 히스토리&lt;/h3&gt;
&lt;pre id=&quot;code_1589193257779&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 가장 최근 커밋이 제일 위에 출력된다.
$ git log&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wIJdG/btqD3HoC5yi/bzPuGzSMQ8CEf6JXPNKxIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wIJdG/btqD3HoC5yi/bzPuGzSMQ8CEf6JXPNKxIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wIJdG/btqD3HoC5yi/bzPuGzSMQ8CEf6JXPNKxIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwIJdG%2FbtqD3HoC5yi%2FbzPuGzSMQ8CEf6JXPNKxIk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;650&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;git log 옵션&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;-p: 각 커밋의 diff 출력&lt;/li&gt;
&lt;li&gt;-2: 최근 두 개의 결과 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rFhkY/btqD3HWpZhK/7iF4rh7x95OhHKEpUVFPx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rFhkY/btqD3HWpZhK/7iF4rh7x95OhHKEpUVFPx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rFhkY/btqD3HWpZhK/7iF4rh7x95OhHKEpUVFPx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrFhkY%2FbtqD3HWpZhK%2F7iF4rh7x95OhHKEpUVFPx0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;650&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;--stat: 각 커밋의 통계 정보 조회&lt;/li&gt;
&lt;li&gt;--pretty=[option]
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;online: 각 커밋을 한 라인으로 출력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;short, full, fuller: 정보의 양을 가감하여 출력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;format: 커스텀 포맷으로 출력&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;저자: 파일을 처음 stage에 올린 사람&lt;/li&gt;
&lt;li&gt;커미터: 마지막으로 파일을 수정하고 stage에 올린 사람&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;650&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rq97q/btqD3JfA9Uc/EBkSGo9vLD0o0uAxSq6gsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rq97q/btqD3JfA9Uc/EBkSGo9vLD0o0uAxSq6gsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rq97q/btqD3JfA9Uc/EBkSGo9vLD0o0uAxSq6gsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frq97q%2FbtqD3JfA9Uc%2FEBkSGo9vLD0o0uAxSq6gsk%2Fimg.png&quot; width=&quot;650&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1589193375276&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예시
$ git log --pretty=format:&quot;%h - %an, %ar : %s&quot;
ca82a6d - Scott Chacon, 6 years ago : changed the version number 
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test 
a11bef0 - Scott Chacon, 6 years ago : first commit&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1589193521009&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# --graph: 커밋 결과를 그래프로 출력
git log --pretty=format:&quot;%h %s&quot; --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
* 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit |\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
* 11d191e Merge branch 'defunkt' into local&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9kCen/btqD2GRd4ll/sianU4uRUDY0gL9xCyCIwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9kCen/btqD2GRd4ll/sianU4uRUDY0gL9xCyCIwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9kCen/btqD2GRd4ll/sianU4uRUDY0gL9xCyCIwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9kCen%2FbtqD2GRd4ll%2FsianU4uRUDY0gL9xCyCIwK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;750&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;git log - 조회 제한 조건&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;--since, --until: 지난 또는 이후 커밋을 조회&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;--s: 코드에서 추가되거나 제거된 내용 중 특정 텍스트가 포함되어있는지 검색&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1589193581255&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 커밋 내용 중 function_name이 포함된 커밋이 있는지 확인
$ git log --Sfunction_name&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;되돌리기(Undo)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;완료한 커밋을 수정해야할 때 사용&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;너무 일찍 커밋했거나 어떤 파일을 빼먹었을 때, 또는 커밋 메시지를 잘못 적었을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1589193612306&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 커밋하자마자 이 명령어를 사용할 경우 내용은 변경된 것이 없으며 
# 커밋 메시지만 변경할 수 있다.
$ git commit --amend

# 커밋을 완료했는데 파일 하나를 빠트린 경우
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vi4TG/btqD6lLoM30/37iFkkLSNd4npnDSWyYskK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vi4TG/btqD6lLoM30/37iFkkLSNd4npnDSWyYskK/img.png&quot; data-alt=&quot;commit 메시지는 유지되며(변경 가능) 빠트린 파일 하나가 추가된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vi4TG/btqD6lLoM30/37iFkkLSNd4npnDSWyYskK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvi4TG%2FbtqD6lLoM30%2F37iFkkLSNd4npnDSWyYskK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;commit 메시지는 유지되며(변경 가능) 빠트린 파일 하나가 추가된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;파일 상태를 unstage로 변경&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p&gt;실수로 git add . 를 사용 &amp;rarr; staged 된 파일을 다시 unstage상태로 만들고 싶다(add 취소)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;단순 git reset 워킹 디렉토리(트리)의 파일은 건드리지 않는다.&lt;/p&gt;
&lt;p&gt;(단, --hard 옵션을 사용할 경우 위험할 수 있다)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1589193654539&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git reset HEAD -- unstage_file&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;Modified 파일 되돌리기 - 수정한 내용이 정말 잘못되었을 때 사용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;파일을 마지막 커밋한 내용으로 되돌리고 싶을 때&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;파일을 처음 clone 햇을 때 처럼 워킹 디렉토리에 처음 checkout 한 내용으로 되돌리고 싶을 때&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;커밋하지 않고 잃어버린것은 되돌릴 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1589193715570&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 초기 상태
$ git status
  On branch master
  Changes to be committed:
(use &quot;git reset HEAD &amp;lt;file&amp;gt;...&quot; to unstage)
	renamed: README.md -&amp;gt; README 
	modified: CONTRIBUTING.md

# modified 해제 - CONTRIBUTING.md를 unmodified 상태로
$ git checkout -- CONTRIBUTING.md $ git status
On branch master
Changes to be committed:
	(use &quot;git reset HEAD &amp;lt;file&amp;gt;...&quot; to unstage) 
		renamed: README.md -&amp;gt; README&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고: &lt;a href=&quot;https://git-scm.com/book/ko/v2&quot;&gt;https://git-scm.com/book/ko/v2&lt;/a&gt;&lt;/p&gt;</description>
      <category>Git</category>
      <category>commit</category>
      <category>git</category>
      <category>Graph</category>
      <category>local</category>
      <category>LOG</category>
      <category>modified</category>
      <category>Staged</category>
      <category>tracked</category>
      <category>Undo</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/30</guid>
      <comments>https://dev-navill.tistory.com/30#entry30comment</comments>
      <pubDate>Mon, 11 May 2020 19:46:23 +0900</pubDate>
    </item>
    <item>
      <title>Docker - Basic</title>
      <link>https://dev-navill.tistory.com/29</link>
      <description>&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;Docker를 실제로 적용해볼일이 있어서 개념과 사용법을 간단하게 정리해보았다. 학원에서 실행하는 것만 따라해보면서 마냥 신기했던 기억이 있는데, 개념을 이해하고 실제로 적용해보니 정말 편리하고, 많은 기업들이 Docker를 사용하는 이유를 알 수 있었다. 앞으로도 도커를 적극적으로 활용하고 컨테이너를 시스템에 의해 처리할 수 있는 쿠버네티스에 대해도 공부해볼 생각이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker 란?&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;docker.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl4fWT/btqCYE8okFH/1b3CPR8cxPqrsbkSWvu4vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl4fWT/btqCYE8okFH/1b3CPR8cxPqrsbkSWvu4vk/img.png&quot; data-alt=&quot;컨테이너를 관리하는 플랫폼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl4fWT/btqCYE8okFH/1b3CPR8cxPqrsbkSWvu4vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl4fWT%2FbtqCYE8okFH%2F1b3CPR8cxPqrsbkSWvu4vk%2Fimg.png&quot; data-filename=&quot;docker.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;344&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컨테이너를 관리하는 플랫폼&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;기존의 Virtual Machine의 단점을 개선한 컨테이너 기반 가상 머신. docker는 크게 이미지(파일)와 컨테이너(프로세스)로 구성된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Image: &lt;/b&gt;어플리케이션(소스 코드)과 라이브러리(또는 프레임워크)를 담고 있는 하나의 파일. 구성하고자 하는 환경을 설치하기 위한 스크립트를 담고 있는 파일이라고 생각하자.&lt;b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Container:&lt;/b&gt; Image의 실행 상태(프로세스). 이미지를 이용해 실행 상태로 만든다.&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;-&amp;gt; 하나의 Image를 이용해 여러개의 Container를 생성할 수 있다.&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;-&amp;gt; Docker의 Container는 자체 컨테이너를 사용한다. (과거에는 &lt;a href=&quot;https://www.notion.so/afmadadans/Docker-449bd6ec011b4ef4b8facaa47f0e4646#dde0c532836841ebbf095089816f8809&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리눅스 컨테이너&lt;/a&gt;를 사용했다.)&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기존의 가상 머신(VM)과 차이점&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;기존의 가상머신은 호스트 OS위에 게스트 OS를 가상화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;호스트OS 위에 게스트OS를 올리고 그 위에 어플리케이션을 동작시킨다.&lt;br /&gt;&lt;/b&gt;&lt;b&gt;Host OS(Hypervisor) - [Guest OS1 - Application1], [Guest OS2 - Application2], ...&lt;br /&gt;&lt;/b&gt;&lt;b&gt;-&amp;gt; 무겁고 느려진다는 단점(실제 서비스하기 어려움)&lt;br /&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;VMware.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;957&quot; width=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buhLIb/btqC3qAENlv/rMjvNk6LcHhSUulUrPiEI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buhLIb/btqC3qAENlv/rMjvNk6LcHhSUulUrPiEI1/img.png&quot; data-alt=&quot;https://www.docker.com/resources/what-container (* Hypervisor: 호스트 컴퓨터에서 다수의 운영체제를 동시에 실행시키기 위한 논리적 플랫폼(가상화 레이어))&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buhLIb/btqC3qAENlv/rMjvNk6LcHhSUulUrPiEI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuhLIb%2FbtqC3qAENlv%2FrMjvNk6LcHhSUulUrPiEI1%2Fimg.png&quot; data-filename=&quot;VMware.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;957&quot; width=&quot;500&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.docker.com/resources/what-container (* Hypervisor: 호스트 컴퓨터에서 다수의 운영체제를 동시에 실행시키기 위한 논리적 플랫폼(가상화 레이어))&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Docker&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;호스트 OS위에 도커 엔진을 설치하고 여기에서 어플리케이션을 동작시킨다.&lt;br /&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;Host OS - Docker Engine - [Application1], [Application2], [Application3],... 구조로 실행 속도가 매우 빠르다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하나의 OS에 여러개의 컨테이너가 독립적으로 실행된다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;git처럼 이미지를 저장소(Dockerhub)에 저장하거나 불러와 쉽게 환경을 구축할 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;docker_container.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;957&quot; width=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqUTL/btqC3p2RxPc/rdmPttSZjQRAeXKHaxLEm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqUTL/btqC3p2RxPc/rdmPttSZjQRAeXKHaxLEm0/img.png&quot; data-alt=&quot;https://www.docker.com/resources/what-container&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqUTL/btqC3p2RxPc/rdmPttSZjQRAeXKHaxLEm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrqUTL%2FbtqC3p2RxPc%2FrdmPttSZjQRAeXKHaxLEm0%2Fimg.png&quot; data-filename=&quot;docker_container.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;957&quot; width=&quot;450&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.docker.com/resources/what-container&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;도커 설치 및 사용법&lt;/h2&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;기본 설정&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;도커 허브 계정 생성 -&amp;nbsp;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://hub.docker.com/&quot;&gt;Docker Hub&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;도커 데스크탑 설치- &lt;a href=&quot;https://hub.docker.com/?overlay=onboarding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Docker Desktop&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1585394483187&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 설치가 끝나고 도커 버전확인 
$ docker --version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도커 이미지 생성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1585394563796&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker 파일 생성 - 일반적으로 Dockerfile(또는 Dockerfile.base)로 생성하는듯
$ touch Dockerfile

# 스크립트 작성
$ vim Dockerfile

####################################################################
# From을 이용해 다른사람이 올려놓은 python3.7 이미지를 사용한다.
FROM python:3.7

RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \
        python3-setuptools \
        python3-pip \
        python3-dev \
        python3-venv \
        git \
        &amp;amp;&amp;amp; \
    apt-get clean &amp;amp;&amp;amp; \
    rm -rf /var/lib/apt/lists/*

CMD python -c &quot;print('hello world')&quot;
####################################################################&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;FROM:&lt;/b&gt; 누군가 올려놓은 기존 이미지를 사용&lt;/p&gt;
&lt;p&gt;&lt;b&gt;RUN:&lt;/b&gt; 쉘 커맨드에서 사용할 명령&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ENV: &lt;/b&gt;환경 변수를 설정할 때 사용&lt;/p&gt;
&lt;p&gt;&lt;b&gt;CMD:&lt;/b&gt; 도커 설정이 완료되고 실행될 명령(파이썬을 실행한 후 print('hello world') 명령 &amp;rarr; 화면에 hello world가 출력된다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;ADD: &lt;/span&gt;&lt;/b&gt;&lt;span&gt;로컬 파일을 이미지에 올릴 때 사용&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;ex) &lt;span&gt;ADD&lt;/span&gt; ./game_of_life/game_of_life.py /var/www/streami/game_of_life/game_of_life.py&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;= game_of_life.py를 해당 이미지로 생성된 컨테이너의 디렉토리(&lt;span style=&quot;color: #333333;&quot;&gt;/var/www/streami/game_of_life/&lt;/span&gt;)에 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도커 주요 명령&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1585394770393&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 빌드 이미지 -&amp;gt; 도커 파일(Dockerfile)을 docker image로 생성
$ docker build -t &amp;lt;your-tag&amp;gt; -f Dockerfile .
# ex) docker build -t hello-world -f Dockerfile .&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;-t:&lt;/b&gt; 태그를 생성할 때 사용&lt;/p&gt;
&lt;p&gt;&lt;b&gt;-f:&lt;/b&gt; Dockerfile의 디렉토리를 의미한다.(위 코드는 현재 폴더의 Dockerfile을 이용해 이미지를 생성함)&lt;/p&gt;
&lt;pre id=&quot;code_1585394918566&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 내 시스템에 생성한 이미지
$ docker images

# 내 시스템 모든 이미지 삭제
$ docker rm $(docker ps -a -q)  # 이후
$ docker rmi $(docker images -q)

# 현재 실행중인 컨테이너
$ docker ps -a

# 도커 실행
$ docker run -it &amp;lt;your-tag&amp;gt;
# ex) docker run -it hello-world
# 'hello world'가 출력된다.

# -d: 백그라운드에서 실행되어야할 경우 필요한 옵션
$ docker run -d -it &amp;lt;your-tag&amp;gt;

# 현재 실행중인 컨테이너 아이디 확인
$ docker ps - a
# 컨테이너 중지
$ docker stop &amp;lt;your-container-id&amp;gt;

# 도커 실행 후 bash shell 실행
docker run -it &amp;lt;your-tag&amp;gt; /bin/bash

# --rm: 컨테이너가 종료될 경우 해당 컨테이너 삭제 
docker run -it --rm &amp;lt;your-tag&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;도커 개념: &lt;/b&gt;&lt;a href=&quot;https://subicura.com/2017/01/19/docker-guide-for-beginners-1.html&quot;&gt;&lt;b&gt;https://subicura.com/2017/01/19/docker-guide-for-beginners-1.html&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;도커 기본 사용법: &lt;a href=&quot;http://pyrasis.com/Docker/Docker-HOWTO&quot;&gt;http://pyrasis.com/Docker/Docker-HOWTO&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;리눅스 컨테이너: &lt;a href=&quot;https://www.44bits.io/ko/keyword/linux-container&quot;&gt;https://www.44bits.io/ko/keyword/linux-container&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Server Side/Docker</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/29</guid>
      <comments>https://dev-navill.tistory.com/29#entry29comment</comments>
      <pubDate>Sat, 28 Mar 2020 20:31:03 +0900</pubDate>
    </item>
    <item>
      <title>도커 이용중 Python 한글 인식 오류(Docker(ubuntu 16.04))</title>
      <link>https://dev-navill.tistory.com/28</link>
      <description>&lt;p&gt;도커를 이용해 가상환경을 구성하고 파이썬을 실행할 경우 한글 입력이 되지 않을 수 있다.&lt;/p&gt;
&lt;p&gt;Dockerfile 생성시 아래의 내용을 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1585389486139&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Dockerfile에 아래 내용 추가
# 한글 출력을 위한 패키지
RUN apt-get install locales
RUN apt-get install -y \
    language-pack-ko &amp;amp;&amp;amp; \
    dpkg-reconfigure locales &amp;amp;&amp;amp; \
    locale-gen ko_KR.UTF-8 &amp;amp;&amp;amp; \
    /usr/sbin/update-locale LANG=ko_KR.UTF-8

# 한글을 출력하기 위해 환경변수 등록
ENV LANG=ko_KR.UTF-8
ENV LANGUAGE=ko_KR.UTF-8
ENV LC_ALL=ko_KR.UTF-8

# 파이썬에서 한글을 사용할 수 있도록 환경변수 등록
ENV PYTHONIOENCODING=UTF-8&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Server Side/Docker</category>
      <category>docker</category>
      <category>KO</category>
      <category>Python</category>
      <category>PYTHONIOENCODING</category>
      <category>systax error</category>
      <category>ubuntu16.04</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/28</guid>
      <comments>https://dev-navill.tistory.com/28#entry28comment</comments>
      <pubDate>Sat, 28 Mar 2020 18:58:57 +0900</pubDate>
    </item>
    <item>
      <title>개발 공부할 때 참고한 사이트(Python, Django, Back-end)</title>
      <link>https://dev-navill.tistory.com/27</link>
      <description>&lt;p&gt;개발자를 준비하면서 새롭게 느낀것은 코딩 스킬도 물론 중요하지만, 어떤 프로젝트에 문제가 생기거나 성능을 향상 시키기 위해 다양한 기술들이 필요하다는 것, 그리고 그 기술을 사용하기 위해서는 큰 그림(프레임워크부터 사용된 기술들이 어떻게 동작하는지??)을 이해 해야한다는 것이다. Python과 Django에 파묻혀서 도메인 지식과 전체적으로 프로젝트나 기술들이 어떻게 동작하는지에 대해 소홀했던 것 같다. 이러한 부분들을 공부하면서, 유용했던 사이트들을 정리해두는 것이 좋을 것 같아 글을 쓰게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Youtube&lt;/h2&gt;
&lt;p&gt;블로그 글보다 말과 영상으로 설명하는 유튜브가 짧은시간에 많은 것을 이해하는데 도움이 되었다. 처음에는 호기심에 봤었는데 지금은 개념을 익히기 위해 유튜브 영상을 주로 참고한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;코드없는 프로그래밍 - &lt;a href=&quot;https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg/videos&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Youtube&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제목처럼 코드보다는 개념을 그림과 말로 설명하기 때문에 빠르게 이해하는데 도움이 된다.&lt;/li&gt;
&lt;li&gt;메인은 C++인것 같지만 이외에도 웹 프로그래밍에 사용되는 개념과 기술들도 올라와 있다.&lt;/li&gt;
&lt;li&gt;프로그래밍에 대한 개념을 기반으로 설명하기 때문에 어렵지 않게 이해할 수 있다.&lt;/li&gt;
&lt;li&gt;영상이 길지 않고 짧고 간략하게 설명되어있어 틈틈히 보기 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;노마더 코더 - &lt;a href=&quot;https://www.youtube.com/channel/UCUpJs89fSBXNolQGOYKn0YQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Youtube&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 개발자에게 도움이 되는 트렌드와 기술에 대한 개념을 설명한다.&lt;/li&gt;
&lt;li&gt;주로 그림과 자막을 통해 누구나 쉽게 이해할 수 있는 컨텐츠가 올라온다.&lt;/li&gt;
&lt;li&gt;특정 언어나 스킬에 대해 설명하고 있어 나같은 주니어 개발자가 새로운 기술을 접할 때 한 번씩 영상을 참고하면 도움이 될 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;포프TV - &lt;a href=&quot;https://www.youtube.com/user/KimPopeTV&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Youtube&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;꽤 오랫동안 개발자 관련 컨텐츠를 올려왔다.&lt;/li&gt;
&lt;li&gt;좋은 개발자가 되기 위해 갖추어야할 자세나 필요한 역량 등 여러 주제를 다룬다.&lt;/li&gt;
&lt;li&gt;개인적으로 개발자로서의 마음가짐에 대해 많은 생각을 하게되는 영상들이 많았다(많은 도움을 받음).&lt;/li&gt;
&lt;li&gt;편집 없이 20~40분 동안 디테일하게 설명해주기 때문에 작정하고 봐야한다.&lt;br /&gt;&lt;s&gt;불면증 치료에 도움됨...&lt;/s&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SQL전문가 정미나 - &lt;a href=&quot;https://www.youtube.com/channel/UCoc7x15NFZ97UbwfdmMZxlw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Youtube&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스(주로 oracle기반)에 대한 컨텐츠를 다룬다.&lt;/li&gt;
&lt;li&gt;주로 오라클에 대한 내용이지만 공통적으로 사용되는 SQL에 대한 설명도 많다.&lt;/li&gt;
&lt;li&gt;기초 쿼리문이나 인덱스 개념등을 이해할 때 참고하였다.&lt;/li&gt;
&lt;li&gt;데이터베이스 공부하면서 길지 않은 영상이기 때문에 틈틈히 보고있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;freeCodeCamp - &lt;a href=&quot;https://www.youtube.com/channel/UC8butISFwT-Wl7EV0hUK0BQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Youtube&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 코딩 스킬을 익히거나 기술의 튜토리얼을 경험해 보고 싶을 때 참고할 수 있는 사이트&lt;/li&gt;
&lt;li&gt;길지 않는 코드를 직접 따라해보면서 기초 스킬을 익히는데 도움이 된다.&lt;/li&gt;
&lt;li&gt;다루는 언어와 기술들이 다양하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Coding for Entreprenures - &lt;a href=&quot;https://www.youtube.com/channel/UCWEHue8kksIaktO8KTTN_zg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Youtube&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://www.codingforentrepreneurs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Membership Site&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주로 Django, Angular, React, Javascript, 및 서버 구현(AWS, Docker 등)에 필요한 여러 기술들에 대해 학습할 수 있다.&lt;/li&gt;
&lt;li&gt;간단한 샘플 코드부터 Project까지 단계별로 따라해보면서 배울 수 있다.&lt;/li&gt;
&lt;li&gt;강의 영상 뿐만 아니라 Posts에서 초기 셋팅같은 간단한 튜토리얼도 제공한다.&lt;/li&gt;
&lt;li&gt;강의 난이도에 따라 등급이 나뉘어있지만, 개인적으로 초급과 중급의 갭이 조금 크다고 생각한다.&lt;/li&gt;
&lt;li&gt;Django 및 AWS 관련 스킬을 익히는데 많은 도움이 되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Blog&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://wayhome25.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;초보몽키&lt;/b&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기초 Django 함수를 익힐 때 공식 문서 만큼 많이 보게 된 블로그라고 생각한다.&lt;/li&gt;
&lt;li&gt;나뿐만 아니라 Python &amp;amp; Django을 공부하면서 참고하지 않은 사람은 많지 않을것 같다.&lt;/li&gt;
&lt;li&gt;누구나 쉽게 이해할 수 있게 꼼꼼하고 자세하게 내용이 정리되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://winterj.me/&quot;&gt;&lt;b&gt;정겨울 블로그&lt;/b&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;초보몽키 블로그처럼 Python &amp;amp; Django 관련 내용을 다룬다.&lt;/li&gt;
&lt;li&gt;기초적인 부분보다 좀 더 심화된 내용(실무적인?)이 담겨있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Community&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://dev.to/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;Dev&lt;/b&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django 관련 boilerplate에 대해 검색하던 중 접하게된 커뮤니티&lt;/li&gt;
&lt;li&gt;게시글의 퀄리티나 내용이 다른 커뮤니티 보다(stackoverflow외에 다른 커뮤니티를 잘 모름) 좋은 것 같다.&lt;/li&gt;
&lt;li&gt;포프TV에서 기술이나 동향에 대해 설명할 때 한 번씩 나온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이 외에 유용한 사이트&lt;/h2&gt;
&lt;h3&gt;&lt;b&gt;&lt;a href=&quot;https://awesome-python.com/&quot;&gt;Awesome Python&lt;/a&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;Awesome 시리즈 파이썬 버전&lt;/li&gt;
&lt;li&gt;파이썬 라이브러리, 소스, 프레임워크 등 매우 많은 자료들이 정리되어 있다.&lt;/li&gt;
&lt;li&gt;카테고리별로 정리되어있어 프로젝트를 진행하면서 파이썬 오픈소스나 라이브러리를 사용하고자 할 때 참고하기 좋은 사이트&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://repl.it/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Repl.it&lt;/a&gt; - 웹 브라우저용 IDE&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저에서 파이썬뿐만 아니라 다양한 언어를 실행할 수 있는 IDE(태블릿에서도 가능)&lt;/li&gt;
&lt;li&gt;프레임워크 또한 지원하기 때문에 Django 실행 가능&lt;/li&gt;
&lt;li&gt;간단한 함수를 테스트하기 위한 코드를 작성할 때 주로 사용한다.&lt;/li&gt;
&lt;li&gt;개발 환경이 구축되지 않은 PC에서 편리하게 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://subscription.packtpub.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Packt&lt;/a&gt; - e-Book&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구독형식으로 운영되는 e-book 사이트&lt;/li&gt;
&lt;li&gt;주로 개발 관련 서적이 올라온다.&lt;/li&gt;
&lt;li&gt;책 뿐만 아니라 강의를 포함한 서비스도 있으며, 구독하면 pdf를 다운받을 수 있어 오프라인에서도 편리하게 읽을 수 있다.&lt;/li&gt;
&lt;li&gt;django 관련 책이 국내에 많지 않아서(지금은 모르겠음) 공부할 때 참고했었다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;django 관련 책은 주로 프로젝트를 기반으로 설명되어 있었음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://github.com/navill/Interview_Question_for_Beginner#technical-interview-guidelines-for-beginners&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Technical Interview Guidelines for beginners&lt;/a&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기술 면접에 필요한 내용이 정리되어있다.&lt;/li&gt;
&lt;li&gt;CS, 알고리즘 및 자료구조 등 면접에서 나올법한 질문들과 답변이 요약되어 있다.&lt;/li&gt;
&lt;li&gt;기술면접을 위해서가 아니라 개발자로서 꼭 알아야할 내용들이 많아서 읽어보는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TIL &amp;amp; Todo List</category>
      <category>Django</category>
      <category>Interview</category>
      <category>Python</category>
      <category>Reference</category>
      <category>유용한 사이트</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/27</guid>
      <comments>https://dev-navill.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 13 Mar 2020 19:20:44 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - INDEX 정리</title>
      <link>https://dev-navill.tistory.com/26</link>
      <description>&lt;p&gt;MySQL의 INDEX 관련 공부를 하던 중 &lt;a href=&quot;https://www.youtube.com/watch?v=KLZWDOK8kZM&amp;amp;list=PLVsNizTWUw7HhYtI-4GGmlJ5yxNdwNI_X&quot;&gt;'이것이 MySQL이다'&lt;/a&gt; 라는 책에 대한 강의가 유튜브에 올라온것을 보고 참고하였다. DB에서 데이터를 가져오는데 많은 시간이 걸리기 때문에 백엔드에서 데이터베이스 튜닝은 매우 중요하다. 그중에서 많은 비중을 차지하는 INDEX에 대해 정리하였다.&lt;/p&gt;
&lt;pre class=&quot;verilog&quot;&gt;&lt;code&gt;# unique not null -&amp;gt; clustered index로 사용됨
create table tbl2(
    a int unique not null,
    b int unique,
    c int unique
);

create table tbl3(
    a int primary key,
    b int unique not null,
    c int unique not null
);

show index from tbl3;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;table1.png&quot; data-origin-width=&quot;2880&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekSLeD/btqCjdBxnuO/LKCF1esShuzhUKeKCokRE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekSLeD/btqCjdBxnuO/LKCF1esShuzhUKeKCokRE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekSLeD/btqCjdBxnuO/LKCF1esShuzhUKeKCokRE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekSLeD%2FbtqCjdBxnuO%2FLKCF1esShuzhUKeKCokRE0%2Fimg.png&quot; data-filename=&quot;table1.png&quot; data-origin-width=&quot;2880&quot; data-origin-height=&quot;196&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Key_name&lt;/b&gt;: &lt;b&gt;PRIMARY_KEY(Clustered index)&lt;/b&gt;는 'PRIMARY'로, &lt;b&gt;UNIQUE(Secondary Index)&lt;/b&gt;는 컬럼 이름으로 지정&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PRIMARY_KEY 없이 보조 인덱스로만 구성된 테이블을 생성할 수 있음&lt;/li&gt;
&lt;li&gt;책의 색인과 같이 테이블에 있는 데이터를 빠르게 찾을 수 있도록 함&lt;/li&gt;
&lt;li&gt;한 페이지의 크기는 16k Bytes&lt;/li&gt;
&lt;li&gt;전체 데이터에서 중복되는 데이터가 적을 때 사용하는 것이 좋다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;남성 또는 여성 두 개로만 분류되는 컬럼은 인덱스로 사용하기 부적합&lt;br /&gt;&amp;rarr; cardinality(중복도)가 높을 수록 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;INDEX 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 쿼리문을 이용해 데이터를 빠르게 가져올 수 있음&lt;/li&gt;
&lt;li&gt;전체 데이터 중 10~15% 내의 데이터를 가져오고자 할 때
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 이상의 데이터는 Full Scan이 더 좋은 성능을 보일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자주 사용 되는 특정 컬럼(여러 컬럼을 조합하기도 함)&lt;/li&gt;
&lt;li&gt;조건절(WHERE)에 자주 등장하는 컬럼&lt;/li&gt;
&lt;li&gt;ORDER BY 절에 자주 사용되는 컬럼
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;INDEX는 정렬되어 저장되기 때문에 빠르게 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;INDEX 단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장 공간을 차지 - DB의 10%정도를 index에서 사용&lt;/li&gt;
&lt;li&gt;처음 인덱스를 생성하는데 시간이 소요됨&lt;/li&gt;
&lt;li&gt;INSERT, SELECT, DELETE 시 많은 시간이 소요됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4&gt;&lt;b&gt;INDEX 종류(MySQL 기준)&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Clustered Index(영어 사전)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터가 정렬된(PK 또는 UNIQUE NOT NULL 컬럼을 기준으로 오름차순) 상태(유지)로 저장&lt;/li&gt;
&lt;li&gt;테이블 당 한 개만 생성&lt;/li&gt;
&lt;li&gt;제약조건 PRIMARY KEY에 의해 자동으로 생성&lt;/li&gt;
&lt;li&gt;제약조건 UNIQUE NOT NULL에 의해 자동으로 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단, 한 테이블에 PRIMARY KEY와 UNIQUE NOT NULL이 함께 있을 경우, PRIMARY KEY를 Clustered Index로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 검색 순서&lt;/b&gt;&lt;br /&gt;루트 페이지 &amp;rarr; 리프 페이지(= 데이터 페이지)&lt;br /&gt;&lt;b&gt;= 리프 페이지&lt;/b&gt;가 곧 &lt;b&gt;데이터 페이지&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;FNT - '푸니타', KAI - '카아이'를 추가로 입력할 경우&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리프 페이지가 모두 차있을 경우 페이지 분할이 일어난다 &amp;rarr; DB부하가 걸린다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;cluster.png&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;722&quot; width=&quot;590&quot; height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BIkaX/btqChG5mVDt/1KR4y2Ke5YUpIcleqWPJwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BIkaX/btqChG5mVDt/1KR4y2Ke5YUpIcleqWPJwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BIkaX/btqChG5mVDt/1KR4y2Ke5YUpIcleqWPJwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBIkaX%2FbtqChG5mVDt%2F1KR4y2Ke5YUpIcleqWPJwK%2Fimg.png&quot; data-filename=&quot;cluster.png&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;722&quot; width=&quot;590&quot; height=&quot;241&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Secondary Index(Non Clustered Index - 책의 '찾아보기')&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블에 여러개의 보조 인덱스를 생성할 수 있음&lt;/li&gt;
&lt;li&gt;제약조건 UNIQUE에 의해 자동으로 생성&lt;/li&gt;
&lt;li&gt;별도의 인덱스가 생성되지만, 원본 데이터는 변경되지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 검색 순서&lt;/b&gt;&lt;br /&gt;루트 페이지 &amp;rarr; 리프 페이지 &amp;rarr; 데이터 페이지(Heap page)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Heap: 정렬 기준 없이 구성된 테이블(입력된 순서대로 저장)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리프 페이지&lt;/b&gt;는 &lt;b&gt;데이터 페이지&lt;/b&gt;를 가리키는 주소값(RID)을 가지고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;FNT - '푸니타', KAI - '카아이'를 추가로 입력할 경우&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리프 페이지가 모두 차있더라도 페이지 분할이 일어나지 않는다.&lt;br /&gt;&amp;rArr; INSERT, DELETE, UPDATE 성능이 Clustered Index보다 낫다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;secondary.png&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;1340&quot; width=&quot;589&quot; height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qczfn/btqChGjWtMP/RvhHHkOamhtOAJmAFbNfe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qczfn/btqChGjWtMP/RvhHHkOamhtOAJmAFbNfe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qczfn/btqChGjWtMP/RvhHHkOamhtOAJmAFbNfe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqczfn%2FbtqChGjWtMP%2FRvhHHkOamhtOAJmAFbNfe1%2Fimg.png&quot; data-filename=&quot;secondary.png&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;1340&quot; width=&quot;589&quot; height=&quot;562&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;SELECT 구문에는 Clustered Index가, INSERT, UPDATE, DELETE 구문에는 Secondary Index가 더 좋은 성능을 발휘한다.&lt;/b&gt;&lt;/p&gt;
&lt;h4&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4&gt;&lt;b&gt;한 테이블에 Clustered 및 Secondary Index가 혼합되어있을 경우&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;# mixed index
create database if not exists testDB;
use testdb;
create table mixedTbl(
    userID char(8) not null,
    name varchar(10) not null,
    addr char(2)
);

insert into mixedTbl value('LSG', '이승기', '서울');
insert into mixedTbl value('KBS', '김범수', '경남');
insert into mixedTbl value('KKH', '김경호', '전남');
insert into mixedTbl value('JYP', '조용필', '경기');
insert into mixedTbl value('SSK', '성시경', '서울');
insert into mixedTbl value('LJB', '임재범', '서울');
insert into mixedTbl value('YJS', '윤종신', '경남');
insert into mixedTbl value('EJW', '은지원', '경북');
insert into mixedTbl value('JKW', '조관우', '경기');
insert into mixedTbl value('BBK', '바비킴', '서울');&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;lsk table.png&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QBPKL/btqCdikv5zg/sK3bVwl4BDDKlNA2diSyaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QBPKL/btqCdikv5zg/sK3bVwl4BDDKlNA2diSyaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QBPKL/btqCdikv5zg/sK3bVwl4BDDKlNA2diSyaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQBPKL%2FbtqCdikv5zg%2FsK3bVwl4BDDKlNA2diSyaK%2Fimg.png&quot; data-filename=&quot;lsk table.png&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;514&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# userID를 PK로 지정 -&amp;gt; 클러스터 인덱스 생성(루트 페이지 + 리프 페이지(데이터 페이지))
alter table mixedTbl
    add constraint PK_mixedTbl_userID
        primary key (userID);

# name을 UNIQUE로 지정 -&amp;gt; 보조 인덱스 생성
alter table mixedTbl
    add constraint UK_mixedTbl_name
        unique (name);

show index from mixedTbl;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;table_pkandunique.png&quot; data-origin-width=&quot;2762&quot; data-origin-height=&quot;142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8AGWF/btqCdh6ZVFP/1XAer3a1mk0acA9sPIrzh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8AGWF/btqCdh6ZVFP/1XAer3a1mk0acA9sPIrzh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8AGWF/btqCdh6ZVFP/1XAer3a1mk0acA9sPIrzh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8AGWF%2FbtqCdh6ZVFP%2F1XAer3a1mk0acA9sPIrzh0%2Fimg.png&quot; data-filename=&quot;table_pkandunique.png&quot; data-origin-width=&quot;2762&quot; data-origin-height=&quot;142&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;mix_table1.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uIQeI/btqCcVXkOyA/D1ENEkhBavzunzgKWO9Ns1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uIQeI/btqCcVXkOyA/D1ENEkhBavzunzgKWO9Ns1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uIQeI/btqCcVXkOyA/D1ENEkhBavzunzgKWO9Ns1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuIQeI%2FbtqCcVXkOyA%2FD1ENEkhBavzunzgKWO9Ns1%2Fimg.png&quot; data-filename=&quot;mix_table1.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;798&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;mix_table2.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIQFvs/btqCgSZbWTs/SHshIsuNknOKNUjEUBlsA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIQFvs/btqCgSZbWTs/SHshIsuNknOKNUjEUBlsA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIQFvs/btqCgSZbWTs/SHshIsuNknOKNUjEUBlsA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIQFvs%2FbtqCgSZbWTs%2FSHshIsuNknOKNUjEUBlsA1%2Fimg.png&quot; data-filename=&quot;mix_table2.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;486&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만일 혼합 인덱스에서 보조 인덱스가 데이터 페이지의 주소를 가리키지 않고 PK를 가리킬 경우, 데이터 페이지에 새로운 값이 입력되면 보조 인덱스가 가리키고 있는 주소값이 모두 변경되어야 함&lt;br /&gt;&lt;b&gt;&amp;rarr; INSERT, DELETE, UPDATE의 성능이 매우 떨어지게 됨&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;인덱스 생성 &amp;amp; 변경 + 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;# Syntax 
# 생성
CREATE INDEX index_name ON table_name (column_list)
# 기본적으로 create index를 이용할 경우 보조 인덱스가 생성된다.

# 삭제
DROP INDEX index_name on table_name

# 반드시 보조 인덱스 삭제 후 클러스터 인덱스 삭제
# 1.secondary index 삭제
drop index UK_mixedTbl_name on mixedTbl;
drop index idx_mixedTbl on mixedTbl;
drop index idx_mixedTbl_name_addr on mixedTbl;

# 2.clustered index 삭제(pk)
alter table mixedTbl
    drop primary key;

# 3. 만일 다른 테이블에서 클러스터 인덱스(pk)를 참조하고 있을 경우 에러 발생
# -&amp;gt; pk를 참조하는 테이블(referTbl)의 제약조건 이름 확인
select table_name, constraint_name
from information_schema.REFERENTIAL_CONSTRAINTS
where CONSTRAINT_SCHEMA = 'sqlDB';
# -&amp;gt; 참조하는 테이블의 외래키와 클러스터 인덱스의 외래키 제거
alter table referTbl
    drop foreign key refertbl_ibfk_1;
alter table mixedTbl
    drop foreign key;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 키로 설정된 클러스터 인덱스의 이름은 'PRIMARY'
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클러스터형 인덱스를 삭제할 경우 'DROP INDEX PRIMARY ON table_name&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ALTER TABLE을 이용해 기본 키를 제거할 경우 클러스터형 인덱스가 제거 됨&lt;/li&gt;
&lt;li&gt;혼합 인덱스에서 인덱스를 전부 제거하고자 할 경우, 보조 인덱스부터 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;b&gt;INDEX를 이용한 테스트 -&lt;a href=&quot;https://www.notion.so/afmadadans/INDEX-TEST-b2045ef5042a49828f79c8fa37704b6f&quot;&gt;Notion&lt;/a&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;REFERENCES&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=aTOFBD52060&amp;amp;t=2s&quot;&gt;[이것이 MySQL이다] 09. MySQL 인덱스(1)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=qW9X4w_SnT4&amp;amp;t=633s&quot;&gt;[이것이 MySQL이다] 09. MySQL 인덱스(2)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=pOaLJVnGJgM&quot;&gt;[이것이 MySQL이다] 09. MySQL 인덱스(3)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8wp8EVRYIlA&quot;&gt;[이것이 MySQL이다] 09. MySQL 인덱스(4)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jojoldu.tistory.com/243&quot;&gt;[mysql] 인덱스 정리 및 팁&lt;/a&gt;&lt;/p&gt;</description>
      <category>Database/MySQL</category>
      <category>clustered index</category>
      <category>create index</category>
      <category>DROP INDEX</category>
      <category>index</category>
      <category>mixed index</category>
      <category>Secondary Index</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/26</guid>
      <comments>https://dev-navill.tistory.com/26#entry26comment</comments>
      <pubDate>Tue, 25 Feb 2020 17:28:03 +0900</pubDate>
    </item>
    <item>
      <title>Python + Selenium을 이용한 웹 자동화</title>
      <link>https://dev-navill.tistory.com/25</link>
      <description>&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;Chrome 브라우저와 Selenium을 이용해 간단한 웹 사이트를 동작시켜보는 예제를 정리해보았다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;&lt;b&gt;Selenium with Python&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;공식 문서&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://selenium-python.readthedocs.io/index.html&quot;&gt;Selenium with Python - Selenium Python Bindings 2 documentation&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1582616546804&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# selenium 설치
pip install selenium&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;&lt;b&gt;크롬 설정&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p&gt;현재 사용중인 크롬 버전확인&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;chrome.png&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;686&quot; width=&quot;780&quot; height=&quot;389&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpovui/btqCindiQUc/O1obUf3ztrkm6YcPqFAPoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpovui/btqCindiQUc/O1obUf3ztrkm6YcPqFAPoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpovui/btqCindiQUc/O1obUf3ztrkm6YcPqFAPoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcpovui%2FbtqCindiQUc%2FO1obUf3ztrkm6YcPqFAPoK%2Fimg.png&quot; data-filename=&quot;chrome.png&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;686&quot; width=&quot;780&quot; height=&quot;389&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p&gt;크롬 드라이버 다운로드(Chrome:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://chromedriver.storage.googleapis.com/index.html?path=80.0.3987.16/&quot;&gt;https://chromedriver.storage.googleapis.com/index.html?path=80.0.3987.16/&lt;/a&gt;)&lt;/p&gt;
&lt;img style=&quot;text-align: center; caret-color: transparent; letter-spacing: 0px;&quot; src=&quot;https://k.kakaocdn.net/dn/bHWmws/btqCeu5MH7u/k3kUWJkzqKiVjnhUy7EtO1/img.png&quot; data-image-src=&quot;https://k.kakaocdn.net/dn/bHWmws/btqCeu5MH7u/k3kUWJkzqKiVjnhUy7EtO1/img.png&quot; data-filename=&quot;chrome_driver.png&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;492&quot; /&gt;
&lt;p&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;크롬 드라이버 다운로드(Chrome:&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://chromedriver.storage.googleapis.com/index.html?path=80.0.3987.16/&quot;&gt;https://chromedriver.storage.googleapis.com/index.html?path=80.0.3987.16/&lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;chrome_directory.png&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RIg5X/btqChG5kCiF/vzLg3igyNodse9ej0ANTaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RIg5X/btqChG5kCiF/vzLg3igyNodse9ej0ANTaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RIg5X/btqChG5kCiF/vzLg3igyNodse9ej0ANTaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRIg5X%2FbtqChG5kCiF%2FvzLg3igyNodse9ej0ANTaK%2Fimg.png&quot; data-filename=&quot;chrome_directory.png&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;206&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;&lt;b&gt;자동 검색어 입력&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p&gt;자동으로 구글에 접속하여 'selenium'을 검색하는 기능 구현&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1582618292325&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

# Chrome
driver = webdriver.Chrome('/Users/jh/Desktop/Python/selenium/Chrome_Driver/chromedriver')
# Firefox
# driver = webdriver.Firefox()
# Intenet explorer
# driver = webdriver.Ie()

wait = WebDriverWait(driver, timeout=1)
driver.get(&quot;https://google.com/&quot;)
mid_result = wait.until(presence_of_element_located((By.CLASS_NAME, &quot;gNO89b&quot;)))
driver.find_element_by_name(&quot;q&quot;).send_keys(&quot;selenium&quot; + Keys.RETURN)

first_result = wait.until(presence_of_element_located((By.CLASS_NAME, &quot;rc&quot;)))
print(first_result.get_attribute(&quot;textContent&quot;))
&quot;&quot;&quot;
HowToMakeWebCrawler-With-Selenium저장된&amp;nbsp;페이지2017. 2. 26. - Selenium은 주로 웹앱을 
테스트하는데 이용하는 프레임워크다. webdriver 라는 API를 통해 운영체제에 설치된 Chrome등의 브라우저를 
제어하게&amp;nbsp;...selenium 설치selenium javaselenium 버튼 클릭크롬 드라이버 64비트selenium xpath 
사용법selenium headless함께 검색한 항목...
&quot;&quot;&quot;

# 검색 완료 후 크롬 창 최대화
driver.maximize_window()
# 새로고침
driver.refresh()
# 3초 후 드라이버 종료(크롬창 닫힘)
time.sleep(3)
print('Test Completed')
driver.quit()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;driver = webdriver.Chrome('/Users/jh/Desktop/Python/selenium/Chrome_Driver/chromedriver')&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;rarr; site-packages에 driver 파일을 위치 시킬 경우 경로를 지정하지 않아도 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;chrome_result.png&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;1190&quot; width=&quot;725&quot; height=&quot;689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kNlp4/btqCgnLSobu/rBzYyBQyE8TOw0vgc9t4NK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kNlp4/btqCgnLSobu/rBzYyBQyE8TOw0vgc9t4NK/img.png&quot; data-alt=&quot;driver.find_element_by_name(&amp;amp;quot;q&amp;amp;quot;).send_keys(&amp;amp;quot;selenium&amp;amp;quot; + Keys.RETURN): input tag에 name=&amp;amp;#39;q&amp;amp;#39; 속성을 이용해 검색 창에 필요한 속성값을 가져오고 입력한 값을 전달한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kNlp4/btqCgnLSobu/rBzYyBQyE8TOw0vgc9t4NK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkNlp4%2FbtqCgnLSobu%2FrBzYyBQyE8TOw0vgc9t4NK%2Fimg.png&quot; data-filename=&quot;chrome_result.png&quot; data-origin-width=&quot;1252&quot; data-origin-height=&quot;1190&quot; width=&quot;725&quot; height=&quot;689&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;driver.find_element_by_name(&quot;q&quot;).send_keys(&quot;selenium&quot; + Keys.RETURN): input tag에 name='q' 속성을 이용해 검색 창에 필요한 속성값을 가져오고 입력한 값을 전달한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;chrome_result2.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1276&quot; width=&quot;728&quot; height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be34P5/btqCgRMJrpQ/bDKOY9d28kx0BiZXRKOvE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be34P5/btqCgRMJrpQ/bDKOY9d28kx0BiZXRKOvE0/img.png&quot; data-alt=&quot;만일 입력에 Enter Key가 유효하지 않을 경우, &amp;amp;#39;driver.find_element_by_name(&amp;amp;#39;btnK&amp;amp;#39;).click())&amp;amp;#39; 를 이용해 직접 클릭 동작을 실행시킬 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be34P5/btqCgRMJrpQ/bDKOY9d28kx0BiZXRKOvE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe34P5%2FbtqCgRMJrpQ%2FbDKOY9d28kx0BiZXRKOvE0%2Fimg.png&quot; data-filename=&quot;chrome_result2.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1276&quot; width=&quot;728&quot; height=&quot;721&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;만일 입력에 Enter Key가 유효하지 않을 경우, 'driver.find_element_by_name('btnK').click())' 를 이용해 직접 클릭 동작을 실행시킬 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;UnitTest&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p&gt;HtmlTestRunner를 이용해 테스트 결과를 html 파일로 변환할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;rarr; 깔끔하게 결과를 확인할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HtmlTestRunner 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1582617310929&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# HtmlTestRunner 설치
$ pip install html-testRunner
# unittest의 결과를 저장할 디렉토리
$ mkdir reports&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;자동 검색 코드 - keyword로 'python'과 'selenium'을 입력&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&amp;nbsp; - python을 검색하는 코드에서 find_element_by_name에 알 수 없는 값 'q1'을 입력하여 의도적으로 오류 출력&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1582617435926&quot; class=&quot;python&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import unittest
import HtmlTestRunner


class GoogleSearch(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome('/Users/jh/Desktop/Python/selenium/Chrome_Driver/chromedriver')
        cls.driver.implicitly_wait(10)
        cls.driver.maximize_window()

    def test_search_selenium(self):
        self.driver.get('https://google.com')
        self.driver.find_element_by_name('q').send_keys('selenium' + Keys.RETURN)

    def test_search_python(self):
        self.driver.get('https://google.com')
        # 알 수 없는 element
        self.driver.find_element_by_name('q1').send_keys('python' + Keys.RETURN)

    @classmethod
    def tearDownClass(cls):
        cls.driver.close()
        cls.driver.quit()
        print('complete')


if __name__ == '__main__':
    # 저장할 주소 지정
    unittest.main(testRunner=HtmlTestRunner.HTMLTestRunner(output='/Users/jh/Desktop/Python/selenium/report'))&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Result&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;result1.png&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;482&quot; width=&quot;617&quot; height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pdeZ5/btqCgReVj4t/enwBoTAvC4lFlqXEtfere1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pdeZ5/btqCgReVj4t/enwBoTAvC4lFlqXEtfere1/img.png&quot; data-alt=&quot;console에 위와 같은 결과를 출력: 2개의 테스트 중 1개 에러&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pdeZ5/btqCgReVj4t/enwBoTAvC4lFlqXEtfere1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpdeZ5%2FbtqCgReVj4t%2FenwBoTAvC4lFlqXEtfere1%2Fimg.png&quot; data-filename=&quot;result1.png&quot; data-origin-width=&quot;1302&quot; data-origin-height=&quot;482&quot; width=&quot;617&quot; height=&quot;228&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;console에 위와 같은 결과를 출력: 2개의 테스트 중 1개 에러&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;result2.png&quot; data-origin-width=&quot;1938&quot; data-origin-height=&quot;1092&quot; width=&quot;697&quot; height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C7ySM/btqCinj3PCs/AHUK7Y1beeHwYMMjFuvtD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C7ySM/btqCinj3PCs/AHUK7Y1beeHwYMMjFuvtD1/img.png&quot; data-alt=&quot;report 디렉토리에 저장된 html파일을 열면 위와 같은 결과를 출력한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C7ySM/btqCinj3PCs/AHUK7Y1beeHwYMMjFuvtD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC7ySM%2FbtqCinj3PCs%2FAHUK7Y1beeHwYMMjFuvtD1%2Fimg.png&quot; data-filename=&quot;result2.png&quot; data-origin-width=&quot;1938&quot; data-origin-height=&quot;1092&quot; width=&quot;697&quot; height=&quot;393&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;report 디렉토리에 저장된 html파일을 열면 위와 같은 결과를 출력한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Selenium을 이용한 자동 로그인&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p&gt;사이트에 접속해 로그인, 로그아웃을 자동으로 실행하는 테스트 코드&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드는 웹 페이지가 모두 구성될 때(실행하려는 요소가 페이지에 확인될 때) 실행 시킬 수 있으므로, 예외처리나 wait 구문에 신경써야 한다.&lt;/li&gt;
&lt;li&gt;공식 문서에서 제공하는 Expected Conditions(&lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions&quot;&gt;link&lt;/a&gt;)를 이용해 필요한 요소가 브라우저에 완전히 출력될 때 실행시켜야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1582617733944&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import unittest
import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class LoginTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome('/Users/jh/Desktop/Python/selenium/Chrome_Driver/chromedriver')
        # cls.driver.implicitly_wait(5)
        cls.driver.maximize_window()

    def test_login(self):
    	# default: 10초
        wait = WebDriverWait(self.driver, 10)
        self.driver.get('https://opensource-demo.orangehrmlive.com/')
        self.driver.find_element_by_id('txtUsername').send_keys('Admin')
        self.driver.find_element_by_id('txtPassword').send_keys('admin123' + Keys.RETURN)
        try:
            # welcom list가 뜰때까지 대기
            wait.until(EC.element_to_be_clickable((By.ID, &quot;welcome&quot;)))
            self.driver.find_element_by_id('welcome').click()
            # link text('Logout')이 뜰때까지 대기
            wait.until(EC.presence_of_element_located((By.LINK_TEXT, &quot;Logout&quot;)))
            self.driver.find_element_by_link_text('Logout').click()
 	# 10초가 넘을 경우 exception
        except Exception as e:
            print(f'raised time out exception: {e}')
        finally:
            time.sleep(2)

    @classmethod
    def tearDownClass(cls):
        cls.driver.close()
        cls.driver.quit()
        print('Test Completed')


if __name__ == '__main__':
    unittest.main()&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드를 작성할 때 웹 페이지가 모두 구성될 때(실행하려는 요소가 페이지에 확인될 때) 실행 시킬 수 있으므로, 예외처리나 wait 구문에 신경써야 한다.&lt;/li&gt;
&lt;li&gt;공식 문서에서 제공하는 Expected Conditions(&lt;a href=&quot;https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions&quot;&gt;link&lt;/a&gt;)를 이용해 필요한 요소가 브라우저에 완전히 출력될 때 실행시켜야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;되도록 time.sleep(), WebDriverWait().until(), driver.implicity_wait()구문을 이용해 클라이언트(브라우저)에서 렌더링이 완료될 시간을 지정해주는 것이 좋다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/Selenium</category>
      <category>automatic</category>
      <category>Python</category>
      <category>selenium</category>
      <category>WebDriver</category>
      <category>자동화</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/25</guid>
      <comments>https://dev-navill.tistory.com/25#entry25comment</comments>
      <pubDate>Tue, 25 Feb 2020 17:08:00 +0900</pubDate>
    </item>
    <item>
      <title>ONLY_FULL_GROUP_BY + query 실행 순서</title>
      <link>https://dev-navill.tistory.com/24</link>
      <description>&lt;p&gt;MySQL tutorial를 공부하던 중 발생한 에러에 대해 정리하는 것이 좋을 것 같아 블로그를 쓰게되었다.&lt;/p&gt;
&lt;p&gt;아래의 코드는 MySQL 공식 사이트의 alias(별칭)와 관련된 튜토리얼에 나오는 코드이다(&lt;a href=&quot;https://www.mysqltutorial.org/mysql-alias/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식사이트&lt;/a&gt;).&lt;/p&gt;
&lt;pre id=&quot;code_1581000171448&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT orderNumber as 'Order no.', SUM(priceEach * quantityOrdered) as total
FROM orderdetails
GROUP BY 'Order no.'
HAVING total &amp;gt; 60000;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;쿼리를 그냥 실행했더니 아래와 같은 에러가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1581000215956&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[42000][1055] Expression 
1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'classicmodels.orderdetails.orderNumber' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;공식 튜토리얼에 나온 코드를 그대로 따라했는데 왜 에러가 발생했는지 알 수 없어서 에러 메시지에 나와있는 sql_mode=only_full_group_by에 대해 검색해보았다. ONLY_FULL_GROUP_BY는 아래와 같이 설명하고 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&quot;Reject queries for which the select list, HAVING condition, or ORDER BY list refer to nonaggregated columns that are neither named in the GROUP BY clause nor are functionally dependent on (uniquely determined by) GROUP BY columns.&quot;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;의미가 어려워 내 마음대로 해석해보니 'select list, HAVING condition, ORDER BY list가 (GROUP BY에 등록되지 않은 구문이나 GROUP BY 열을 기능적으로 의존하는)비집계 열을 참조하는 것을 거부한다' 라고 되어있는듯 하다. 정확한 의미를 이해하진 못했지만 select 구문에서 사용된 이름이 group by에서 사용되어야 하는 것 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저 문장을 이해하기 위해 코드를 이용해 테스트해 보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1581000512124&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# default sql_mode
set sql_mode ='';

SELECT orderNumber as 'Order no.', SUM(priceEach * quantityOrdered) as total
FROM orderdetails
GROUP BY orderNumber
HAVING total &amp;gt; 60000;  # 정상 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;411&quot; height=&quot;121&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXkwab/btqBNMFiinn/PyPkFgEUaewomGUC50Jv1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXkwab/btqBNMFiinn/PyPkFgEUaewomGUC50Jv1K/img.png&quot; data-alt=&quot;의도한 값이 출력 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXkwab/btqBNMFiinn/PyPkFgEUaewomGUC50Jv1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXkwab%2FbtqBNMFiinn%2FPyPkFgEUaewomGUC50Jv1K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;411&quot; height=&quot;121&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;의도한 값이 출력 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1581000552697&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT orderNumber as 'Order no.', SUM(priceEach * quantityOrdered) as total
FROM orderdetails
GROUP BY 'Order no.'
HAVING total &amp;gt; 60000;  # 의도하지 않은 결과 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;440&quot; height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhGtA/btqBNkWrZvI/pwC6rDhR2ro12luxQlCsK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhGtA/btqBNkWrZvI/pwC6rDhR2ro12luxQlCsK1/img.png&quot; data-alt=&quot;의도하지 않은 값이 출력 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhGtA/btqBNkWrZvI/pwC6rDhR2ro12luxQlCsK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhGtA%2FbtqBNkWrZvI%2FpwC6rDhR2ro12luxQlCsK1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;440&quot; height=&quot;69&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;의도하지 않은 값이 출력 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1581000624088&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# only_full_group_by
set sql_mode ='ONLY_FULL_GROUP_BY';

SELECT orderNumber as 'Order no.', SUM(priceEach * quantityOrdered) as total
FROM orderdetails
GROUP BY orderNumber
HAVING total &amp;gt; 60000;  # 정상 출력

SELECT orderNumber as 'Order no.', SUM(priceEach * quantityOrdered) as total
FROM orderdetails
GROUP BY 'Order no.'  
HAVING total &amp;gt; 60000;  # 에러 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 문제에 대해 좀 더 검색하던 중 MySQL이 아래와 같은 순서로 실행됨을 알 수 있었다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;FROM&lt;/li&gt;
&lt;li&gt;WHERE&lt;/li&gt;
&lt;li&gt;GROUP BY&lt;/li&gt;
&lt;li&gt;HAVING&lt;/li&gt;
&lt;li&gt;SELECT&lt;/li&gt;
&lt;li&gt;ORDER BY&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 순서대로 실행된다면 에러가 발생하거나 의도한 값이 출력하지 않은 이유를 알 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;위 예제에서 &lt;b&gt;GROUP BY&lt;/b&gt;가 실행될 때, &lt;b&gt;SELECT&lt;/b&gt;에 정의된 별칭은 사용될 수 없다.&lt;/p&gt;
&lt;p&gt;&amp;rarr; &lt;b&gt;SELECT&lt;/b&gt;에 정의되어 있는 별칭 &lt;b&gt;'Order no.'&lt;/b&gt;는 &lt;b&gt;GROUP BY&lt;/b&gt;가 실행될 시점에는 알 수 없는 값이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;'의도하지 않은 결과 출력' 코드는 &lt;b&gt;GROUP BY&lt;/b&gt;를 생략해도 동일한 값을 출력한다.&lt;/p&gt;
&lt;p&gt;&amp;rarr; &lt;b&gt;GROUP BY&lt;/b&gt;가 동작하지 않는다.&lt;/p&gt;
&lt;b&gt;select orderNumber, sum(priceEach*quantityOrdered) total from orderdetails;&lt;/b&gt; 이것과 동일한 결과를 나타낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;추가로 공식 사이트에서 아래와 같은 사항을 주의하라고 말한다.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&quot;Notice that you cannot use a column alias in the WHERE clause. The reason is that when MySQL evaluates the WHERE clause, the values of columns specified in the SELECT clause is not be evaluated yet.&quot;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 역시 &lt;b&gt;SELECT&lt;/b&gt; 구문이 평가되기 전에 &lt;b&gt;WHERE&lt;/b&gt; 구문이 먼저 실행되기 때문에 &lt;b&gt;WHERE&lt;/b&gt; 구문에서 &lt;b&gt;SELECT&lt;/b&gt;에서 정의된&amp;nbsp;별칭을 사용할 수 없다는 것을 말한다.(&lt;b&gt;GROUP BY&lt;/b&gt;와 동일한 이유)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ONLY_FULL_GROUP_BY&lt;/b&gt;는 &lt;b&gt;GROUP BY&lt;/b&gt; 사용 시 잘못된 쿼리 사용을 미리 막을 수 있기 때문에 데이터베이스를 생성할 때 미리 설정하는 것이 좋다고 생각한다.&lt;/p&gt;
&lt;p&gt;&amp;rarr; 만일 쿼리의 실행 결과를 모르는 상태에서 두 번째 코드를 실행 시켰다면 정상적으로 동작한다고 생각할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;References&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jason-heo.github.io/&quot;&gt;Jason Heo's Blog&lt;/a&gt;: &lt;a href=&quot;http://jason-heo.github.io/mysql/2014/03/05/char13-mysql-group-by-usage.html&quot;&gt;MySQL GROUP BY 사용 시 주의점&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_only_full_group_by&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 5.1.11 Server SQL Modes&lt;/a&gt;&lt;/p&gt;</description>
      <category>Database/MySQL</category>
      <category>Alias</category>
      <category>group by</category>
      <category>ONLY_FULL_GROUP_BY</category>
      <category>query 실행 순서</category>
      <category>sql_mod</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/24</guid>
      <comments>https://dev-navill.tistory.com/24#entry24comment</comments>
      <pubDate>Thu, 6 Feb 2020 23:56:27 +0900</pubDate>
    </item>
    <item>
      <title>Javascript에서 django url template tag 사용</title>
      <link>https://dev-navill.tistory.com/23</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Javascript&lt;/b&gt;에서 django의 &lt;b&gt;url template tag&lt;/b&gt;를 사용하는 방법&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;javascript에서도 일반 html에서 사용하는 template tag처럼 코드를 작성해보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1580799062677&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var url = &quot;{% url 'products:detail' pk=obj.id %}&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아래와 같은 에러 발생&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xqOiH/btqBGe4fI9Z/pV8AV5gbyVw1hSrskWzjT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xqOiH/btqBGe4fI9Z/pV8AV5gbyVw1hSrskWzjT0/img.png&quot; data-alt=&quot;pk를 찾지 못한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xqOiH/btqBGe4fI9Z/pV8AV5gbyVw1hSrskWzjT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxqOiH%2FbtqBGe4fI9Z%2FpV8AV5gbyVw1hSrskWzjT0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pk를 찾지 못한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;구글링을 해보니 javascript의 &lt;b&gt;replace&lt;/b&gt; 메서드를 이용해 pk에 들어갈 값을 간접적으로 할당해주어야 정상적으로 인식이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1580799225938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var url = &quot;{% url 'products:detail' pk='product_id' %}&quot;.replace('product_id', obj.id);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;530&quot; height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CADSr/btqBIHRMEP0/tBATna5AFHygfCXqtHtCD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CADSr/btqBIHRMEP0/tBATna5AFHygfCXqtHtCD1/img.png&quot; data-alt=&quot;infoWindow에 url tag가 정상적으로 적용되었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CADSr/btqBIHRMEP0/tBATna5AFHygfCXqtHtCD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCADSr%2FbtqBIHRMEP0%2FtBATna5AFHygfCXqtHtCD1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;530&quot; height=&quot;376&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;infoWindow에 url tag가 정상적으로 적용되었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Django</category>
      <author>navill</author>
      <guid isPermaLink="true">https://dev-navill.tistory.com/23</guid>
      <comments>https://dev-navill.tistory.com/23#entry23comment</comments>
      <pubDate>Tue, 4 Feb 2020 15:55:49 +0900</pubDate>
    </item>
  </channel>
</rss>