Lambda 표현식 이란?

Java에서도 똑같이 Lambda 표현식이 있으며 Java 1.8 부터 지원하게 되었다.
즉 "익명함수"라고 하며 보통 함수명을 붙여서 함수를 만들지만 재사용성이 없으며 1급함수를 다룰때는 Lambda가 유용할 수 있다.

Lambda 표현식 쓰는 법

def add_ten(x):
    return x + 10

lambda x: x + 10

즉 일반적으로는 def 함수명(parameter): 과 return 으로 이루어진다.

하지만 lambda는 익명이므로, lambda parameter: statement 또는 표현식의 경우 return 값이 된다.

일반적인 함수와 매핑을 해보면 def -> lambda    (parameter): -> parameter:    return -> 생략하고 바로 return값.

또한 중요한 것은 lambda 에서 expression 부분은 무조건 1개만 가능하다. 여러개를 사용할 수 없다.( colon(;) 으로 구분해도 안된다. )

 

Lambda 사용 예시

Lambda의 기본적인 사용예시를 아래에 설명한다.
  • 만약 일반 함수처럼 이름(reference)을 할당 하고 싶다면.
    • add_ten = lambda x: x+10
    • 하지만 이는 이렇게 된다는 것만 알것. PEP8에서 assignment(=)와 함께 lambda를 쓸려면 def를 쓰라고 강력 권고하고 있음.
  • lambda *args, **kwargs: None
    • 어떤 parameter가 오더라도 None을 return하라는 의미임.(즉 아무것도 하지 마라.)
    • 아래와 동일한 코드임.
def do_nothing(*args, **kwargs):
    passs

 

Lambda 자주 사용하는 용법

실제 개발할때 가장 많이 사용하는 lambda case이다. map, filter, sorted 시에 list와 함께 쓰인다.

map, filter, sorted, list 와 함께 사용

map은 말그대로 매핑하는 기능을 수행하는 built-in 함수이다.

map(function, iterable, ...) 의 signature 이며, function은 매핑Rule이다. 그리고 iterable은 보통 list가 들어오며

iterable로 들어온 대상의 항목을 하나씩 매핑하라는 뜻이다.

따라서 map(대문자바꾸는 함수, ['a', 'b', 'c']) 이렇게 하면 ['A','B','C'] 가 나온다.

 

map(lambda x: x.upper(),  ['a', 'b', 'c']) => 이거 자체도 map함수이며 list로 할려면,

list(map(lambda x: x.upper(),  ['a', 'b', 'c'])) 이렇게 하면 ['A', 'B', 'C']가 나온다. 


filter(function, iterable...) 도 필터링하는 built-in 함수이다.

즉, 필터링을 하되 어떻게 필터링해라라는 것이 function으로 오고, iterable은 필터링할 대상이다.

예를 들면 아래와 같다.

list(filter(lambda x: 'o' in x, ['cat', 'dog', 'cow']))

즉, x 가 in x 로 사용되므로 iterable이고 그게 바로 다음 parameter이다. 그리고 x 안에 알파벳 'o'  있으면 True임.

따라서 눈치챘겠지만 function은 boolean을 return하는 함수이어야 한다.


sorted 도 정렬된 객체를 새로 만드는 built-in 함수이다. 

sorted(iterable, function..) 이 된다.

즉 sort할 대상 iterable이며 해당 iterable에서 정렬할 로직이 function이 된다.

ids = ['id1', 'id2', 'id30', 'id3', 'id22', 'id100']

sorted_ids = sorted(ids, key=lambda x: int(x[2:]))

상기 예는 ids를 정렬해서 새로운 sorted_ids를 만들으라는 것인데 정렬로직은 x: int(x[2:]) 이다.

즉 iterable x 가 들어오면 세번째(포함)이후가 key value가 된다. 해당 값으로 정렬하라는 것이며

위 예의 경우는 id를 뺀 세번째 1,2,30,3,22,100 으로 정렬하라는 것이다.

즉 return은 ['id1', 'id2', 'id3', 'id22', 'id30', 'id100'] 이 된다.

 

'Python' 카테고리의 다른 글

