블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

웹애플리케이션을 개발하기 위한 최신 기술셋을 알아보자. 모바일 컨버전스 솔루션 또는 서비스를 개발하기 위하여 방향전환을 시도중이다. 14년을 Java만 사용하다가 이제 다시 Reset 하는 기분으로 스터디중이랄까... 기본 언어가 자바스크립트이기 때문에 틈틈히 언어 공부도 필요하다. 하기 작성된 목록은 원문의 내용중 눈에 띄는 것을 임으로 정리한 것이다. 


1) Node.js 

  - 생태계가 잘 갖추어져 가고 있다 : modulesresources

  - 특징 : single-threaded, event-driven, asychronous I/O JavaScript Server Framework 

  - twitter list 팔로잉해서 최신 정보를 받자 

  - Logging, Error Handling, Bootup&Restart, Hosting 등의 해결책을 제시하고 있다 


2) JavaScript 

  - Node를 하려면 기본적으로 숙달해 있어야 한다 (JavaScript: The Definition Guide 추천 - 번역서 나왔음 6th)

  - DailyJS 통하여 최신 정보도 숙지한다 


3) CoffeeScript

  - .coffee 확장자로 코딩하여 .js로 컴파일 된다

  - 코드가 깔끔해 지고 유지보수성이 높아진다 

  - CoffeeScript의 스타일 가이드 참조 (참조2)

  - JavaScript를 CoffeeScript로 전환 툴

  - cake.coffee 툴 : CoffeeScript로 작성한 make 버전이다. CLI 방식 호출 (참조)


4) MongoDB

  - NoSQL : JSON방식 데이터 통신, 저장은 BSON(Binary JSON) 형태, JavaScript언어로 제어 

  - Replication Set 을 통한 High Availability 제공

  - Sharding을 통한 Scale-out을 제공

  - Aggregation Framework을 통하여 Big Data 제어 


5) Web Application 개발

  - Node에서는 Jade(Template Engine)사용, CSS는 stylus 사용함 

  - jQuery 기본 사용

  - UI MV* Framework으로 Backbone.js가 대세 - underscore.js를 기본사용함 -

  - Express : Node 에서 기본사용하는 MVC Framework - REST Web Services 개발함 - 


6) Testing 

  - Jasmine : BDD 

  - Vows : 비동기 BDD

  - QUnit : jQuery Javascript library


7) 통합 해주는 것들 

  - Express 개발할 때 : Express Wiki

  - CoffeeScript, Express, Jade, Stylus에 대한 boilerplate 코드 생성 : Cham

 

8) 추가적인 것들

  - socket.io : 실시간 구현

  - meteor : 실시간 서버 프레임워크 

  - 모바일 프레임워크 : PhoneGap


위의 내용들이 대충 눈에 들어오면 SKT의 CornerStone Framework을 내가 생각하는 모바일 컨버전스 솔루션이나 서비스에 접목 시켜 볼까 한다. 맨땅에 해딩하지 말고 이미 만들어진 것을 사용 목적에 맞게 수정하여 써보는 방향을 택한다. 실력이 된다면 기여자가 되보고 싶다. 



<참조>

  - 원문 : Getting Started With Node.js, Coffeescript, MongoDB, and More

posted by 윤영식
2013. 1. 31. 10:08 Dev Environment/Build System

Grunt의 API를 사용하여 Task를 만들어 보자. Grunt의 Task가 핵심으로 한개를 수행하거나 여러개를 동시에 수행할 수도  있다. 


1) Task 별칭 등록하기 

  - grunt.registerTask 로 Task의 별칭을 지정한다

    + api : grunt.registerTask(taskName, taskList)

    + 예 : task.registerTask('default', 'lint qunit concat min'); 

    + grunt 수행시 특정 task를 지정하지 않으면 자동으로 default 별칭의 task가 수행된다 


2) Function Task 만들기

  - grunt.regiterTask 로 Task를 신규로 만들 수 있다

    + api : grunt.registerTask(taskName, description, taskFunction)

    + description, taskFunction을 파라미터로 넘기면 새로운 task 등록됨 

    + fail이 나면 return false 를 해야 한다 

