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

Publication

Category

Recent Post

2013. 1. 29. 21:57 NodeJS/Prototyping

Node.js를 설치하고 MongoDB를 사용하여 REST API를 만들어보자. native MongoDB driver를 사용하며 REST API를 쉽게 만들기 위하여 Node.js의 웹애플리케이션 프레임워크인 Express를 이용한다. 원문의 내용을 보고 수행한 결과를 요약한다 



1) Node.js 설치 

  - http://nodejs.org/dist/  : 사이트에서 최신 버전을 선택하여 다운로드한다 

  - 예) linux 

[mongodb@localhost ~]$ wget http://nodejs.org/dist/v0.9.8/node-v0.9.8-linux-x86.tar.gz 

--2013-02-01 21:24:48--  http://nodejs.org/dist/v0.9.8/node-v0.9.8-linux-x86.tar.gz

Resolving nodejs.org... 165.225.133.150

Connecting to nodejs.org|165.225.133.150|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 4491882 (4.3M) [application/octet-stream]

Saving to: “node-v0.9.8-linux-x86.tar.gz”


100%[=========================================================>] 4,491,882    284K/s   in 17s     


2013-02-01 21:25:07 (263 KB/s) - “node-v0.9.8-linux-x86.tar.gz” saved [4491882/4491882]


[mongodb@localhost ~]$ ls

aggregation  mongo  mongod  mongodb  mongofiles  mongos  node-v0.9.8-linux-x86.tar.gz  shard

[mongodb@localhost ~]$ tar zxf node-v0.9.8-linux-x86.tar.gz

[mongodb@localhost ~]$ ls

aggregation  mongod   mongofiles  node-v0.9.8-linux-x86         shard

mongo        mongodb  mongos      node-v0.9.8-linux-x86.tar.gz

[mongodb@localhost ~]$ rm node-v0.9.8-linux-x86.tar.gz

[mongodb@localhost ~]$ mv node-v0.9.8-linux-x86 node-v0.9.8

[mongodb@localhost ~]$ ls

aggregation  mongo  mongod  mongodb  mongofiles  mongos  node-v0.9.8  shard

[mongodb@localhost ~]$ cd node-v0.9.8/

[mongodb@localhost node-v0.9.8]$ cd bin

[mongodb@localhost bin]$ ./node -v

v0.9.8


2) Node.js 수행하기 

  - 적당한 디렉토리에 nodecellar 디렉토리 만듦

  - nodecellar 안에 server.js 파일 생성

  - server.js 코딩 

////////////////////////////////////////////////
// server.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');


  - server.js 수행하고 브라우져에서 http://127.0.0.1:3000/ 호출 

[mongodb@localhost ~]$ cd nodecellar/

[mongodb@localhost nodecellar]$ node server.js

Server running at http://127.0.0.1:3000/



3) Express 설치하기 

  - Node.js의 Web Application Framework 이고, REST API 생성을 쉽게 해준다 

  - nodecellar 디렉토리안에 package.json 파일을 만들어서 Node.js가 의존하는 모듈을 정의한다 

////////////////////////////////////////////
// package.json
{
    "name": "wine-cellar",
    "description": "Wine Cellar Application",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "express": "3.x"
    }
}

  - express 설치하기 

// package.json의 의존관계 모듈을 읽어서 자동 설치해 준다 

[mongodb@localhost nodecellar]$ npm install

npm WARN package.json wine-cellar@0.0.1 No README.md file found!

npm http GET https://registry.npmjs.org/express

npm http 200 https://registry.npmjs.org/express

npm http GET https://registry.npmjs.org/express/-/express-3.1.0.tgz

... 중략 ...
express@3.1.0 node_modules/express
├── methods@0.0.1
├── fresh@0.1.0
├── range-parser@0.0.4
├── cookie-signature@0.0.1
├── buffer-crc32@0.1.1
├── cookie@0.0.5
├── commander@0.6.1
├── debug@0.7.0
├── mkdirp@0.3.3
├── send@0.1.0 (mime@1.2.6)
└── connect@2.7.2 (pause@0.0.1, bytes@0.1.0, formidable@1.0.11, qs@0.5.1)



4) server.js를 Express 형식으로 바꾸기 

  - express 프레임워크를 이용하여 HTTP Listener를 바꾼다