Python Celery Task Monitoring  (0) 2019.10.08
Celery from scratch  (0) 2019.05.20
Python - Monkey Patch  (1) 2019.05.02
Python Excel to MySQL  (0) 2019.04.12
Database 정보 CSV 작성방법  (0) 2019.04.10

Celery Startup

Celery Coding

Coding은 매우 간단하다.(아래 샘플)

 

[file 명 : tasks.py]

from celery import Celery

app = Celery('tasks', broker="broker url", backend="backend url")

@app.task

def add(x, y):

    return x+y

 

이렇게 하면 기본적인 코딩 끝이다.

@app.task는 celery에 task를 등록한다는 것이다.

 

Celery 실행

실행방법

celery config paramters

 

http://docs.celeryproject.org/en/latest/userguide/configuration.html#example-configuration-file

ex) CELERYD_CONCURRENCY 는 celery 의 동시 실행 worker갯수를 의미한다.

따라서, 해당 변수를 setting하면 제어가능하다.

위의 변수를 setting안하면 default는 12이다.

따라서 아래 명령어 celery 를 실행하고 ps -eaf | grep celery | grep -v grep 하면 총 13개가 나온다.

1개는 master 이며 나머지 12개가 worker이다.

app = Celery(...), app.conf.update(CELERYD_CONCURRENCY=3) 이렇게 하고 다시 ps 해보면 4가 나온다.

 

celery -A tasks worker --loglevel=info

-A: application ( = -app )  => 확장자를 제외하고 입력함. 만약 tasks.py 이면 tasks를 입력

worker 는 기본 명령어이며 worker 서버를 구동하라는 뜻이다.

--loglevel은 다들 아는 것이니 넘어가자.

정리 : -A 파이썬화일명(확장자제외) 이부분만 기억하면 된다. 

 

celery worker 에 작업시키기

python prompt로 들어감.

중요한 것은, @app.task를 통해 등록한 add task를 호출하는 것은 delay 이다.

delay : task call

위에 key가 redis에 저장되는 키이다. ( celery-task-meta-  + key )

위와 같이 redis-cli로 들어가서 get key정보를 하면 값이 나온다. result를 보면 6이다.

task_id는 key가 된다.

 

비동기 작업 수행

Celery 활용시 필수 사항

대부분 비동기처리를 위해 Celery를 사용한다.

그리고 서버는 일반적으로 여러대이며 어떤 서버(그리고 어떤 Celery데몬이) 가 해당 Task를 수행할지 모른다.

예를 들면 File Upload 및 데이터 처리시 1번서버에서 Upload를 하면 1번서버에서 수행되어야 하지만,

2번서버의 Celery데몬이 작업을 수행하면 File not found error가 난다.

또는 2개의 데몬이 있는데 대량 작업이 돈다면 그 작업은 하나의 데몬, 나머지 작업은 다른 데몬이 하도록 하게 하고 싶은 경우,

Queue라는 개념이 매우 중요하다.

 

예를 들면,

add 라는 task가 있다고 하자.

@app.task
def add(x, y):
    sleep(30)
    return x + y

위 Task는 30초 걸리는 장시간 작업이다.

celery -A proj worker -l info
celery -A proj worker -l info -Q hipri

위 데몬에  -Q option이 큐지정이다.

-Q option : 기본값은 celery이다. 즉 없는 것은 -Q celery와 같다.

-Q hipri : queue가 hipri로 들어오면 수행하는 데몬이고 나머지는 수행안한다.

apply_async를 써야 real-time으로 queue를 제어할 수 있고, delay를 사용할려면 queue는 속성으로 한번 지정되면,

다시 수정해서 celery데몬을 띄워야 하니 나는 항상 apply_async를 사용한다.

1) add.apply_async((2,5))
2) add.apply_async((2,3), queue='celery')
3) add.apply_async((2,5), queue='hipri')

1)번과 2)번은 default로 동일하다.

3)번은 데몬의 처리queue가 hipri인 대상이 수행하라는 뜻이다.

 

이걸로 아래의 실무에 적용할수 있다.(예시임.)

sequenced : long running job은 하나의 데몬이 순차적으로 수행

paralleled : 가벼운 작업은 여러 데몬이 병렬로 수행

near_real : 준실시간 처리는 여기로... 등등

 

여러 celery데몬을 띄워서 제어하는 것 까지 실무에서 많이 사용한다.

