1.원격 저장소 사용
1)기본 작업
=>clone: 원격 저장소 복제
=>remote: 원격 저장소를 추가하고 조회하고 삭제하기
=>push: 원격 저장소에 저장
=>fetch: 원격 저장소의 내용을 가져오기만 하기
=>pull: 원격 저장소의 내용을 가져와서 합치기
2)clone
=>원격 저장소의 내용을 그대로 가져오는 작업
git clone 원격저장소URL
git clone 원격저장소URL 특정경로
=>특정 경로를 설정할 때는 문자열 형태로 설정해야 하고 빈 디렉토리를 설정
=>현재 로그인 되어 있는 계정의 repository(fork 된 repository)를 clone 하면 자동으로 연결
=>git clone https://github.com/itggangpae/python_basic.git
제 계정이라서 git remote -v 로 원격 저장소를 확인해보면 연결된 것을 확인
3)git remote
=>원격 저장소를 추가하고 조회하고 삭제할 수 있는 명령
=>원격 저장소를 생성
Git Hub 페이지에서 Repositorys 를 선택하고 New 를 누르면 됩니다.
저장소를 생성할 때 README.md 파일이나 .gitignore를 생성하면 저장소와 처음 연결할 때 비어있지 않기 때문에 clone을 해서 연결을 해야 합니다.
Repository가 비어있으면 연결을 바로 할 수 있고 바로 push 가 가능합니다.
=>비어있는 repository를 생성 - samplerepository
https URL은 https://gitgub.com/이름/레포지토리이름.git
SSH URL은 git@github.com:이름/레포지토리이름.git
=>로컬 저장소를 생성 - 빈 디렉토리를 만들고 git init 을 수행하면 됩니다.
=>원격 저장소 와 로컬 저장소를 연결
git remote add <원격 저장소 이름> <원격 저장소 URL>
저장소 이름은 정해진 규칙은 없지만 일반적으로 original의 약자인 origin 을 많이 사용
현재 프로젝트에 존재하는 저장소 이름 확인: git remote
저장소 이름 과 연결된 URL을 확인: git remote -v 또는 git remote --verbose
=>로컬 저장소 와 원격 저장소를 연결
> git remote add origin https://github.com/itggangpae/samplerepository
> git remote
origin
> git remote -v
origin https://github.com/itggangpae/samplerepository (fetch)
origin https://github.com/itggangpae/samplerepository (push)
=>원격 저장소 이름 변경
git remote rename <기존 이름> <새로운 이름>
> git remote rename origin changed
> git remote
> git remote -v
=>원격 저장소 연결 해제
git remote remove <저장소이름>
> git remote remove changed
> git remote
> git remote -v
4)git push
=>로컬 저장소의 내용을 원격 저장소에 업로드하는 작업
=>기본적으로 local repository 에 존재하는 내용만 업데이트 합니다.
git add <업로드하고자하는 파일> 명령을 수행해서 업로드하고자 하는 파일을 stage 영역에 등록
git commit -m <메시지 제목> 명령을 수행해서 stage 영역에 있는 파일들 중 변화가 발생한 것만 local repository에서 업데이트를 수행합니다.
git push 명령으로 업로드
=>로컬 저장소에 a.txt 파일을 만들고 A 라는 문자을 작성
=>스테이지 영역에 등록: git add a.txt
=>로컬 저장소에 업데이트를 반영: git commit -m "A add in a.txt"
=>원격 저장소 연결
git remote add origin git@github.com:itggangpae/samplerepository.git
=>기본 브랜치 이름이 main 이 아니라면 main 브랜치로 체크아웃하거나 현재 브랜치 이름을 main으로 변경
git branch -M main: 현재 브랜치의 이름을 main 으로 변경
git checkout -b main: main 브랜치를 만들고 체크아웃
이 작업들이 필요한 이유는 git 에서는 기본 브랜치 이름이 master 이고 git hub에서는 기본 브랜치 이름이 main 이라서 브랜치 이름이 틀려서 연결이 안될 수 있기 때문에 local git의 branch를 변경합니다.
설치를 하고 난 후 기본 브랜치 이름을 main 으로 변경해도 됩니다.
=>푸시: git push <원격저장소이름> <브랜치이름>
매번 원격 저장소 이름 과 브랜치 이름을 생략하고자 하면 처음 push를 할 때 -u 옵션을 사용하면 됩니다.
git push -u origin main 을 수행하면 다음부터는 git push 만 해도 git push origin main 으로 간주하고 git pull 만 해도 git pull origin main으로 간주
=>업로드가 종료되면 git hub 사이트에서 확인이 가능
=>a.txt 파일에 B를 추가하고 이를 push
브랜치에서 작업 - a.txt 파일에 B를 추가
git status: 현재 git 상태를 확인할 수 있는데 작업 디렉토리의 변경 내용 과 stage 영역의 변경 내용을 확인할 수 있습니다.
변경한 내용을 stage 영역으로 이동: git add a.txt
- git add <변경한 파일 경로> 또는 .
- .을 이용하는 경우 python 이나 node 기반의 프로젝트의 경우는 불필요한 파일들은 .gitignore를 이용해서 업로드 되지 않도록 해주어야 합니다.
- node에서는 node_modules 디렉토리가 되고 python에서는 가상환경이 되며 자바에서는 clean을 해서 불필요한 빌드에 관련된 파일을 제거
stage 영역의 내용을 local repository에 반영: git commit -m "B add in a.txt"
commit 내용을 확인: git log --patch
원격 저장소에 업로드: git push
원격 저장소에서 a.txt 파일의 내용 확인
5)fetch
=>원격 저장소의 변경 사항을 로컬 저장소에 병합하지 않고 가져만 오는 방법
=>현재 commit 상태를 확인: git log --oneline
2개의 commit 이 존재
=>원격 저장소에서 a.txt 파일에 C를 추가하고 commit changes를 눌러서 commit을 발생
=>현재 상태
로컬 저장소는 커밋 2개
원격 저장소는 커밋 3개
=>로컬 저장소에서 git fetch 명령을 수행
=>현재 상태 확인: git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
하나의 commit 이 적용되지 않은 상태라는 메시지
패치는 원격 저장소의 변경 내용을 가져오기는 하지만 현재 프로젝트에 반영하지는 않음
=>브랜치를 비교: git diff main origin/main
커밋이나 브랜치를 비교하는 명령은 git diff <커밋이나 브랜치 이름> <커밋이나 브랜치 이름>
=>origin/main 으로 체크 아웃: git checkout origin/main
fetch를 한 경우에는 직접 branch 이름을 입력하지 않아도 됩니다.
이 경우에는 FETCH_HEAD로도 이동이 가능
FETCH_HEAD는 최근에 패치한 브랜치의 최신 커밋을 가리키기 때문
=>origin/main 브랜치의 commit 확인: git log --oneline
=>main 브랜치에 origin/main 의 변경 내용을 반영
git checkout main
git merge origin/main
=>main 브랜치의 커밋 상태 확인: git log --oneline
origin/main 과 동일하게 3개의 커밋을 가진 상태
6)pull
=>원격 저장소를 가져와서 합치는 작업
=>풀은 패치 와 병합을 동시에 하는 방식
=>원격 저장소에서 a.txt 파일에 D를 추가하고 commit changes 를 수행
=>로컬 저장소에서 현재 상태 확인: git log --oneline
커밋이 3개인 상태
=>git pull 수행
=>로컬 저장소에서 현재 상태 확인: git log --oneline
커밋이 4개인 상태
7)주의할 점
=>동일한 브랜치에서 각각 수정을 수정을 하게되면 push가 안될 수 있음
push는 최근의 상태에 변경 내역을 추가하는 것입니다.
push하는 상태가 최근의 상태에서 작업한 것이 아니면 push가 되지 않습니다.
동일한 파일을 작업한 경우가 아니라면 pull 을 다시 받아서 변경을 수행해야 할 수 도 있습니다.
원격 저장소에서 수정한 내용이 로컬에서 수정한 파일과 다른 경우에는 git pull 만 하고 다시 푸시하면 됩니다.
=>서로 다른 브랜치에서 동일한 내용을 다르게 수정하게 되면 merge가 동작을 안할 수 있습니다.
이 경우는 한쪽의 변경 내역을 포기해야 하는 경우가 발생
=>git hub에서 코드를 공유하면서 작업을 할 때는 동시에 동일한 파일을 수정하는 부분에 주의해야 합니다.
2.Pull Request
=>협업 작업을 위해서 git hub에서 제공하는 기능
=>하나의 프로젝트를 가지고 작업을 하는 경우에 reviwer 나 작업자를 등록을 해서 메시지를 전송한 후 그 답장을 보고 다음 작업을 수행할 수 있도록 해주는 기능
1)repository를 생성할 때 reviewer를 등록시켜서 push를 할 때 pr을 선택적으로 보내서 리뷰를 받는 방법이 가능
=>원격 Repository를 생성
=>Repository를 선택하고 Settings 탭을 선택하고 Collaborators 메뉴를 누른 후 Add People 메뉴를 눌러서 이름이나 email을 입력해서 리뷰어를 초대
리뷰어에게 초대 이메일이 전송되므로 각 리뷰어는 이메일을 확인해서 초대에 응할지 여부를 판단
=>로컬 저장소를 생성하고 원격 저장소 와 연결해서 push
mkdir collaboration
cd collaboration
git init
sample.txt 파일을 생성하고 내용을 추가
git add .
git commit -m "message"
git remote add origin https://github.com/itggangpae/collaboration
git push origin main
=>프로젝트를 수정하고 새로운 브랜치로 push
git branch feature/body-change
git checkout feature/body-change
git add .
git commit -m "Change Body"
git push origin feature/body-change
=>원격 저장소 확인
Compare & pull request 라는 메뉴가 생성
메뉴를 누르고 리뷰어를 선택해서 등록
Create Pull Request를 눌러서 pr을 전송
2)repository를 fork에서 작업을 수행한 후 원래의 repository 관리자에게 pr을 보내서 merge 를 하도록 하는 방법
=>자신의 계정에서 git hub에 로그인 한 후 fork 할 프로젝트의 url로 이동
=>fork 버튼을 눌러서 새로운 fork를 만들면 내 계정에서의 repository 이름을 입력하는 창이 나오게 되고 이름을 입력하면 프로젝트가 복제됩니다.
=>fork를 했을 때 주의할 점은 원본에서 commit 작업이 일어나면 내용이 서로 다르기 때문에 sync 를 맞추고 작업을 수행하는 것이 좋습니다.
=>fork 한 프로젝트 clone
=>새로운 브랜치를 하나 생성하고 checkout
git branch itggangpae
git checkout itggangpae
=>내용을 수정하고 수정한 내용을 새로운 브랜치를 이용해서 push
git add .
git commit -m "내용 수정"
git push origin itggangpae
=>원격 저장소 확인
compare & pull request 버튼이 보입니다.
버튼을 누르고 메시지를 작성한 후 create pull request를 눌러서 pr 을 전송
=>원본을 가진 계정에서 pull request를 확인해서 merge 수행 여부를 결정
각 작업을 수행할 때 마다 상대방 계정으로 이메일이 전송됩니다.
3.Git Hub Action
1)개요
=>새로운 기능을 개발하고 프로젝트 코드를 테스트하고 빌드하고 원격 저장소에 반영하고 배포하는 일련의 과정이 완료되어야 실제 작업이 마무리 됨
=>이러한 일련의 작업을 자동화하는 다양한 도구가 있는데 그 중의 하나가 git hub action
=>소프트웨어 개발에 필요한 작업 주기를 자동화하는 도구
=>액션은 이벤트 기반으로 특정 이벤트가 발생했을 때 특정 명령 혹은 명령 집합을 자동으로 실행시킬 수 있슴
=>이벤트로는 repository에 발생하는 Pull, Request, Push 와 같은 이벤트 사용이 가능하고 크론도 있습니다.
on:
schedule:
- cron: '* * * * * *'
jobs:
cron
수행할 내용
=>schedule 기능을 적절히 이용하며 주기적인 학습이나 배포가 가능
일정한 주기를 가지고 데이터를 수집해서 학습을 하고 그 모델을 배포하는 서비스를 만드는 경우 git action 에서 일정한 주기를 가지고 모델을 학습하도록 만들어주면 됩니다.
수집한 데이터를 public cloud 의 storage service를 이용하면 public cloud 의 AI 서비스에서 데이터 파이프라인 구축이 쉬워집니다.
2)이벤트 기반 명령 실행
이벤트(repository 관련 이벤트, cron 이벤트) -> Job -> Step -> Action
3)node 테스트 프로젝트를 git hub action을 이용해서 수행
=>node 설치 확인: node --version
=>디렉토리 생성: mkdir node_test
=>디렉토리로 이동: cd node_test
=>노드 프로젝트 생성: npm init
=>테스트 패키지 설치: npm install mocha
파이썬에는 테스트를 패키지를 freeze 로 배포가 안되는 경우가 있는데 이런 경우에는 설치한 패키지의 이름을 의존성 목록 파일에 직접 추가를 해주어야 합니다.
=>테스트를 위한 파일을 생성해서 테스트 코드 작성 - 파일명은 test. 으로 시작해야 합니다.(test.spec.js 로 생성)
DevOps 나 MLOps 에서는 실행되는 코드 와 테스트를 위한 코드가 동일한 장소에 저장되어 있어야 합니다.
describe('Default Test Set', () => {
it('test1 should be passed', ()=>{
console.log('test1 passed')
})
it('test2 should be passed', () => {
console.log('test2 passed')
})
})
=>테스트 수행
./node_modules/.bin/mocha test.spec.js
윈도우즈에서는 cd node/modules -> cd .bin -> mocha ../../test.spec.js
=>package.json 파일의 scripts 부분을 수정
- windows
"scripts": {
"test": "node_modules\\.bin\\mocha test.spec.js"
},
- mac, linux
"scripts": {
"test": "./node_modules/.bin/mocha test.spec.js"
},
=>현재 프로젝트를 git hub에 푸시
- .gitignore를 생성해서 작성: node_modules
- git hub 에 repository 생성: https://github.com/itggangpae/node_test.git
- git init
- git add .
- git commit -m "node test"
- git remote add origin https://github.com/itggangpae/node_test.git
- git push -u origin main
=>.gitignore 가 적용이 안될 때는 cache를 삭제하고 수행(git rm -r --cached .)
=>gitaction 작성 - git hub 내에서 action에서 yaml 파일을 추가해서 작성해도 되고 로컬 레지포지토리 안에 .github/workflows 디렉토리 안에 yaml 파일을 만들어서 업로드해도 됩니다.
여러 개의 파일도 가능
name: Node.js CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
#배열 변수 선언 - python 이나 node 같은
#프로그래밍 언어는 여러 버전에서 동작
strategy:
matrix:
node-version: [14.x]
#작업 수행
#uses 는 다른 곳에서 만든 것 이용
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{matrix.node-version}}
- run: npm install
- run: npm test
=>push
git add .
git commit -m "git action"
git push origin main
4.TDD(Test Driven Development)
1)개요
=>소프트웨어 개발 방법론 중 하나
=>이전에는 테스트 코드의 작성을 프로덕션 코드가 작성된 이후에 했지만 TDD를 적용하면 프로덕션 코드보다 실패하는 테스트 코드를 먼저 작성하고 코드를 테스트를 통과하기 위해 최소한으로 개선한 이후 테스트를 통과한 프로덕션 코드를 리팩토링
=>TDD는 테스트만을 위한 기술이 아니며 오히려 소프트웨어 설계 방법론에 가까움
2)TDD Cycle
=>RED -> GREEN -> REFACTOR
=>RED: 테스트 코드 작성
동작하는 프로덕션 코드가 없는 상황에서 테스트 코드를 먼저 작성하는 것으로 앞으로 작성될 프로덕션 코드가 어떤 동작을 하면 좋을지 작성
요구사항을 작성하는 것 과 유사
테스트 코드를 먼저 작성하기 때문에 테스트 코드가 기대하는 로직이 실행되지 않아 테스트는 실패
실패하는 테스트 코드를 작성하는 것이 목적
2개의 숫자를 더해서 결과를 넘겨주는 로직을 작성
def plusTest():
calculator = Calculator()
result = calculator.plus(1, 3)
Assert(result, 4)
=>GREEN: 테스트를 통과하는 최소의 코드를 작성
실패하는 테스트 코드를 통과하도록 만드는 최소한의 코드를 작성
현재 목적은 빠르게 GREEN을 보는 것 - 에러가 없어져야 함
코드를 깔금하게 만드는 작업이 시간이 걸린다면 테스트 코드를 통과하는 데에만 집중을 해서 코드를 작성 - 죄악
GREEN을 보기 위해서는 어떤 죄악을 저질러도 됨
빠르게 결과를 확인하기 위해서 상수를 반환하는 코드를 많이 사용
class Calculator:
def plus(a, b):
return 4
=>REFACTOR: 리팩토링
GREEN을 통과하기 위해 저지른 죄악을 수습
좋은 코드로 리팩토링
class Calculator:
def plus(a, b):
return a + b
3)원칙
=>실패하는 단위 테스트를 작성하기 전에는 프로덕션 코드를 작성하지 않음
=>컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성
=>현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성
4)필요한 이유
=>변화에 대한 불안감 해소: 어느 정도 테스트 코드가 작성되어 있기 때문에 변화에 대한 영향력을 빠르게 파악할 수 있음
=>한 번에 하나의 일에만 집중할 수 있음
=>빠른 피드백
=>테스트 코드 자체가 문서화
=>테스트를 나중에 작성하는 귀찮음
=>코드 퀄리티: 결합도를 낮추고 응집도를 높일 수 있음 - 느슨한 커플링(마이크로 서비스, 애자일, 컨테이너 등)
5.파이썬의 테스트 모듈 - pytest
=>test_로 시작하는 모든 파일을 로드하고 test_ 로 시작하는 모든 함수를 실행하는 패키지
=>설치: pip install pytest
=>실행: pytest
=>테스트 코드는 옭고 그름만 판단
=>테스트를 건너뛰기
pytest.skip() 함수를 사용하여 테스트를 건너뛴 것으로 표시하고 다음 함수로 이동할 수 있음
pytest.mark.skip 데코레이터를 이용해서 테스트를 건너뛸 수 있음
6. Mongo DB를 연동하는 flask web application을 만들어서 파싱을 수행하는 함수를 테스트하고 테스트를 통과하면 Dockerfile을 이용해서 빌드를 한 후 배포하는 애플리케이션
1)Mongo DB 컨테이너 실행
=>docker run --name mongodb -v ~/data:/data/db -dit -p 27017:27017 mongo
=>bash 접속: docker exec -it mongodb bash
2)가상 환경 만들기
=>빈 디렉토리 생성 - flaskweb
=>가상 환경 생성
3)필요한 패키지 설치
=>flask
=>requests, beautifulsoup4
=>pymongo
4)mongodb 연동하는 flaskweb 만들기
=>프로젝트에 app.py 파일을 추가하고 작성
from flask import Flask, render_template, jsonify, request
app = Flask(__name__)
#Mongo DB 사용 준비
from pymongo import MongoClient
client = MongoClient('mongo', 27017)
db = client.adam
@app.route("/")
def home():
#templates 디렉토리의 파일을 출력합니다.
return render_template("index.html")
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
=>프로젝트에 templates 디렉토리를 만들고 index.html 파일을 만든 후 브라우저에서 재접속
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flask Web</title>
</head>
<body>
<h3>Flask Web Application</h3>
</body>
</html>
=>python app.py 로 애플리케이션 실행
=>브라우저에서 localhost:5000 으로 접속
5) 영화 정보를 파싱해서 결과를 넘겨주는 함수(URL -> https://movie.naver.com/movie/bi/mi/basic.nhn?code=185293)
=>utils.py 파일을 만들고 파싱을 위한 함수 작성
import requests
from bs4 import BeautifulSoup
def get_movie_info(url_receive):
#User-Agent 는 접속한 클라이언트 정보
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36(KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
#html 읽어오기
data = requests.get(url_receive, headers=headers)
#파싱 준비
soup = BeautifulSoup(data.text, 'html.parser')
#파싱
title = soup.select_one('div.title_area.type_keep._title_area > h2 > span > strong').get_text()
image = soup.select_one('div.cm_info_box > div.detail_info > a > img')['src']
desc = soup.select_one('div.cm_info_box > div.detail_info > div > span').get_text()
return title, image, desc
=>테스트에 사용할 함수를 소유할 test_utils.py 파일을 생성하고 함수를 작성
from utils import get_movie_info
def test_get_movie_info():
#샘플 url
test_url =
"https://movie.naver.com/movie/bi/mi/basic.nhn?code=185293"
#함수를 호출해서 값을 가져오기
title, image, desc = get_movie_info(test_url)
print(title)
print(image)
print(desc)
assert title == "내일의 기억"
=>pytest를 설치하고 pytest 명령을 수행
=>app.py 수정
from flask import Flask, render_template, jsonify, request
from utils import get_movie_info
app = Flask(__name__)
#Mongo DB 사용 준비
from pymongo import MongoClient
client = MongoClient('127.0.0.1')
db = client.adam
@app.route("/")
def home():
#templates 디렉토리의 파일을 출력합니다.
return render_template("index.html")
@app.route('/memo', methods=['GET'])
def listing():
articles = list(db.articles.find({}, {'_id': False}))
return jsonify({'all_articles': articles})
@app.route('/memo', methods=['POST'])
def saving():
url_receive = request.form['url_give']
comment_receive = request.form['comment_give']
title, image, desc = get_movie_info(url_receive)
doc = {
'title': title,
'image': image,
'desc': desc,
'url': url_receive,
'commtent': comment_receive
}
db.articles.insert_one(doc)
return jsonify({'msg': "저장이 완료되었습니다."})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
=>서버 구동: python app.py
=>Web API Test
GET 방식 테스트: 파라미터에 한글만 없다면 브라우저에 직접 URL을 입력해서 테스트가 가능
POST 방식 테스트: POSTMAN 같은 API Test 도구를 이용
6)git hub에 업로드
=>필요한 패키지를 텍스트 파일에 내보내기: 컨테이너에서 실행될 때는 가상 환경이 없고 ubuntu 에 python 만 설치된 상태이므로 소스 코드를 실행할려면 패키지들을 다시 설치해야 합니다.
pip freeze > requirements.txt
=>git hub에 배포
원격 저장소에 레포지토리 생성: https://github.com/itggangpae/flaskweb.git
git init
git add .
git commit -m "first"
git remote add origin https://github.com/itggangpae/flaskweb.git
git push -u origin main
=>git hub action 추가
로컬 레포지토리에 .github/workflows 디렉토리에 야믈 추가
원격 레포지토리에서 action을 추가해도 됩니다.
name: CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
python-hello-world:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "3.8"
- run: python -c "print('Hello World')"