////////////////////////////////////////////
// server.js
var express = require('express');
 var app = express();
 
app.get('/wines', function(req, res) {
    res.send([{name:'wine1'}, {name:'wine2'}]);
});
app.get('/wines/:id', function(req, res) {
    res.send({id:req.params.id, name: "The Name", description: "description"});
});
 
app.listen(3000);
console.log('Express Listening on port 3000...');

  - express 실행

[mongodb@localhost nodecellar]$ node server

Express Listening on port 3000...


  - 브라우져 호출하기 

    + 전체 wine들 

  

    + 1번 wine 내역 

  


5) Node.js에서 Controller로써 routes를 만들기 

  - nodecellar 디렉토리 밑으로 routes 폴더를 만든다 

  - routes 밑에 모듈로 wines.js 를 만든다 

////////////////////////////////////////////
// routes 디렉토리 밑의 wines.js
exports.findAll = function(req, res) {
    res.send([{name:'wine1'}, {name:'wine2'}, {name:'wine3'}]);
};
 
exports.findById = function(req, res) {
    res.send({id:req.params.id, name: "The Name", description: "description"});
};


  - server.js 파일에서 wines.js 모듈을 로딩하게 한다. 그리고 다시 브라우져로 호출한다 

////////////////////////////////////////////
// server.js에서 wines.js 모듈 로딩
var express = require('express'),
    wines = require('./routes/wines');
var app = express();
 
app.get('/wines', wines.findAll);
app.get('/wines/:id', wines.findById);
 
app.listen(3000);
console.log('Express Listening on port 3000...');


6) MongoDB Driver 설치하기 

  - MongoDB는 설치되어 있다고 가정한다 (참조)

  - 여기서는 native Node.js driver를 사용한다

  - mongodb driver 설치하기 

[mongodb@localhost nodecellar]$ npm install mongodb

npm WARN package.json wine-cellar@0.0.1 No README.md file found!

npm http GET https://registry.npmjs.org/mongodb

...  중략 ...

npm http GET https://registry.npmjs.org/bson/-/bson-0.1.6.tgz

... 중략 ...

node-gyp clean

node-gyp configure build

gyp http GET http://nodejs.org/dist/v0.9.8/node-v0.9.8.tar.gz

gyp http 200 http://nodejs.org/dist/v0.9.8/node-v0.9.8.tar.gz

make[1]: Entering directory `/home/mongodb/nodecellar/node_modules/mongodb/node_modules/bson/build'

  CXX(target) Release/obj.target/bson/ext/bson.o

  SOLINK_MODULE(target) Release/obj.target/bson.node

  SOLINK_MODULE(target) Release/obj.target/bson.node: Finished

  COPY Release/bson.node

make[1]: Leaving directory `/home/mongodb/nodecellar/node_modules/mongodb/node_modules/bson/build'

child process exited with code 0

mongodb@1.2.11 node_modules/mongodb

└── bson@0.1.6



7) REST API 정의하기 

  - 호출 내역 

    + GET: 전체 wine 목록

    + GET: id로 선택된 wine 정보얻기 

    + POST: 새로운 wine 생성

    + PUT: id로 선택된 wine 정보갱신

    + DELETE: id로 선택된 wine 삭제하기 

  

  

  - server.js에서 wines.js를 확장한 메소드를 추가한다 

  - wines.js 안에 MongoDB 코드로 변경하기 



8) MongoDB 와 Node.js 수행하고 Testing 하기 

  - MongoDB는 default port로 수행한다 

[mongodb@localhost ~]$ ./mongod --dbpath /home/mongodb/aggregation

... 중략 ...

Fri Feb  1 22:30:46 [initandlisten] options: { dbpath: "/home/mongodb/aggregation" }

Fri Feb  1 22:30:46 [initandlisten] Unable to check for journal files due to: boost::filesystem::basic_directory_iterator constructor: No such file or directory: "/home/mongodb/aggregation/journal"

Fri Feb  1 22:30:46 [initandlisten] couldn't unlink socket file /tmp/mongodb-27017.sockerrno:1 Operation not permitted skipping

Fri Feb  1 22:30:46 [initandlisten] waiting for connections on port 27017