이상 기본적인 Celery를 마쳤으며 이정도만 알아도 활용할 수 있다.

더 고급정보는 실무에 활용하면서 배우기 바란다.

 

 

'Python' 카테고리의 다른 글

Python Celery Task Monitoring  (0) 2019.10.08
Python Lambda  (0) 2019.09.03
Python - Monkey Patch  (1) 2019.05.02
Python Excel to MySQL  (0) 2019.04.12
Database 정보 CSV 작성방법  (0) 2019.04.10

Monkey Patch란?

업무를 하면서 가끔 회사에서 Monkey Patch를 하고...라는 말을 듣는다.

무슨뜻이지? 하면서 한번도 찾아본적이 없어서 이번에 찾아보고 정리한다.

 

위키피디아에 이렇게 정리되어 있다.

 

A monkey patch is a way for a program to extend or modify supporting system software locally (affecting only the running instance of the program).

해석을 한다면 monkey patch는 프로그램이 내부 프로그램을 로컬에서 잠시 다른 기능을 수행하도록 수정하거나 확장하도록 하는 방법이며 이는 로컬이므로 런타임시에만 영향을 주는 방식이다.

 

예시로는 Python으로 아래와 같이 있다.

>>> import math
>>> math.pi
3.141592653589793
>>> math.pi = 3
>>> math.pi
3
>>> ================================ RESTART ================================
>>> import math
>>> math.pi
3.141592653589793
>>>

위의 내용만 봐도 이해는 했을 것이다.

그런데 어디다가 쓰지?

 

예상은 했겠지만, Test할때 주로 쓴다.

그리고 다른 기능을 수행하도록 하는 부분 또한 Mock Object를 원하는 기능이 수행하도록 만든 뒤 그것으로 replace하는 것이다.

 

my_calendar.py

import requests
from datetime import datetime

def is_weekday():
    today = datetime.today()
    return (0 <= today.weekday() < 5)

def get_holidays():
    r = requests.get('http://xxx.holiday.org/api/holidays')
    if r.status_code == 200:
        return r.json()
    return None

위와 같은 코드를 만들었고, 이제 테스트를 해야 한다.

get_holidays() 함수는 requests가 필요한데 아직 위의 url에서는 해당 api를 서비스하지 않고 있다.

즉, 테스트를 하기가 어렵다.

 

아래와 같이 tests.py를 한번 보자.

 

import unittest
from my_calendar import get_holidays
from requests.exceptions import Timeout
from unittest.mock import patch

class TestCalendar(unittest.TestCase):
    @patch('my_calendar.requests')
    def test_get_holidays_timeout(self, mock_requests):
            mock_requests.get.side_effect = Timeout
            with self.assertRaises(Timeout):
                get_holidays()
                mock_requests.get.assert_called_once()

if __name__ == '__main__':
    unittest.main()

위의 코드는 my_calenadar class를 Test하기 위한 코드이다.

 

@patch('my_calendar.requests') 이부분이 위에 설명되었던 Monkey Patch부분이다.

@patch decorator에 들어가는 파라메터(my_calendar.requests)는 replace 대상(target)이 되는 속성이다.

즉, my_calendar 소스내에 import requests 가 있는데 이걸 내가 원하는 requests로 바꿀려고 한다.

그럼 바꿀려고 하는 mock object 참조변수는 def test_get_holidays_timeout(self, mock_requests) 의 mock_requests이다.

 

따라서 해당 함수 안에서 mock_requests.get.side_effect = Timeout 즉 해당 request의 get() 함수는 실제 url에 접속하고 관계없이,

Timeout을 Raise해줘.. 라는 것으로 가짜 object를 만들었다. 이제 @patch decorator를 통해 실제 my_calendar.py의 requests 객체를 바꾸었으니 Exception Test가 가능해졌다.

 

with 문 이하는 본 monkey patch와 관계없는 Mock관련 사항이므로 설명을 생략한다.

 

따로 Python의 Mock 관련해서는 설명 글을 게시할 예정이다.

 

정리하자면 위와 같이 requests 는 아시겠지만 이를 테스트할려면 해당 api서버가 개발을 해주거나 서비스를 제공해야 테스트 가능하다.