//////////////////////////////////////////////
// grunt.js 환경파일에 등록한다 
  grunt.registerTask('dowon', 'A sample task that logs stuff.', function(arg1, arg2) {
    if (arguments.length === 0) {
      grunt.log.writeln(this.name + ", no args");
    } else {
      grunt.log.writeln(this.name + ", " + arg1 + " " + arg2);
    }
  });

//////////////////////////////////////////////
// 결과
// 아규먼트 없을 때
D:\Development\testing_grunt>grunt.cmd dowon
Running "dowon" task
dowon, no args
Done, without errors.

// 아규먼트 전달 : 이용 
D:\Development\testing_grunt>grunt.cmd dowon:hello:youngsik
Running "dowon:hello:youngsik" (dowon) task
dowon, hello youngsik
Done, without errors.


3) Multi Task 만들기 

  - grunt.registerMultiTask 를 이용하여 만든다

    + api : grunt.registerMultiTask(taskName, description, taskFunction)

    + lint, concat, min task등이 multi task이다 

    + sub-properties (별칭 targets) 이 내부적으로 task가 된다

    + multi task에서는 function에서 특별히 this 키워드를 사용하여 접근한다 

  - grunt.initConfig 안에 target을 만든다 객체명칭 = multi task의 대표 명칭이다 

    + 하기 예제에서 logstuff 가 multi task의 대표명칭이다 

    + grunt.registerMultiTask의 첫번째 아규먼트인 multi task 명칭을 logstuff 로 일치시킨다 

    + 등록한 function에서 this 함에 주의*

//////////////////////////////////////////////
/*global config:true, task:true*/
grunt.initConfig({
  logstuff: {
    foo: [1, 2, 3],
    bar: 'hello world',
    baz: false
  }
});

grunt.registerMultiTask('logstuff', 'This task logs stuff.', function() {
  // this.target === the name of the target
  // this.data === the target's value in the config object
  // this.name === the task name
  // this.args === an array of args specified after the target on the command-line
  // this.flags === a map of flags specified after the target on the command-line
  // this.file === file-specific .src and .dest properties

  // Log some stuff.
  grunt.log.writeln(this.target + ': ' + this.data);

  // If data was falsy, abort!!
  if (!this.data) { return false; }
  grunt.log.writeln('Logging stuff succeeded.');
});

//////////////////////////////////////////////
// 결과
// target을 지정하지 않았을 때는 전체 target이 수행
D:\Development\testing_grunt>grunt.cmd logstuff
Running "logstuff:foo" (logstuff) task
foo: 1,2,3
Logging stuff succeeded.

Running "logstuff:bar" (logstuff) task
bar: hello world
Logging stuff succeeded.

Running "logstuff:baz" (logstuff) task
baz: false
 Task "logstuff:baz" failed. Use --force to continue. 

Aborted due to warnings.

// foo target을 지정
D:\Development\testing_grunt>grunt.cmd logstuff:foo
Running "logstuff:foo" (logstuff) task
foo: 1,2,3
Logging stuff succeeded.

Done, without errors.

// bar target을 지정 
D:\Development\testing_grunt>grunt.cmd logstuff:bar
Running "logstuff:bar" (logstuff) task
bar: hello world
Logging stuff succeeded.

Done, without errors.

// baz target에서 false return하면서 warning 발생함 
D:\Development\testing_grunt>grunt.cmd logstuff:baz
Running "logstuff:baz" (logstuff) task
baz: false
 Task "logstuff:baz" failed. Use --force to continue. 

Aborted due to warnings.


4) Init Task 만들기 

  - api : grunt.registerInitTask(taskName, description, taskFunction)

    +최초에 수행되는 init task를 수행하고 별도의 환경 설정 데이터도 필요없다 


5) Task명칭 바꾸기 

  - api : grunt.renameTask(oldname, newname)