Fri Feb  1 22:30:46 [websvr] admin web console waiting for connections on port 28017



  - Node.js 수행하기 

     + MongoDB의 기본 port 27017 로 접근한다 

[mongodb@localhost nodecellar]$ node server

========================================================================================

=  Please ensure that you set the default write concern for the database by setting    =

=   one of the options                                                                 =

=                                                                                      =

=     w: (value of > -1 or the string 'majority'), where < 1 means                     =

=        no write acknowlegement                                                       =

=     journal: true/false, wait for flush to journal before acknowlegement             =

=     fsync: true/false, wait for flush to file system before acknowlegement           =

=                                                                                      =

=  For backward compatibility safe is still supported and                              =

=   allows values of [true | false | {j:true} | {w:n, wtimeout:n} | {fsync:true}]      =

=   the default value is false which means the driver receives does not                =

=   return the information of the success/error of the insert/update/remove            =

=                                                                                      =

=   ex: new Db(new Server('localhost', 27017), {safe:false})                           =

=                                                                                      =

=   http://www.mongodb.org/display/DOCS/getLastError+Command                           =

=                                                                                      =

=  The default of no acknowlegement will change in the very near future                =

=                                                                                      =

=  This message will disappear when the default safe is set on the driver Db           =

========================================================================================

Express Listening on port 3000...

Connected to 'winedb' database


  - curl을 수행한다 

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

// POST를 통하여 신규 wine을 생성한다

[mongodb@localhost ~]$ curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "New Wine", "year": "2009"}' http://localhost:3000/wines

HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 79

Date: Sat, 02 Feb 2013 06:38:49 GMT

Connection: keep-alive