이부분을 내가 로컬에서 단위테스트를 하기 위해서는 원래의 requests를 내가 원하는 방식으로 바꿔줘야 하는데 이게 monkey patching이며, 원하는 방식으로 바꾸기 위한 임시객체(가짜객체)를 Mock Object라 하며 Python에서는 unittest.mock에서 강력한 기능들을 제공한다.

 

끝.

'Python' 카테고리의 다른 글

Python Celery Task Monitoring  (0) 2019.10.08
Python Lambda  (0) 2019.09.03
Celery from scratch  (0) 2019.05.20
Python Excel to MySQL  (0) 2019.04.12
Database 정보 CSV 작성방법  (0) 2019.04.10

PostgresQL String Concatenation 엔 뭔가 다른 것이 있다.

이 다른 것을 알지 못하면 큰 장애를 유발 할 수 있다.

PostgresQL을 많이 다루어 보지 못해서 생긴 이슈일수도 있다.

꼭 아래 내용을 숙지할 것.

 

String concatenation 2 가지 방법

1. || Operator

||( vertical bar ) 2개를 연속하여 사용하는 방법이며 이것은 NULL 을 인지한다.

따라서 NULL이 들어오면 모든 문자는 NULL이 된다.

select 'A'||NULL; --> NULL Return

Ex) Oracle의 경우, select 'A'||NULL from dual --> 'A' Return 됨.

 

2. concat Function

concat Function은 NULL을 무시한다.

select concat('abc', NULL, 'def'); --> 'abcdef' 즉, NULL을 무시하여 concat('abc','def') 와 같은 결과임.

 

참조 URL) http://www.postgresqltutorial.com/postgresql-concat-function/

 

PostgresQL 에서의 Empty String

소위 말하는 '' 이다.( Single Quatation 2개를 연속해서 씀.)

PostgresQL에서 ''은 NULL 이 아니고 말 그대로 "빈 문자열" 자체의 의미이다.

하지만 다른 DB에서는 NULL 로 인지한다.

따라서 select * from aaa where col1 is null 과 where col1 = '' 은 다르다.

그리고 not null 컬럼에 ''이 들어갈수 있다. 육안으로 보기엔 null처럼 보이니 주의해야 한다.

 

 

대량 엑셀을 효율적으로 ...

배경

현업이 IT부서에 Raw Data를 뽑아달라고 했다.

뽑아보니 레코드 수도 그렇지만 700Mb가 넘는 사이즈였다...

이걸로 뭘 하겠냐고 물어보니 엑셀함수를 이용해서 데이터 검증을 하겠다고 한다...

일단 뽑아줄테니 이걸로 업무하기는 어려울것 같다, 화일 여는데만 10분걸리고 수정/저장할때마다 10분씩 걸릴거다..

라고 하였다. ( 매주 하던 작업이고 할때마다 하루종일 걸린다고 했다..)

 

업무처리 방식 제안

도저히 생산성이 안나올테니 걸어볼 엑셀 함수와 최종 어떤 작업할껀지 알아내고, IT부서에서 기본적인 엑셀 작업을 해주기로 했다.

 

Python 활용..

Python script를 통해 제공한 엑셀을 내 Local DB( MySQL ) 로 로드하여 각종 함수를 적용하고 다시 그것을 엑셀로 뽑아서 주면 된다.

다른 라이브러리도 있지만 나는 pandas 를 익숙하게 잘 쓰고 싶어서 pandas로 하고 python orm은 sqlalchemy를 활용하기로 했다.

 

따로 엑셀함수등 구현은 업무마다 많이 상이하니..

"Excel File을 DB에 로드" 하는 부분만 예시로 기재한다.

import pandas as pd
from sqlalchemy import create_engine
table = pd.read_excel('엑셀화일명.xlsx', sheet_name='쉬트명', header=0,)
engine = create_engine("mysql+pymysql://DB계정:비밀번호@127.0.0.1:3306/스키마명", encoding='utf-8-sig')
table.to_sql(name='테이블명', con=engine, if_exists='append', index=False)

위 Script는 연습해서 외워서 필요할때 테이블만 만들고 간단히 메일쓰듯이 할 수 있으면 좋겠다.

이거 하나 해주니 현업이 엄청 좋아했다. 덩달아 나의 평가도 올라갔다.