6) Inside Tasks 알아보기 

  - grunt의 this 에는 여러 유용한 properties 와 method를 가지고 있다. grunt.task.current 로 expose 한다 

  - Task에서 구현하는 function에서 사용한다 

  - this.async / grunt.task.current.async

    + task를 비동직적으로 수행시켜 준다 

//////////////////////////////////////////////
// Tell grunt this task is asynchronous.
var done = this.async();
// Your async code.
setTimeout(function() {
  // Let's simulate an error, sometimes.
  var success = Math.random() > 0.5;
  // All done!
  done(success);
}, 1000);


  - this.requires / grunt.task.current.requires : 의존관계있는 task를 열거

  - this.requiresConfig / grunt.task.current.requiresConfig : config properties 열거 

  - this.name / grunt.task.current.name : 등록된 task 명칭 

  - this.nameArgs / grunt.task.current.nameArgs : grunt뒤의 아규먼트들 예) grunt.cmd task1:foo  -> task1:foo 

  - this.args / grunt.task.current.args : task명칭을 뺀 실제 아규먼트값을 배열로 리턴

  - this.flags / grunt.task.current.flags : 아규먼트를 만들어준다 

  - this.errorCount / grunt.task.current.errorCount : task에서 발생한 에러건수 


7) Indside Multi Tasks 알아보기 

  - this.target / grunt.task.current.target : multi task에서만 사용. config data로 등록된 key (name) 값 

  - this.data / grunt.task.current.data : multi task에서만 사용. config data로 등록된 value 값

  - this.file / grunt.task.current.file : compact format 사용시 this.file.src , this.file.dest 가 만들어진다 (template api 참조)



8) 외부에서 정의된 Task 로딩하기 

  - 큰 프로젝트에서 sub 프로젝트끼리 공유하기 위하여 task와 helper 들을 만든다 

  - 여러 디렉토리에서 task를 로딩하거나 또는 Npm-installed grunt plugin 을 로딩한다 

  - task 관련 파일들 로딩하기 

    + api : grunt.loadTasks(tasksPath)

  - task와 helper 로딩하기 

    + api : grunt.loadNpmTasks(pluginName)

  - npm module 호출 

    + api : grunt.npmTasks(npmModuleName)



9) Helper 정의하고 실행하기 

  - 이미 만들어지 helper들 존재 (참조)

  - helper 만들기 

    + api : grunt.registerHelper(helperName, helperFunction)

//////////////////////////////////////////////
grunt.registerHelper('add_two_nums', function(a, b) {
  return a + b;
});

  - helper 이름 바꾸기 

    + api : grunt.renameHelper(oldname, newname)


  - helper 호출하기 

    + api : grunt .helper(helperName, [, agruments...])



10) Warning 과 Fatal Error

  - api 호출하여 화면에 출력 한다 

  - grunt.warn(error [, errorCode])

  - grunt.fatal(error [, errorCode])



<참조>

  - Grunt API

posted by 윤영식
2013. 1. 30. 21:42 Dev Environment/Sublime Text

Sublime Text 2에서 CoffeeScript를 빌드하고 Syntax Highlighting 기능을 사용하기 위하여 CoffeeScript 플러그인을 설치해 보자 