{

  "name": "New Wine",

  "year": "2009",

  "_id": "510cb4798859a9b51d000001"


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

// MongoDb 확인 

[mongodb@localhost ~]$ mongo

MongoDB shell version: 2.2.2

connecting to: test

> show dbs

dowonDB 0.03125GB

local (empty)

winedb 0.0625GB

> use winedb

switched to db winedb

> show collections

system.indexes

wines

> db.wines.find()

{ "name" : "New Wine", "year" : "2009", "_id" : ObjectId("510cb4798859a9b51d000001") }


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

// GET 명령 수행하여 정보 조회

// wine 목록을 얻어온다.

[mongodb@localhost ~]$ curl -i -X GET http://localhost:3000/wines

HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 93

Date: Sat, 02 Feb 2013 06:41:37 GMT

Connection: keep-alive


[

  {

    "name": "New Wine",

    "year": "2009",

    "_id": "510cb4798859a9b51d000001"

  }

]


// 특정 wine 조회. _id를 넣어준다 

[mongodb@localhost ~]$ curl -i -X GET http://localhost:3000/wines/510cb4798859a9b51d000001

HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 79

Date: Sat, 02 Feb 2013 06:42:14 GMT

Connection: keep-alive


{

  "name": "New Wine",

  "year": "2009",

  "_id": "510cb4798859a9b51d000001"



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

// PUT 명령 수행하여 정보 수정 

[mongodb@localhost ~]$ curl -i -X PUT -H 'Content-Type: application/json' -d '{"name": "New Wine", "year": "2010"}' http://localhost:3000/wines/510cb4798859a9b51d000001
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 42
Date: Sat, 02 Feb 2013 06:44:00 GMT
Connection: keep-alive

{
  "name": "New Wine",
  "year": "2010"


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

// DELETE 명령 수행하여 정보 삭제

[mongodb@localhost ~]$ curl -i -X DELETE http://localhost:3000/wines/510cb4798859a9b51d000001
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 2
Date: Sat, 02 Feb 2013 06:46:22 GMT
Connection: keep-alive

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

// MongoDb 확인 

[mongodb@localhost ~]$ mongo
MongoDB shell version: 2.2.2
connecting to: test
> use winedb
switched to db winedb
> show collections
system.indexes
wines
> db.wines.find()    <=== 데이터가 삭제되어 없음 



<참조>

  - 원문 : Creating a REST API using Node.js, Express, and MongoDB

  - 참조 

    + https://speakerdeck.com/jakobmattsson/writing-restful-web-services-using-nodejs

    + Node.js 설치하기

    + MongoDB 설치하기

  - 심화 : Backbone.js 와 Bootstrap, Node.js로 만들기 

posted by 윤영식
2013. 1. 29. 21:48 Languages/CoffeeScript

정규표현식과 html안에 .coffee 확장자로 작성한 스크립트를 포함시키는 방법에 대하여 알아보자 


1) 정규 표현식 

  - /// .....  ///   슬래쉬3개 앞뒤로 하여 그사이에 표현식을 넣는다 

//////////////////////////////////////////
// regex.coffee
emails = ['ysyun@yuwin.co.kr', 'nulpulum@gamil.com', 'joe.567@gmail.com', 'andrew']

emailRegex = ///
	([\w\.+-]+) 	# unique name
	@				# at-sign
	(\w+)			# domain name
	(\.\w+[\w\.]*)  # tld
///

for email in emails
	match = email.match emailRegex
	if match?
		console.log "#{email} matched"
	else
		console.log "#{email} didn't matched"

//////////////////////////////////////////
// 컴파일 내역
// Generated by CoffeeScript 1.4.0
var email, emailRegex, emails, match, _i, _len;
emails = ['ysyun@yuwin.co.kr', 'nulpulum@gamil.com', 'joe.567@gmail.com', 'andrew'];
// 한줄로 표현된다 
emailRegex = /([\w\.+-]+)@(\w+)(\.\w+[\w\.]*)/;

for (_i = 0, _len = emails.length; _i < _len; _i++) {
  email = emails[_i];
  match = email.match(emailRegex);
  if (match != null) {
    console.log("" + email + " matched");
  } else {
    console.log("" + email + " didn't matched");
  }
}


2) Coffeescript를 컴파일한 Javascript 파일을 포함한 경우의 html

  - src/dom.coffee 파일 작성

  - js/ 디렉토리 밑으로 컴파일된 .js 위치 : coffee -c --watch -o js src/dom.coffee

    + --watch 옵션 : 변경내용을 감시하여 자동 재컴파일 수행 

  - 브라우저에서 웹서버 도움없이 바로 index.html 파일을 호출하면 된다. 

    + 단, jquery.js 파일은 동일 디렉토리에 위치 (첨부파일 참조)

//////////////////////////////////////////
// index.html 파일 
<!DOCTYPE html>
<html>
	<head>
		<title> CoffeeScript in the Browser </title>
	</head>
	<body>
		<div id="menu">
			<div>Tools</div>
			<div id="dropdown">
				<ul>
					<li>Tool 1</li>
					<li>Tool 2</li>
					<li>Tool 3</li>
				</ul>
			</div>
		</div>
		<script src="jquery.js"></script>
		<script src="js/dom.js"></script> <!-- 컴파일한 dom.js 파일을 포함시킨다 -->
	</body>
</html>  
// dom.coffee 파일로 jquery 기반 코딩
$ -> 
	menu = $ '#menu'
	dropdown = $ '#dropdown'
	dropdown.hide()

	menu.on 'mouseover', (e) -> dropdown.stop().show 200
	menu.on 'mouseout', (e) -> dropdown.stop().hide 200

//////////////////////////////////////////
// 컴파일 내역
$(function() {
  var dropdown, menu;
  menu = $('#menu');
  dropdown = $('#dropdown');
  dropdown.hide();
  menu.on('mouseover', function(e) {
    return dropdown.stop().show(200);
  });
  return menu.on('mouseout', function(e) {
    return dropdown.stop().hide(200);
  });
});


3) dom.coffee 파일을 직접 html안에 포함시키기 

  - html안에 coffee-script.js 파일을 포함시킨다 (첨부파일 참조)

    + 다운로드 한 파일의 extras 디렉토리 파일임

  - dom.coffee 파일을 포함시키고 type="text/coffeescript" 타입을 넣는다 

//////////////////////////////////////////
// index2.html 파일 
<!DOCTYPE html>
<html>
	<head>
		<title> CoffeeScript in the Browser </title>
	</head>
	<body>
		<div id="menu">
			<div>Tools</div>
			<div id="dropdown">
				<ul>
					<li>Tool 1</li>
					<li>Tool 2</li>
					<li>Tool 3</li>
				</ul>
			</div>
		</div>
		<script src="jquery.js"></script>
		<script src="coffee-script.js"></script>  <!-- 컴파일한 coffee-script.js 파일을 포함 -->
		<script src="src/dom.coffee" type="text/coffeescript"></script>  <!-- dom.coffee 포함 -->
	</body>