잠깐! 꼭 알아야 할 것

1. Encoding

내 Table 의 첫번째 컬럼은 Bigint(20) 이었다.

그런데 들어가다가 오류가 났다. 분명히 눈엔 47748649 만 보이는데...Why?

위 engine 의 encoding option을 보면 처음에는 utf-8 로 했다가 utf-8-sig 로 하니까 잘된다.

utf-8의 BOM문제라고 한다.  그래서 그냥 utf-8 이 아닌 utf-8-sig ( 약어는...signature로 예상됨. )

로 변경하니 잘된다. 따라서 위 오류나면 ( \ufeff --> \u : 유니코드 의미, feff : UTF-16 Big Endian 의미)

즉 UTF-16 Big Endian으로 Encoding된 문자를 utf-8로 해서 앞에 BOM 문자가 포함되어 오류남.

위처럼 하면 utf-8 로 인코딩하되, signature를 보고 input 문자의 encoding을 확인하라는 의미임.

참고 URL : http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem

 

 2. sqlalchemy , pymysql 등 환경

pip install pandas
pip install pymysql
pip install sqlalchemy

따라하기 예제코드

아래는 Full Code 이며, 계정과 비밀번호, 스키마명만 변경해서 하면 된다.

테이블구조는 예제 실습을 위해 임의로 정하였다.

 

내 Local에 테이블이 없는 상태이다.

mysql table 확인

처리해야 할 엑셀 화일 샘플이다.( raw_data_test.xlsx)

아래 코드 실행

import pandas as pd
from sqlalchemy import create_engine

engine = create_engine("mysql+pymysql://계정:비밀번호@127.0.0.1:3306/스키마명", encoding='utf-8-sig')

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.mysql import BIGINT
from sqlalchemy import Column, String, Integer

Base = declarative_base()

class BillRawTest(Base):
    __tablename__ = 'bill_raw_test'
    __table_args__ = {'extend_existing': True}
    bill_id = Column(BIGINT(20), primary_key  = True)
    item = Column(String(20))
    amount = Column(Integer)

metadata = Base.metadata
metadata.create_all(engine)

df = pd.read_excel('~/Downloads/bill_raw_test.xlsx', sheet_name='Sheet1', header=0)
df.to_sql(name='bill_raw_test', con = engine, if_exists='append', index=False)

 

실행 후 DB조회

 

끝.

'Python' 카테고리의 다른 글

Python Celery Task Monitoring  (0) 2019.10.08
Python Lambda  (0) 2019.09.03
Celery from scratch  (0) 2019.05.20
Python - Monkey Patch  (1) 2019.05.02
Database 정보 CSV 작성방법  (0) 2019.04.10

MySQL 의 테이블 데이터를 CSV로 만들기

현장에서 운영업무를 하다 보면 현업이 Raw 데이터를 긴급으로 CSV로 달라는 요청이 종종 있다.

서버는 상용이고 터미널이외엔 적당한 tool이 없다.

 

이런 경우, Python을 활용하면 빨리 된다.

상용의 개인계정(리눅스)에 python 과 pip를 설치 할 수만 있다면 OK!

 

리눅스 서버에서,

pip install pandas
pip install sqlachemy

 

그리고 python 을 쳐서 python prompt 로 진입.

import pandas as pd
import sqlalchemy as sql

connect_string = 'mysql+pymysql://유저명:비밀번호@DB서버호스트명:3306/스키마명'

sql_engine = sql.create_engine(connect_string)
query =query = "select * from 주문테이블 where 조건들"
df = pd.read_sql_query(query, sql_engine)
df.to_csv(r'test.csv')

 

위와 같이 하면 총 7줄의 코딩으로  간단히 처리된다.

 

끝.

 

'Python' 카테고리의 다른 글

Python Celery Task Monitoring  (0) 2019.10.08
Python Lambda  (0) 2019.09.03
Celery from scratch  (0) 2019.05.20
Python - Monkey Patch  (1) 2019.05.02
Python Excel to MySQL  (0) 2019.04.12

자주 쓰지만 잘 모르는 git 명령어

git commit -am <message>

이 명령어는 git add + git commit 이다.

즉 Tracking되는 unstaged 된 화일을 staging area 로 이동( git add ) 후 commit 을 하는 것임.