1) 플로그인 설치 

  - 하기 내역을 ctrl + `  누르면 sublime text 하단에 command 입력란이 나온다 => copy & paste => enter key를 치면 설치

  - ctrl + shift + p => install package 이동 => coffeescript 타입핑 하여 필요한 coffeescript 플로그인을 설치한다 

  - .coffee 파일을 오픈하면 Syntax Highlighting 이 되어 있다. (잘 안되면 하단의 참조 원문 보고 진행)

  - sublime text 메뉴 tool => build system => Automatic 으로 설정

import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print 'Please restart Sublime Text to finish installation


2) Short Key

alt+shift+t - Run a Cake task
alt+shift+r - Run some CoffeeScript (puts/print is available for output)
alt+shift+s - Run a syntax check
alt+shift+c - Compile a file
alt+shift+d - Display compiled JavaScript
alt+shift+l - Display lexer tokens
alt+shift+n - Display parser nodes
alt+shift+w - Toggle watch mode
alt+shift+p - Toggle output panel


<참조>

  - 설정 원문 : CoffeeScript Install Using Package Installation

  - 참조 원문 : CoffeeScript Setting

posted by 윤영식
2013. 1. 30. 16:03 NodeJS/Prototyping

한개의 Socket.io 인스턴스를 공유하여 3개의 독립적인 채팅 서버를 운영하는 방법과 Express.js 사용시 virtual host를 설정하여 sub domain을 만드는 방법을 알아본다.



1. 가정

  - mydomain.com / sub1.mydomain.com / sub2.mydomain.com 의 서로 독립적인 채팅서버 운영

  - socket.io 인스턴스는 하나만 사용하여 공유함

  - 테스트 사이트 구경하기



2. GitHub에서 소스 다운로드

  - git 기본 설치 되었음을 가정한다 (참조)

  - 각 분리된 namespace에서 Chat 애플리케이션 3개의 인스턴스를 수행할 것이다

  - 소스 설치하기 

[mongodb@localhost ~]$ git clone git://github.com/braitsch/sub.socket.io.git socket-io-example

Initialized empty Git repository in /home/mongodb/socket-io-example/.git/

... 중략 ..

Resolving deltas: 100% (56/56), done.

[mongodb@localhost ~]$ cd socket-io-example/

[mongodb@localhost socket-io-example]$ pwd

/home/mongodb/socket-io-example


///////////////////////////////////////////

// 각 분리된 namespace 존재 

[mongodb@localhost socket-io-example]$ ls 

README.md  

mydomain.com 

sub1.mydomain.com  

sub2.mydomain.com



3. mydomain.com의 app.js 와 mydomain.com/subdomain/sub1(2).js 소스이해

  - Express 사용하기 

// app.js

var exp = require('express');

var app = exp.createServer();


  - socket.io Listen 설정 : 전역(gobal)으로 Socket.IO 인스턴스에 접근하도록 선언한다 

// app.js

// create the single instance of socket.io that will be shared across all applications //

// 한개의 socket.io인스턴스를 생성하여 모든 애플리케이션간 공유한다

global.socket = require('socket.io').listen(app);

global.socket.set('log level', 1);

global.socket.set('transports', [ 'websocket', 'flashsocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']);


  - subdomain 만들기

    + virtual host로써 동작하는 subdomain 애플리케이션을 설정한다

// create subdomain applications //

app.use(exp.vhost('sub1.' + global.host, require('./subdomains/sub1')));

app.use(exp.vhost('sub2.' + global.host, require('./subdomains/sub2')));


  - 모듈 로딩하면서 수행

// finally create this application, our root server //

// chat-socket.js 파일 모듈 로딩

require('./app/config')(app, exp);

require('./app/server/router')(app);

require('./app/server/modules/chat-socket');


  - sub1(2).js 소스 : 채팅 커넥션과 메세지를 다루기위해 chat-socket을 포함한 Express 애플리케이션이다

var exp = require('express');

var app = exp.createServer();


app.root = global.root + '/sub1.mydomain.com';

require(app.root + '/app/config')(app, exp);

require(app.root + '/app/server/router')(app);

require(app.root + '/app/server/modules/chat-socket');

module.exports = app;



4. chat-socket.js 소스이해

  - socket.io에 네임스페이스를 '/chat'으로 정의하기 

// pwd : ./socket-io-example/mydomain.com/app/server/modules

module.exports = function()

{

// 랜덤하게 사용자 색깔 지정 

var colors = ['#AE331F', '#D68434', '#116A9F', '#360B95', '#5F209E'];

        // 사용자 커넥션 추적을 유지하기 위한 객체 생성 

var connections = { };

// if you use socket.of(), you can set namespace. 

        // chat 네임스페이스 정의하고 connect  되면 수행할 펑션들 정의 

global.socket.of('/chat').on('connection', function(socket) {

       // give each connected user a random color so it's easier to tell them apart in the chat log //

               // 채팅사용자가 준비상태 

socket.on('user-ready', function(data) {

socket.name = data.name;

socket.color = data.color = colors[Math.floor(Math.random() * colors.length)];

brodcastMessage('user-ready', data);

});


               // 메세지 전송하기 

socket.on('user-message', function(data) {

data.color = socket.color;

brodcastMessage('user-message', data);

});


                // 접속자 상태 전송 

function dispatchStatus()

{

brodcastMessage('status', connections);

}

                // 메세지 전송하기 

function brodcastMessage(message, data)

{

               // remove socket.emit if you don't want the sender to receive their own message //

socket.emit(message, data);

socket.broadcast.emit(message, data);

}

                // soket.io 커넥션 끊길 때 호출 

        // handle connections & disconnections //

connections[socket.id] = {}; dispatchStatus();

socket.on('disconnect', function() {

delete connections[socket.id]; dispatchStatus();

brodcastMessage('user-disconnected', { name : socket.name, color : socket.color });

});

});

}();


  - sub1.mydomain.com 에 대하여 네임스페이스를 틀리게 기술한다 

global.socket.of('/chat-sub1').on('connection', function(socket) ...


  - sub2.mydomain.com 에 대하여 네임스페이스를 틀리게 기술한다 

global.socket.of('/chat-sub2').on('connection', function(socket) ...



5. index.js와 index.jade 소스이해

  - index.jade 하단에 index.js 와 socket.io.js 포함 

div.navbar.navbar-fixed-top

div.navbar-inner

div.container-fluid

ul.nav.pull-left

.brand Node.js & Socket.IO Chat Server

ul.nav.pull-right

li

a(href='#')#connected


#container

#send-message.well.span4

h2 Say Something

hr

label Your Name 

input(type="text", name="name", id='name').span4

label Your Message

textarea(rows='6', name="msg", id='msg').span4

button#btn-send.btn.btn-primary

i.icon-pencil.icon-white

| Send it !

#messages.well.span4

h2 Conversation

hr

#incoming


script(src='/vendor/jquery.min.js')

script(src='/socket.io/socket.io.js')

script(src='/js/index.js')


  - index.js 파일

$(document).ready(function() {


$('#msg').focus();

        // give user a generic name to start //

        // 사용자가 접속하면 랜덤 명칭을 설정한다 

$('#name').val(Math.random().toFixed(8).toString().substr(2));

$('#btn-send').click(function(){ sendMessage(); })

$('#msg').keypress(function(e){ if (e.keyCode === 13) { sendMessage(); return false; } })


       // initialize the socket connection to listen on the 'chat' namespace //

socket = io.connect('/chat');

socket.on('status', function (connections) {

var i=0; for (p in connections) i++;

var s = i > 1 ? ' are '+i+' People ' : ' is '+i+' Person ';

$('#connected').html('There '+s+' Currently Connected');

});

socket.on('user-ready', function (data) {

$('#incoming').append('<span class="shadow" style="color:'+data.color+'">'+data.name +' :: connected</span><br>');

autoScroll();

});

socket.on('user-message', function (data) {

$('#incoming').append('<span class="shadow" style="color:'+data.color+'">'+data.name +' :: '+ data.message+'</span><br>');

autoScroll();

});

socket.on('user-disconnected', function (data) {

$('#incoming').append('<span class="shadow" style="color:'+data.color+'">'+data.name +' :: disconnected</span><br>');

autoScroll();

});


        // register the user's name with the socket connection on the server // 

socket.emit('user-ready', {name : $('#name').val() });

var autoScroll = function() { 

document.getElementById('incoming').scrollTop = document.getElementById('incoming').scrollHeight; 

}


        // 메세지 보내기 

var sendMessage = function() {

socket.emit('user-message', {name : $('#name').val() , message : $('#msg').val() });

$('#msg').val('')

}

});



7. 채팅 서비스 설정하기 

  - 채팅 서비스에 대한 수행전에 필요한 모듈에 대해서 install 한다 

///////////////////////////////////////////////////////////////

// mydomain.com 에 stylus, jade, express, socket.io 설치

// package.json 참조하여 설치함

$ cd mydomain.com 

$ npm install -d 

... 중략 ...

stylus@0.32.0 node_modules/stylus

jade@0.28.1 node_modules/jade

express@2.5.8 node_modules/express

socket.io@0.9.13 node_modules/socket.io

npm info ok 


// mydomain.com 안에 모듈 설치 디렉토리 생성

[mongodb@localhost mydomain.com]$ ll
total 20
drwxrwxr-x. 4 mongodb mongodb 4096 Feb  1 23:17 app
-rw-rw-r--. 1 mongodb mongodb 1109 Feb  1 23:17 app.js
drwxrwxr-x. 7 mongodb mongodb 4096 Feb  2 19:49 node_modules
-rw-rw-r--. 1 mongodb mongodb  590 Feb  1 23:17 package.json
drwxrwxr-x. 2 mongodb mongodb 4096 Feb  1 23:17 subdomains

//////////////////////////////////////////////////////
// sub1/sub2 도메인에 jade, stylus, express 설치 
// (socket.io는 mydomain에만 설치됨)
$ cd ../sub1.mydomain.com
$ npm install -d 
... 중략 ...
npm info prepublish sub.socket.io@1.0.0
jade@0.28.1 node_modules/jade
stylus@0.32.0 node_modules/stylus
express@2.5.8 node_modules/express


  -  /etc/hosts 파일에 다음을 설정한다 : 브라우져에서 호출하기 위한 sub1, sub2 도메인을 설정한다 

127.0.0.1 sub1.localhost

127.0.0.1 sub2.localhost



8. Chat Node Server 실행하기

  - mydomain.com 디렉토리로 들어가서 Node를 실행한다

/home/mongodb/socket-io-example/mydomain.com

[mongodb@localhost mydomain.com]$ node app

   info  - socket.io started

Express server listening on port 8080 in development mode 


  - 브라우져 2개를 띄워서 http://localhost:8080 을 동일하게 실행한다 

    + dowon 채팅창과 다른 브라우져창에서 try 명칭의 사용자가 들어왔다

    + socket.io를 통하여 채팅을 주고 받고 있다


  - 브라우져 2개를 띄워서 http://sub1.localhost:8080 을 동일하게 실행한다 (http://sub2.localhost:8080 동일 수행함)

    + youngsik 채팅창과 다른 브라우져창에서 girl 명칭의 사용자가 들어왔다

    + mydomain.com의 동일한 socket.io를 통하여 채팅을 주고 받고 있다 (namespace만 틀릴 뿐이다)



<참조>

  - 원문 : Building a Node.js Chat Application and Sharing Socket.IO Across Multiple Subdomains

  - 소스 : https://github.com/braitsch/sub.socket.io

  - Express.js Virtual Host 설정

  - 원문과 동일한 socket.io 인스턴스 한개와 Virtual Host 를 통한 SubDomain 공유에 대한 동일 예제


posted by 윤영식
2013. 1. 30. 15:36 Git, GitHub/Git Lec02

공개팀으로 Git을 운영하는데는 비공개팀과 약간의 차이가 있다. 공개팀 운영시에는 모든 사람이 공유 저장소에 대해서 쓰기 권한이 없기 때문이다. 프로젝트 관리자는  Fork를 지원하는 Git 호스팅에서 -GitHub- 기여하는 방법에 대해 가이드 해야 한다. GitHub을 예로 Pull Request는 어떤 절차로 이루어 질까?



1) 갑순이 Fork 질 하기 

  - 갑순이 중앙 저장소(예, ysyun)의 GitHub에서 Fork질 하여 자신의 원격 저장소(예, nulpulum)를 하나 만든다  

    + GitHub의 갑순이 계정으로 로그인한다 

    + GitHub의 중앙 저장소(ysyun)로 이동하여 "Fork" 버튼을 클릭하면 갑순이 계정으로 중앙 저장소(nulpulum)가 clone된다 

     

     [GitHub Fork 클릭]


  - 갑순이 원격 저장소(nulpulum)를 자신의 PC 로컬 저장소로 clone 한다 : git clone <갑순이 원격저장소>

  - 갑순이의 원격 저장소 이름을 origin에서 myfork로 바꾼다

    + git remote -v : default 설정된 origin 명칭 확인 

    + git rename origin myfork : origin을 myfork라는 이름으로 변경 



2) 갑순이 별도 브랜치 만들고 push 질 하기 

  - 갑순이 별도의 featureA 브랜치를 만들고 두번의 commit 질 한다 

    + git checkout -b featureA : featureA 만들기 

  - 간혹 commit  실수 한것은 날려 버리고 싶다 : git reset --hard HEAD^ (참조)

  - 갑순이의 원격 저장소(nulpulum)인 myfork에 featureA를 push 한다 (참조)

    + GitHub 의 commit 내역은 "Commit" 탭에서 확인가능하다 


  [GitHub Commit]


//////////////////////////////////////////

// 로컬 저장소에 새로운 브랜치 만들기 

dowon /d/git-nulpulum/jmqtt_client (master)

$ git checkout -b featureA

Switched to a new branch 'featureA'


dowon /d/git-nulpulum/jmqtt_client (featureA)

$ vi license.properties


dowon /d/git-nulpulum/jmqtt_client (featureA)

$ git commit -am "modified license 1"

[featureA 9e5ce9b] modified license 1

 1 file changed, 1 insertion(+)


dowon /d/git-nulpulum/jmqtt_client (featureA)

$ vi licene.properties


dowon /d/git-nulpulum/jmqtt_client (featureA)

$ git commit -am "modified license 2"

[featureA b3787b8] modified license 2

 1 file changed, 1 insertion(+), 1 deletion(-)


////////////////////////////////////////////

// 원격 저장소에 새로운 브랜치 만들기 

dowon /d/git-nulpulum/jmqtt_client (featureA)

$ git push myfork featureA

Username for 'https://github.com': nulpulum@gmail.com

Password for 'https://nulpulum@gmail.com@github.com':

Counting objects: 8, done.

Delta compression using up to 2 threads.

Compressing objects: 100% (4/4), done.

Writing objects: 100% (6/6), 562 bytes, done.

Total 6 (delta 2), reused 0 (delta 0)

To https://github.com/nulpulum/jmqtt_client.git

 * [new branch]      featureA -> featureA


  

 [갑순이 GitHub 저장소(nulpulum)의 featureA 브랜치]



3) 갑순이 Pull Request 질 하기 

  - 갑순이는 수정한 사항에 대하여 중앙 저장소(ysyun)의 관리자에게 Pull Request를 요청하여 자신이 수정한 것을 가져가라 알린다

    + 갑순이 GitHub 계정으로 들어가서 상단의 "Pull Request"를 클릭한다 

 

 [갑순이 GitHub 저장소(nulpulum)의 Pull Request 버튼 클릭]


    + Pull Request 원하는 브랜치를 선택한다 

    + 갑순이 원격 저장소(nulpulum)에서 featureA를 선택하고 중앙 저장소(ysyun)에게 Pull Request를 보낸다

    + featureA에 commit 두번 한것과 파일 수정 정보등이 보인다 -Commits (2) Files Chagned (1)-

  [Pull Request 요청 내역 입력한후 "Send pull request" 보내기]



    + 중앙 저장소 (ysyun)에서 Pull Request온 내역을 볼 수 있다 

 [중앙 저장소(ysyun)의 Pull Request 내역 보기]

  


  - 가급적 Pull Request를 할때는 별도의 토픽 브랜치(갑순이가 만든 featureA)와 같이 만들어서 관리자에게 요청한다 

    + master 브랜치와 구분하고 수정 내용을 거부할 때 쉽게 버릴 수 있다

  - 갑순이 다른 브랜치를 만들어서 작업할 때는 featureA에서 하지 말고 origin/master에서 한다 

    + git checkout -b featureB origin/master



<참조> 

  - Pro Git (p. 110)

  - 2개 아이디의 Public repository를 만들어서 테스트 해보았다.

posted by 윤영식