</html>  

  - 브라우져에서 로컬파일을 불러오게 되면 오류가 발생한다

  - 실행방법 : 웹서버 구동하여 브라우져에서 호출 

    + node-static 을 설치한다 (블로그 참조)

    + $ static : dom.coffee 파일이 있는 곳에서 수행 (8080 포트로 브라우저에서 호출함)

     


  - 최종 파일 구조     

    

 

* 파일 

coffeescript-5.zip



<참조>

  - 자바스크립트 정규표현식

posted by 윤영식
2013. 1. 28. 17:48 Dev Environment/Build System

이전에 Ant를 이용하여 Javascript project를 build하는 것을 알아 보았다. 요즘은 Grunt.js라는 빌드도구가 나와서 많이 사용되고 있고, Javascript 에 최적화 되어 있기때문에 앞으로는 Grunt.js를 사용한다. Grunt.js에 대해서 알아보자 


1) 준비하기

  - node.js 와 npm 설치되어 있어야 한다 

  - 기본 설치 : npm uninstall -g grunt  ==> npm install -g grunt-cli

  - 부가 설치 : npm install grunt-contrib

  - grunt.js (gruntfile)이 핵심 구성내역

    + 프로젝트 환경

    + grunt plugins 또는 tasks 폴더 로딩

    + Tasks 와 Helpers



2) Task 만들기 

  - 환경파일 만들기 (node.js 모듈로 생성) :  grunt init:gruntfile  명령 수행하면 Gruntfile.js 파일 생성됨(grunt 환경파일)

    + 윈도우 : grunt.cmd init:gruntfile 수행

  - grunt.js 파일안에 task 열거 lint, qunit, concat, min, watch, jshint, testuglify

    + lint : 자바스크립트 문법오류 가능성 있는 것 체크

    + qunit : Unit test를 위하여 QUnit을 사용 (PhantomJS이용)

    + concat : 지정된 디렉토리/파일을 1개의 파일로 합침

    + min : 파일사이즈 minify 최소화

    + mincss : css 최소화 

    + watch : node.js::fs 모듈의 watch 메소드 사용하여 파일 변경사항 발생시 task를 수행한다 

    + 사용가능 task 목록 보기 : grunt -h 


// grunt.js 파일 내역 
/*global module:false*/
module.exports = function(grunt) {
  // Project configuration.
  grunt.initConfig({
    pkg: '',
    meta: {
      banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
        '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
        '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' +
        '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
        ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
    },
    lint: {
      files: ['grunt.js', 'lib/**/*.js', 'test/**/*.js']
    },
    qunit: {
      files: ['test/**/*.html']
    },
    concat: {
      dist: {
        src: ['', '.js>'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    min: {
      dist: {
        src: ['', ''],
        dest: 'dist/<%= pkg.name %>.min.js'
      }
    },
    watch: {
      files: '',
      tasks: 'lint qunit'
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        browser: true
      },
      globals: {}
    },
    uglify: {}
  });

  // Default task.
  grunt.registerTask('default', 'lint qunit concat min');
};

  - module.exports = function(grunt){...}; 를 딱 한번만 grunt.js 에 표기한다 (module.exports 참조)

    + 가급적 module.exports를 사용한다 (exports 사용안함)

  - grunt.initConfig({...}); 에 환경설정 한다 

  - 환경 설정 참조 파일 : javascript-hooker/grunt.js

  - 일반 설정 사항

// Project configuration.
grunt.initConfig({
  // Project metadata, used by some directives, helpers and tasks.
  meta: {},
  // Lists of files to be concatenated, used by the "concat" task.
  concat: {},
  // Lists of files to be linted with JSHint, used by the "lint" task.
  lint: {},
  // Lists of files to be minified with UglifyJS, used by the "min" task.
  min: {},
  // Lists of files or URLs to be unit tested with QUnit, used by the "qunit" task.
  qunit: {},
  // Configuration options for the "server" task.
  server: {},
  // Lists of files to be unit tested with Nodeunit, used by the "test" task.
  test: {},
  // Configuration options for the "watch" task.
  watch: {},
  // Global configuration options for JSHint.
  jshint: {},
  // Global configuration options for UglifyJS.
  uglify: {}
});

  - plugins 또는 task를 로딩한다

// TASK
// Load tasks and helpers from the "tasks" directory, relative to grunt.js.
grunt.loadTasks('tasks');

// PLUGIN
// Load tasks and helpers from the "grunt-sample" Npm-installed grunt plugin.
grunt.loadNpmTasks('grunt-sample');


3) 사용하기 : grunt <task>

  - lint 수행 : grunt lint 

  - min 수행 : grunt min 

  - grunt 명령으로 default 수행 만들기 : grunt.registerTask('default', 'lint test concat min mincss'); 



4) Grunt.js & Yeoman 이해하기 