참고로, git commit -am 을 하면 모든 tracking되는 화일이 모두 staging으로 간다.

따라서 주의해야한다. ( 필요한 화일만 add 할려면 따로 git add filename1 filename2.. 이런식으로 하고 

git commit -m 으로 해야 한다.

 

git pull ? fetch ?

이건 아주 간단하다.

git fetch 한후 git merge 한것이 git pull 과 완전 동일하다.

따라서 git pull 도 충돌이 날수 있다.( git merge를 하는 것이므로 )

하지만 git fetch는 충돌안난다. 변경사항만 가져오므로.

 

Remote의 특정브랜치 기준으로 브랜치 만들기

요약하자면, Remote의 특정Branch기준으로 Local에 브랜치 만들고 그걸 remote에도 반영하기.

 

일단 현재 Branch 상태를 알아봐야 겠지?

git branch : 현재 local의 branch를 조회함.

git branch -a : remote 포함해서 모두 조회함.

그런데 동료가 remote에 branch만들었다고 하는데..왜 안보이지?

그럴때는  git fetch 이걸 통해 remote들의 정보를 가져온다.

그리고 나서 다시 git branch -a 를 하면 branch 정보를 모두 볼수 있다.

 

Remote에 이미 Branch가 있는 경우.( Remote 특정 Branch 로 부터 만들기 )

리모트의 Branch명과 동일하게 내 Local에 Branch를 만들기.

git checkout -t origin/feature-01 ( -t 는 tracking option 이며 --tracking 도 동일옵션임 )

이렇게 하면 리모트와 동일하게 만들고 tracking까지 한다.

 

리모트의 Branch명과 다르게 내 Local에 Branch를 만들기

git checkout -b local_feature-01 origin/feature-01

 

Remote에 Branch가 없는 경우.

Remote의 특정브랜치로 부터 만들고 그 Branch를 remote에 올려야함.

git checkout -b issue-001 origin/feature/iss-1

git push origin issue-001

이렇게 하고 github가보면 issue-001이 생긴것을 확인할 수 있다.


단순하지만 중요한 것.

위의 issue-001을 보면, issue-001은 origin/feature/iss-1 에서 만들었고 origin/feature/iss-1은 master로 부터 만들었다.

따라서 issue-001을 수정하고 push하면 반드시 origin/feature/iss-1 에 merge하고 그걸 master로 또 merge해야 한다.

일단 해보자.

 

수정, git commit , git push origin HEAD 를 수행함.

github에 가보면 pull request 대상으로 뜬거 확인.

pull request 를 원래 base 였던 issue-001 -> origin/feature/iss-1 로 진행함. commit 1개 발생.

이후에 수기로 다시 pull request 함. ( origin/feature/iss-1  -> master )

merge 시 confict 남. -> conflict 해결 -> commit 1개 발생.

즉 origin/feature/iss-1 에는 2개의 commit이 존재하게 되고 그걸 master로 merge하면 된다.

즉, conflict 가 나서 merge 작업을 하면 그것 또한 origin/featrue/iss-1 브랜치에서 수정된 것으로 된다.

참고로 물론 issue-001 -> 바로 master에 머지할 수 있지만, 그렇게 하게 되면 history 와 브랜치가 꼬여서

복잡해지고 관리가 안됨. 따라서 실무에서는 항상 branch의 base가 된 remote branch에 먼저 push하고 merge

하면서 차근차근 진행할 것.

 


복잡하지만 중요한 것 ( Branch 관련 )

만약, 리모트에 브랜치(feature/iss-2) 가 있는데 로컬에 그 기준으로 다른 이름으로 브랜치를 만들고 Tracking 을 하는 경우.

git checkout -b local_iss-2 origin/feature/iss-2

그럼 local 은 즉시 local_iss-2 로 checkout 되어 있는 상태이다.

 

여기서 문서를 수정하고 commit 하고 git push 를 하면 오류가 난다.

local 현재 브랜치 명과 remote 브랜치 명이 틀려서 다른 명령어를 쓰라는 것이다.

 

따라서,

git push origin HEAD 이렇게만 하면 새로운 iss-2 이라는 브랜치를 리모트에 만들고 push하고,

git push origin HEAD:feature/iss-2 를 하면 그 feature/iss-2 에 push한다.( 즉, local에서 tracking하는 리모트브랜치로 push)

 

git push origin HEAD  를 하고 나면 github에서는 어떤일이 생기냐 하면,

local로 부터 remote의 feature/iss-3를 base로 만든 branch local_iss-3 이 push되었으니 remote의 feature/iss-3에 pull request해야 한다. 라는 메세지가 github 상단에 친절하게 보인다.

( 실제로 아래 Compare  pull request 를 눌르면 기본으로 feature/iss-3 <-- local_iss-3 으로 표시됨.)

pull request하고 feature/iss-3에 merge & commit을 하면 자동으로 또 한번 더 나온다. 뭐가? ( 맞춰보세요 0)

아래와 같이 나온다. 아래는 master <-- feature/iss-3 을 하라는거다.( 캡쳐는 iss-2로 된건데 실수임. )

이 사항들은 꼭 기억하길 바란다.

'개발환경 > GIT' 카테고리의 다른 글

Git & Github  (0) 2019.04.07

GitHub 에 여러 계정을 연결하기.

일반적으로 Git 을 사용하는 User는 Github 계정을 여러개 가지고 있다.

하지만 이 계정들을 자유자재로 Local PC에서 접근하고 다루는 것은 은근히 잘 모른다.

이에 정리해본다.

 

GitHub 에 Repository 생성 

GitHub Repository 생성은 github 사이트에 접속해서 직접 해야함.( 따로 설명 안함 )

Local에서 아래와 같이 한다.

mkdir user1

cd user1

git init // user1 디렉토리 기준으로 git을 초기화한다.

이까지 하면 내 로컬에 git 을 초기화까지 하였다.

Local에 ssh 및 계정 설정

내 Local에서 개인키/공개키 쌍을 만든다.

그리고 나는 개인키를 보유, 공개키는 github의 내 계정에 등록한다.

그리고 해당 계정의 github에 내 개인키로 접속하면 접속된다.

 

내 Local에 여러개의 ssh키 등록

mkdir ~/.ssh/github_key

mkdir ~/.ssh/bitbucket_key

이런식으로 관리를 위해 directory를 여러개 만든다.

 

그리고 cd ~/.ssh/github_key 로 하여 github용 폴더로 이동.

ssh-keygenssh-keygen -t rsa -C "XXXXXX@gmail.com"   // 개인키/공개키 생성

위 명령어 수행시 id_rsa (개인키) 와 id_rsa.pub( 공개키 )를 github_key 하부에 저장되도록 한다.

 

위까지 하고 github에 내 공개키를 등록한다.

github의 계정으로 가서, settings > SSH and GPG Keys 로 이동하여 New SSH Key를 생성한다.

생성할때 여기도 관리를 위해 이름등을 알기 쉽게 잘 입력할 것.

 

config 화일 설정

관리를 하기 위한 config화일을 설정한다. d

아래처럼 Host로 구분하면 되고, github의 경우 HostName은 "github.com" 그리고 User 는 "git" 으로만 해야 한다.

#Host gitlab
#    HostName gitlab.com
#    User git
#    PubkeyAcceptedKeyTypes +ssh-rsa
#    PreferredAuthentications publickey
#    IdentityFile ~/.ssh/gitlab-key/id_rsa

Host github-user2
    HostName github.com
    User git
    Port 22
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/github-key/user2/id_rsa
    
Host github-user1
    HostName github.com
    User git
    Port 22
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/github-key/user1/id_rsa

#Host gist
#    HostName gist.github.com
#    User git
#    Port 22
#    PreferredAuthentications publickey
#    IdentityFile ~/.ssh/id_rsa

#Host my-dev
#    HostName 192.168.0.214
#    User lesstif
#    Port 9022
#    PreferredAuthentications publickey
#    IdentityFile ~/.ssh/dev/id_rsa

## Host 를 * 로 지정하면 위에서 설정한 Host를 제외하고 모든 Host 에 적용됨
#Host *
#    User dosjung
#    PreferredAuthentications publickey, password
#    IdentityFile ~/.ssh/id_rsa

Local 에 Remote Repository 추가

이제 Remote Repository를 추가한다.

동일한 Repository에 서로 다른 git 계정(local)이 사용할 거다.

config를 통해 2개의 Host를 등록했다.

여기서 만약

git remote add origin git@github.com... 이렇게 등록하면,

실제 git에서 어떤 계정으로 연결할지 모른다.

즉, 아래 나오겠지만 ssh-add -l 을 하면 github 의 ssh key가 2개 나온다.

( 어떤것을 선택할 지 몰라서 될때도 있고 안될때도 있다.)

 

따라서, 아래와 같이 해야 한다.

( 아래 녹색부분은 config 화일에 host로 구분해둔 이름이다.)

 

user1 에서는...

git remote add origin git@github-user1:user1/git_training.git

 

user2 에서는...

git remote add origin git@github-user2:user2/git_training.git

 

이렇게 하면 각각의 user1, user2 에서 각각 git init 을 하였을 것이니,

해당 git 환경에서 따로 remote 에 access한다.

 

권한 오류가 날때....

사실 ssh-add는 해줘야 한다. ( 오류날때 하는 것이 아니다.)

 

ssh-add 와 file permission 을 확인.

ssh agent에 위에서 작업한 사항이 반영되도록 ssh-add 명령어를 통해 등록한다.

먼저 이전에 등록된 대상이 garbage로 있을수 있다.

이것들 때문에 잘 안되는데 해결 못하는 경우가 많다.

( 안해도 되지만 잘 안될때는 아래 ssh-add -D로 캐쉬를 제거한 후 진행해보는 거도 좋다.)

 

먼저 file permission

chmod 600 id_rsa* // id_rsa, id_rsa.pub 2개 permission 변경

chmod 644 config // config file permission 변경

 

ssh-add -D // 기존 ssh 등록분 메모리에서 제거

ssh-add /Users/XXXXX/.ssh/github-key/user1/id_rsa  // 등록

ssh-add -l  // 등록된거 조회 ( 뭔가 보이면 됨. )

 

ssh -vvv -T github-user1 // 테스트( config 화일의 호스트이름으로 테스트 )

 

참고) set-url