<참조>

  - Grunt.js Getting Started

  - Grunt.js 소개

  - 사용하기 : Outsider님 블로깅

posted by 윤영식
2013. 1. 28. 10:12 Git, GitHub/Git Lec02

비공개 대규모 팀을 운영할 때는 Git Workflow에서 Integration-Manager 방식을 선택한다. 이는 팀별로 별도의 Master를 두고 Integration Manager가 중앙 Master로 push할 수 있는 권한을 갖도록 한다. 즉, 중간 단계의 master가 하나 더 있는 구조이다. 


1) 가정

  - 갑순이는 두 팀에 속한다 

  - 1팀 갑순이 + 갑돌이

  - 2팀 갑순이 + 갑복이 



2) 1팀 갑순이 featureA만들어 갑돌이와 작업

  - 갑순이는 저장소를 clone하고 featureA 브랜치를 만들고 수정후 커밋한다 

    + feautreA 브랜치 생성 : git checkout -b featureA

    + 커밋 : git commit -am "add function"


  - 갑순이가 해당 브랜치를 갑돌이와 공유하려 한다. 

    + 여기서 갑순이는 Integration Manager가 아니다

    + 갑순이는 운격 저장소에 featureA로 push 하고 갑돌이에게 해당 사실을 알린다 



3) 2팀 갑순이 featureB 브랜치 만들어 갑복이와 작업

  - 갑순이는 갑복이와 원격 저장소의 master 브랜치를 기반으로 featureB작업을 계속 수행하기로 한다

    + 원격저장소에서 로컬 저장소로 fetch 하기 : git fetch origin

    + git checkout -b featureB origin/master


  - 갑순이가 몇가지 작업을 하고 featureB에 커밋을 한다 

    + git fetch origin

    + git checkout -b featureB origin/master

    + 2번의 커밋객체 생성 : git commit -am "modified some function" (e5b0f) -> git commit -am "add new function" (85127)


  


   [그림 5.12] 갑순이 현재 로컬 저장소 커밋 그래프


  - 갑순이 featureB를 push 하려는데 갑복이로부터 이미 featureBee 브랜치로 한번 push 했다고 연락을 받는다

    + 갑복이 내역을 merge 하기위해 fetch 한다 : git fetch origin

    + 갑복이 브랜치를 merge 한다 : git merge origin/featureBee

 

  - 갑순이 이제 featureB를 원겨 저장소로 push 하려는데 갑복이 featureBee 와 이름이 틀리다

    + 로컬 featureB를 원격 featureBee로 push 한다 : git push origin featureB:featureBee (cd685)



4) 1팀 갑돌이 featureA 작업

  - 갑돌이 featureA 작업후에 push 했고 갑순이에게 확인요청한다 

  - 갑순이는 내역확인을 위하여 원격저장소에서 fetch 한다 : git fetch origin 

  - 갑순이는  featureA 브랜치에 어떤 것이 업데이트 되었는지 확인한다 (갑돌이 커밋시 메시지 잘 입력했다 가정함)

    + 변경내역 확인 : git log origin/featureA ^featureA 

    + 확인후 로컬 featureA 브랜치로 이동 : git checkout featureA

    + 원격 featureA를 로컬 featureA에 merge 수행 : git merge origin/featureA

  

  - 갑순이 다시 일부 수정하여 featureA 브랜치를 원격 저장소로 push 한다 

    + git commit -am "small tweak"

    + git push origin featureA (774b3)

    + 갑순이의 저장소를 보자 


  


  [그림 5.13] featureB도 원격으로 push하고 featureA도 원격 저장소로 push한 갑순이 로컬 저장소 



5) 갑순이 메인 브랜치로 merge 요청작업 

  - Integration-Manager는 두 브랜치를 merge 하고 메인 브랜치의 커밋 (5399e) fetch해 온다 

  - 다음과 같은 구조가 될 것이다 


  


  [그림 5.14] integration manager는 774b3 과 ce685 커밋을 merge하여 5399e를 원격저장소에 커밋한 후 갑순이가 fetch 함!



<참조>

  - Pro Git 5장 108p

posted by 윤영식
2013. 1. 28. 09:50 Git, GitHub/Git Lec02

소규모 팀으로 일을 할때 어떤 절차에 의해서 소스를 Merge하고 원격저장소로 Push 할 수 있는지 알아보자. 팀원간 Git 기본 workflow로써 가장 기본적으로 숙지해야할 사항이라 판단된다. 


1) 가정 

  - 3~5명이 하나의 원격 Git - 예, GitHub Private Repository - 에 원본을 합친다 

  - 각자가 local repositor로 내려 받아서 작업을 한다 


2) 갑순이 push 작업

  - 갑순이가 GitHub에서 저장소를 복제한다 : git clone <git address>

  - 갑순이가 하나의 파일에 대해서 수정하고 commit 한다 : git commit -am "modified files"

  - GitHub에 변경된 파일을 push 한다 : git push origin master


3) 갑돌이 push 작업

  - 갑돌이도 GitHub에서 저장소를 복제한다 

  - 값돌이도 다른 파일 하나를 수정하고 commit 한다 

  - GitHub에 변경된 파일을 push 한다 => 오류가 발생하여 파일 push를 하지 못한다 


4) 갑돌이 push 오류 해결하기 

  - 갑돌이는 Push 하기전 원격저장소의 갑순이 commit 내역을 로컬 저장소에 merge 해야 한다 

  - 갑돌이는 먼저 원격 저장소의 내용을 fetch 한다 : git fetch origin

  

   


   [그림 5.4] origin에서 fetch를 하면 origin/master가 된다(fbff5) 로컬의 master (738ee)와 merge는 안된 상태

  

  - 로컬 master와 원격 origin/master를 merge 한다 : git merge origin/master

  - 갑돌이는 merge를 완료하고 push를 재시도 한다 : git push origin master  (origin master 생략가능)


  


  [그림 5.5] merge를 했을 때 새로운 commit object가 생성된다 (72bbc)



  


  [그림 5.6] push를 하게되면 origin/master의 위치도 최신 commit object를 가르키게 된다 (72bbc)



5) 갑순이 branch 생성후 push 추가작업

  - 갑순이는 이슈해결을 위하여 별도 issue54 브랜치를 만들었다

  - issue54 브랜치에 대해서 3개의 commit을 수행하였다. 

  - 원격으로 push 하기 위하여 먼저 원격의 갑돌이 push 내역을 fetch 한다 : git fetch origin


  


  [그림 5.8] fetch하여 원격의 origin/master를 가져온다 (72bbc)


  - fetch 해온 origin/master 와 merge할 내용을 확인한다 : git log --no-mergs origin/master ^issue54

  - merge를 위하여 master 브랜치로 checkout 한다 : git checkout master

  - 먼저 issue54 부터 merge 한다 : git  merge issue54

    origin/master 와 issue54 브랜치는 모두 master 보다 fast-forward 된 브랜치 이기 때문에 순서에 상관없이 merge해도 된다

  - 다음 origin/master 를 merge 한다 : git merge origin/master


  


  [그림 5.9] local의 issue54를 merge하고, origin/master와 merge를 하면 새로운 commit object가 생성된다 (8059c)


  - 로컬 저장소에 모드 merge 되었으므로 원격 저장소로 push 한다 : git push origin master 


  


  [그림 5.10] push를 하게되면 origin/master가 가르키는 commit object는 최신 8059c 가 된다. 



6) 최종 Workflow 모습

  - 갑순이 == Jessica

  - 갑돌이 == John


   


  [그림 5.11] push -> fetch -> merge -> push 작업이 이루어진다     


<참조>

  - Pro Git : 5장 page 104

posted by 윤영식