git 에서 직접 remote setting 시에도 아래처럼 host-in-ssh-config 처럼 하여

remote 를 변경할 수 있다. 참고할것.( host-in-ssh-config 는 config에 등록한 호스트 이름이다.)

 

git remote set-url origin git@<host-in-ssh-config>:<username>/<repo>

( 참고) <username>/<repo> 는 github에서도 copy & paste 할수 있도록 되어 있다.

  기본적으로 github repo 주소는, git@github.com( 이까지는 동일 ) + ":" + username/repository이름의 형식이다.
  즉, git@github.com:newbiestory/helloworld.git 이런 형식이다. )

Local git 환경 설정

이제 여러 계정으로 동일 repository에 접속하든 다른 repository에 접속하든,

나의 local PC 한개에서 여러개를 처리해야 한다.

따라서 global config는 지양한다.

 

cd user1 // 처음 repository 만든 위치

git config user.name "user1"

git config user.email "user1@xxx.com"

 

cd user2 // 이것도 user1과 동일한 방식으로 진행( git 설정까지 모두 )

git config user.name "user2"

git config user.email "user2@xxx.com"

 

이렇게 하면 ...

user1 에서 작업하면 user1 commit log

user2 에서 작업하면 user2 commit log 가 생기고

 

서로 user1, user2 독립된 git 환경에서 작업이 가능해 진다.

 

끝.

'개발환경 > GIT' 카테고리의 다른 글

Git 명령어  (0) 2019.04.07

Sublime Text로 개발하기

  1. 일단 다운로드 하고 설치한다.
  2. 사용법을 익힌다.
  3. 참조할 사이트는 https://www.lesstif.com/pages/viewpage.action?pageId=9437318#SublimeText3%EC%84%A4%EC%B9%98%EB%B0%8F%EC%84%A4%EC%A0%95-Packagecontrol%EC%84%A4%EC%B9%98
  4. 잘 정리되어 있다.

유용한 Tips

  1. control + ` : 
  2. command + shift + P : 명령창 ( 요거는 꼭 외울것 )
  3. fast file switching : command + p ( 파일명을 빨리 찾을때 매우 유용함 )


+ Recent posts