Tuesday, October 10, 2017

Git Flow: A successful Git branching model

In this post I present the development model that I’ve introduced for some of my projects (both at work and private) about a year ago, and which has turned out to be very successful. I’ve been meaning to write about it for a while now, but I’ve never really found the time to do so thoroughly, until now. I won’t talk about any of the projects’ details, merely about the branching strategy and release management.
It focuses around Git as the tool for the versioning of all of our source code. (By the way, if you’re interested in Git, our company GitPrime provides some awesome realtime data analytics on software engineering performance.)

Why git?

For a thorough discussion on the pros and cons of Git compared to centralized source code control systems, see the web. There are plenty of flame wars going on there. As a developer, I prefer Git above all other tools around today. Git really changed the way developers think of merging and branching. From the classic CVS/Subversion world I came from, merging/branching has always been considered a bit scary (“beware of merge conflicts, they bite you!”) and something you only do every once in a while.
But with Git, these actions are extremely cheap and simple, and they are considered one of the core parts of your daily workflow, really. For example, in CVS/Subversion books, branching and merging is first discussed in the later chapters (for advanced users), while in every Git book, it’s already covered in chapter 3 (basics).
As a consequence of its simplicity and repetitive nature, branching and merging are no longer something to be afraid of. Version control tools are supposed to assist in branching/merging more than anything else.
Enough about the tools, let’s head onto the development model. The model that I’m going to present here is essentially no more than a set of procedures that every team member has to follow in order to come to a managed software development process.

Decentralized but centralized

The repository setup that we use and that works well with this branching model, is that with a central “truth” repo. Note that this repo is only considered to be the central one (since Git is a DVCS, there is no such thing as a central repo at a technical level). We will refer to this repo as origin, since this name is familiar to all Git users.
Each developer pulls and pushes to origin. But besides the centralized push-pull relationships, each developer may also pull changes from other peers to form sub teams. For example, this might be useful to work together with two or more developers on a big new feature, before pushing the work in progress to origin prematurely. In the figure above, there are subteams of Alice and Bob, Alice and David, and Clair and David.
Technically, this means nothing more than that Alice has defined a Git remote, named bob, pointing to Bob’s repository, and vice versa.

The main branches


At the core, the development model is greatly inspired by existing models out there. The central repo holds two main branches with an infinite lifetime:
  • master
  • develop
The master branch at origin should be familiar to every Git user. Parallel to the master branch, another branch exists called develop.
We consider origin/master to be the main branch where the source code of HEAD always reflects a production-ready state.
We consider origin/develop to be the main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release. Some would call this the “integration branch”. This is where any automatic nightly builds are built from.
When the source code in the develop branch reaches a stable point and is ready to be released, all of the changes should be merged back into master somehow and then tagged with a release number. How this is done in detail will be discussed further on.
Therefore, each time when changes are merged back into master, this is a new production release by definition. We tend to be very strict at this, so that theoretically, we could use a Git hook script to automatically build and roll-out our software to our production servers everytime there was a commit on master.

Supporting branches

Next to the main branches master and develop, our development model uses a variety of supporting branches to aid parallel development between team members, ease tracking of features, prepare for production releases and to assist in quickly fixing live production problems. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually.
The different types of branches we may use are:
  • Feature branches
  • Release branches
  • Hotfix branches
Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets. We will walk through them in a minute.
By no means are these branches “special” from a technical perspective. The branch types are categorized by how we use them. They are of course plain old Git branches.

Feature branches


May branch off from:
develop
Must merge back into:
develop
Branch naming convention:
anything except master, develop, release-*, or hotfix-*
Feature branches (or sometimes called topic branches) are used to develop new features for the upcoming or a distant future release. When starting development of a feature, the target release in which this feature will be incorporated may well be unknown at that point. The essence of a feature branch is that it exists as long as the feature is in development, but will eventually be merged back into develop (to definitely add the new feature to the upcoming release) or discarded (in case of a disappointing experiment).
Feature branches typically exist in developer repos only, not in origin.

Creating a feature branch

When starting work on a new feature, branch off from the develop branch.
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"

Incorporating a finished feature on develop

Finished features may be merged into the develop branch to definitely add them to the upcoming release:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop
The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature. Compare:
In the latter case, it is impossible to see from the Git history which of the commit objects together have implemented a feature—you would have to manually read all the log messages. Reverting a whole feature (i.e. a group of commits), is a true headache in the latter situation, whereas it is easily done if the --no-ff flag was used.
Yes, it will create a few more (empty) commit objects, but the gain is much bigger than the cost.

Release branches

May branch off from:
develop
Must merge back into:
develop and master
Branch naming convention:
release-*
Release branches support preparation of a new production release. They allow for last-minute dotting of i’s and crossing t’s. Furthermore, they allow for minor bug fixes and preparing meta-data for a release (version number, build dates, etc.). By doing all of this work on a release branch, the develop branch is cleared to receive features for the next big release.
The key moment to branch off a new release branch from develop is when develop (almost) reflects the desired state of the new release. At least all features that are targeted for the release-to-be-built must be merged in to develop at this point in time. All features targeted at future releases may not—they must wait until after the release branch is branched off.
It is exactly at the start of a release branch that the upcoming release gets assigned a version number—not any earlier. Up until that moment, the develop branch reflected changes for the “next release”, but it is unclear whether that “next release” will eventually become 0.3 or 1.0, until the release branch is started. That decision is made on the start of the release branch and is carried out by the project’s rules on version number bumping.

Creating a release branch

Release branches are created from the develop branch. For example, say version 1.1.5 is the current production release and we have a big release coming up. The state of develop is ready for the “next release” and we have decided that this will become version 1.2 (rather than 1.1.6 or 2.0). So we branch off and give the release branch a name reflecting the new version number:
$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)
After creating a new branch and switching to it, we bump the version number. Here, bump-version.sh is a fictional shell script that changes some files in the working copy to reflect the new version. (This can of course be a manual change—the point being that some files change.) Then, the bumped version number is committed.
This new branch may exist there for a while, until the release may be rolled out definitely. During that time, bug fixes may be applied in this branch (rather than on the develop branch). Adding large new features here is strictly prohibited. They must be merged into develop, and therefore, wait for the next big release.

Finishing a release branch

When the state of the release branch is ready to become a real release, some actions need to be carried out. First, the release branch is merged into master (since every commit on master is a new release by definition, remember). Next, that commit on master must be tagged for easy future reference to this historical version. Finally, the changes made on the release branch need to be merged back into develop, so that future releases also contain these bug fixes.
The first two steps in Git:
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2
The release is now done, and tagged for future reference.
Edit: You might as well want to use the -s or -u <key> flags to sign your tag cryptographically.
To keep the changes made in the release branch, we need to merge those back into develop, though. In Git:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
This step may well lead to a merge conflict (probably even, since we have changed the version number). If so, fix it and commit.
Now we are really done and the release branch may be removed, since we don’t need it anymore:
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

Hotfix branches


May branch off from:
master
Must merge back into:
develop and master
Branch naming convention:
hotfix-*
Hotfix branches are very much like release branches in that they are also meant to prepare for a new production release, albeit unplanned. They arise from the necessity to act immediately upon an undesired state of a live production version. When a critical bug in a production version must be resolved immediately, a hotfix branch may be branched off from the corresponding tag on the master branch that marks the production version.
The essence is that work of team members (on the develop branch) can continue, while another person is preparing a quick production fix.

Creating the hotfix branch

Hotfix branches are created from the master branch. For example, say version 1.2 is the current production release running live and causing troubles due to a severe bug. But changes on develop are yet unstable. We may then branch off a hotfix branch and start fixing the problem:
$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)
Don’t forget to bump the version number after branching off!
Then, fix the bug and commit the fix in one or more separate commits.
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
Finishing a hotfix branch
When finished, the bugfix needs to be merged back into master, but also needs to be merged back into develop, in order to safeguard that the bugfix is included in the next release as well. This is completely similar to how release branches are finished.
First, update master and tag the release.
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1
Edit: You might as well want to use the -s or -u <key> flags to sign your tag cryptographically.
Next, include the bugfix in develop, too:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
The one exception to the rule here is that, when a release branch currently exists, the hotfix changes need to be merged into that release branch, instead of develop. Back-merging the bugfix into the release branch will eventually result in the bugfix being merged into develop too, when the release branch is finished. (If work in develop immediately requires this bugfix and cannot wait for the release branch to be finished, you may safely merge the bugfix into develop now already as well.)
Finally, remove the temporary branch:
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).

Summary

While there is nothing really shocking new to this branching model, the “big picture” figure that this post began with has turned out to be tremendously useful in our projects. It forms an elegant mental model that is easy to comprehend and allows team members to develop a shared understanding of the branching and releasing processes.
A high-quality PDF version of the figure is provided here. Go ahead and hang it on the wall for quick reference at any time.
Update: And for anyone who requested it: here’s the gitflow-model.src.key of the main diagram image (Apple Keynote).

Friday, October 6, 2017

Gitlab - Command line instructions

https://gitlab.com

 Command line instructions

Git global setup
git config --global user.name "Nguyễn Văn Hưng"
git config --global user.email "hungnv@runsystem.net"
Create a new repository
git clone git@gitlab.com:hungnv-runsystem-net/design-pattern.git
cd design-pattern
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
Existing folder
cd existing_folder
git init
git remote add origin git@gitlab.com:hungnv-runsystem-net/design-pattern.git
git add .
git commit -m "Initial commit"
git push -u origin master
Existing Git repository
cd existing_repo
git remote add origin git@gitlab.com:hungnv-runsystem-net/design-pattern.git
git push -u origin --all
git push -u origin --tags 
 
 

Giới thiệu về Git - Phần 2

Sử dụng git trong thực tế

Git model

Tại sao lại là git?

Git mang lại cho chúng ta 1 cách tiếp cận mới, nó thay đổi cách nghĩ của người phát triển phần mềm về việc merging và branching. Với những công cụ truyền thống là CVS/Subversion thì nguời phát triển luôn luôn lo lắng, e ngại mỗi lúc mergeing/branching với những confict tiềm tàng ẩn chứa rủi ro.
Nhưng đối với git, việc đó trở nên dễ dàng và an toàn hơn bao giờ hết, việc mergeing và branching đã trở thành những công việc thường ngày mà chúng ta làm trong quá trình phát triển. Trong những ebook hướng dẫn sử dụng với CVS/Subversion thì hướng dẫn branching và merging thường được đề cập ở những chap cuối của sách (phần nâng cao) dành cho những người đã thông thạo, còn với git thì nó lại thuộc phần basic (cơ bản), điều này dễ dàng cho ta thấy việc sử dụng git để merging và branching dễ dàng và an toàn hơn so với các phương thức cổ điển.
Những cải tiến suất sắc trong merging và branching của git so với những công cụ truyền thống đã giúp cho việc quản lý version của source code trở nên đơn giản và nhẹ nhàng hơn rất nhiều, vì vậy mà các nhà phát triển dần dần đã chuyển sang sử dụng git để thay thế các phương pháp truyền thống.
Vậy sử dụng git trong thực tế như thế nào, tổ chức và quản lý các branch, tiến hành mergeing như thế nào là đúng đắn??? Sau đây sẽ là hướng dẫn cụ thể việc sử dụng git trong phát triển phần mềm thực tế, sẽ giúp các bạn nắm rõ hơn cách tổ chức 1 bộ source bằng git trong quá trình phát triển.
Decentralized but centralized (phân tán nhưng tập trung)
Với 1 source được quản lý bởi git, luôn chỉ có duy nhất 1 "central truth repo" (1 repo gốc, sẽ được sử dụng để deploy trong quá trình release hệ thống thật) gọi là "origin" (remote origin) → thuật ngữ rất phổ biến với git users.
Mỗi developer sẽ push và pull lên remote origin → centralized, tuy nhiên ta vẫn có thể tổ chức những nhóm riêng (sub team) sử dụng remote riêng để phục vụ cho quá trình phát triển.
Decentralized but centralized
Ví dụ giống như hình trên, mỗi khi phát triển 1 feature lớn, cần có 1 team gồm nhiều thành viên để phát triển thì ta sẽ tiến hành tổ chức các remote khác nhau để hỗ trợ. Các developer sẽ push lên các remote của sub team trước khi push lên remote origin, trong hình trên ta thấy được subteam được tổ chức giữa Alice và Bob, Alice và David, Clair và David. => Alice đơn giản chỉ là khai báo 1 remote, ví dụ tên bob, trỏ vào local repo của Bob.
The main branches (Những branch chính)
Main banrches là những branch sẽ tồn tại mãi mãi, gồm có 2 branch sau: master develop 2 branch này được phát triển vả tồn tại song song với nhau. Và chú ý là source code HEAD của branch origin/master chính là phiên bản sẵn sàng để phát hành ra thực tế. Còn đối với origin/develop là branch mà source code HEAD của nó là phiên bản phát hành cuối cùng để sẵn sàng cho lần release tiếp theo. Ngoài ra nó còn được gọi là "integration branch".
Khi source code trong branch develop đã đạt được mục tiêu của lần release tiếp theo thì code của nó sẽ được merge trở lại vào master, được tag với 1 dãy số release (release version, ví dụ v1.0.1). Về release version ta sẽ đề cập ở phần cuối của bài này.
Mỗi lần ta merge vào master có nghĩa là có 1 sản phẩm mới, 1 phiên bản mới sẽ được phát hành, và sẽ phải rất cẩn thận rong quá trình release này, ta có thể sử dụng 1 đoạn git hook script để tự động build và roll-out source code thành phiên bản thực tế mỗi lần ta commit lên master.
Main Branches
Supporting branches (những branch hỗ trợ)
Sau main branch, developer còn sử dụng rất nhiều những supporting branches để tiến hành phát triển song song giữa các thành viên trong team, dễ dàng theo dõi các features, chuẩn bị cho quá trính release cũng nhưng để fix những bug của sản phẩm. Không giống như main branch, những suporting branch luôn có thời gian tồn tại nhất định. Supporting branches gồm những loại sau:
  • Feature branches
  • Release branches
  • Hotfix branches
Mỗi 1 branch trên sẽ có 1 mục đích sử dụng cụ thể riêng và sẽ có những quy định sử dụng cụ thể đi kèm về: được checkout (branch off) từ branch nào và sẽ được merge vào branch nào. Chúng ta sẽ đi từng branch cụ thể đôi chút.

Hệ thống branch

Feature branches

  • branch off từ: develop
  • merge vào: develop
  • Quy luật đặt tên: bất kể gì trừ master, develop, release-, hay hotfix-
Feature branches(hay topic branches) được sử dụng để phát triển 1 tính năng mới cho sản phẩm và sẽ phát hành trong tương lai. Khi bắt đầu phát triển 1 tính năng, có thể ta không biết được là nó sẽ được phát hành cùng với phiên bản release nào. Bản chất của feature branch là sẽ tồn tại như 1 tính năng trong quá trình phát triển, nhưng sau cùng nó sẽ cũng được merger vào develop hoặc là bị hủy đi, không sử dụng nữa. Feature branches thông thường chỉ tồn tại trên repos của developer, không tồn tại trên origin.
Feature branches
Tạo feature branch:
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
Kết thúc phát triển sẽ được merge lại vào develop và sẽ được add thêm trong lần release tiếp theo:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop
–no-ff flag có nghĩa là việc merge sẽ luôn luôn tạo ra 1 đối thượng commit, kể cả nếu việc merge có thể được thực thi với fast-forward. Nó chống lại việc mất thông tin về quá trình phát triển của feature và nhóm lại với nhau, hình sau sẽ giúp ta dễ hình dung hơn:
Merge without ff
Với việc sử dụng flag –no-ff thì những log về commit trong branch cũ vẫn được lưu giữ lại việc này giúp cho chùng ta lần lại được log của tất cả những commit trong quá khứ, xem được những thay đổi trong mỗi lần commit đấy. Sử dụng flag này tránh được rắc rối khi chúng ta kiểm tra lại sự thay đổi của project trong quá trình phát triển, khi mà lúc merge xong thì mọi commit trong branch cũ được kết hợp lại làm một.
Tuy nhiên chưa có cách config nào để biến flag này thành mặc định, nhưng nó sẽ có khả năng có trong tương lai.

Release branches

  • Được branch off từ:develop
  • Được merge vào develop và master.
  • Quy tắc đặt tên: release-*
Release branch hỗ trợ chuẩn bị cho 1 release mới của product. Chúng cho phép đứt quãng quá trình và bỏ qua nó. Hơn nữa, nó cũng cho phép tiến hành hạy song song fix bug và chuẩn bị meta-data cho release (version number, build dates,...).
Khi tạo branch release từ develop thì branch develop lúc đó phải thể hiện rõ (mang đủ những tính năng) của product trong lần release mới này. Tối thiểu tất cả những features của lần release mới này phải được merge vào develop rồi.
Chính xác thì khi strat 1 release branch thì nó sẽ được gán 1 version mới (sự thay đổi version release, ko phải fix bug, → sẽ nói kỹ càng hơn ở phần cuối của mục "sử dụng trong thực tế"). Nó được gọi là "project’s rules on version number va chạm" → quy tắc đặt tên version.
Tạo release branch: được tạo từ branch develop. Ví dụ phiên bản hiện tại của product là 1.1.5 và chúng ta đang tiến hành release 1 phiên bản mới. Lúc này phiên bản release mới sẽ là 1.2.0 thay vì 1.1.6 hay 2.0. Ví dụ:
$ git checkout -b release-1.2 develop
  → tạo mới và chuyển sang "release-1.2"
$ ./bump-version.sh 1.2
  → bump (nâng version) new version (config thông tin của product thành version mới)
$ git commit -a -m "Bumped version number to 1.2"commit state mới
Sau khi tạo mới release branch và chuyển qua nó, chúng ta tiến hành bump số version của product. bump-version.sh là 1 đoạn shell script mà nó sẽ thay đổi nội dung 1 số file để khớp với số version release mới. Rồi bumped số version mới được commit lên.
Có thể tồn tại những branch khác trong quá trình branch release được tiến hành, cho đến khi sự release co thể bị xoay ngược lại. Trong khoảng thời gian này, việc fix bug có thể được apply vào branch này (nhanh hơn so với develop). Việc thêm những tính năng lớn ở giai đoạn này bị cấm tuyệt đối. Chúng sẽ được merge vào develop và chờ cho tới lần release tiếp theo.
Hoàn thành release branch Khi trạng thái của branch release đã sẵn sàng để thành 1 release thực sự, cần phải cẩn thận một số hành động tại thời điểm này. Đầu tiên, branch release phải được merge vào master (nhớ là khi mọi commit trên master là đã được quy định). Tiếp theo, những commit trên master phải được tag để trong tương lai ta có thể ánh xạ lại được những version cũ của product trong quá khứ. Và cuối cùng là những thay đổi trên release branch phải được merge ngược trở lại vào develop để đảm bảo tương thích (những bug đã được fix hay những tính năng nhỏ khác được tiến hành trên branch release) cho lần release tiếp theo.
2 bước đầu tiên trên git
$ git checkout master
    Switched to branch 'master'
$ git merge --no-ff release-1.2
    Merge made by recursive.
$ git tag -a 1.2
   Relese done, và được tag cho lần release này.
Và như nói ở trên, ta phải merge ngược lại vào develop. In Git:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
Bước này có thể bị confict, ta phải fix chúng rồi commit lên develop.
Tiếp theo chúng ta xoá release branch đi nếu như chúng ta không còn dùng đến nó nữa:
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

Hotfix Branches

Hotfix Branches
  • Branch off from: master
  • được merge vào: develop and master
  • Quy tắc đặt tên: hotfix-*
Branch hotfix có điểm rất giống branch release là nó có ý nghĩa sử dụng trong quá trình chuẩn bị cho lần release mới của product. Branch này xuất hiện khi có 1 thay đổi, sửa lỗi cần thiết trên phiên bản thực tế của product (phiên bản đang được sử dụng trong thực tế) và nó hoàn toàn nằm ngoài thiết kế. Khi có 1 bug nghiêm trọng trong phiên bản thực tế của product thì branch hotfix được branch off từ master và là version của product cũng được nâng lên tại thời điểm này (Ví dụ 1.1.2 → 1.1.3).
Lúc này thì công việc của team vẫn được tiến hành bình thường trên branch develop, sẽ có 1 vài người được chỉ định để fix bug nhanh chóng trên product.
Branch hotfix được tạo từ master. Ví dụ 1.2 là phiên bản hiện tại của product trong thực tế và xuất hiện 1 bug nghiêm trọng cần thiết phải sửa chữa ngay lập tức thì công việc sẽ được hình dung cụ thể như sau:
$ git checkout -b hotfix-1.2.1 master
 Tạo mới và chuyển sang branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)
Đừng bao giờ quên bump the version number sau khi branching off!
Và tiếp theo, tiến hành sửa lỗi và commit lên
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
Finishing a hotfix branch
Khi kết thúc sửa lỗi, branch hotfix cần phải merge ngược lại vào cả master và develop.
Đầu tiên, update master và tag phiên bản release.
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1
Và merge vào develop
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
Có một ngoại lệ đặc biệt ở đây là khi mà branch release đang tồn tại thì branch hotfix sẽ được merge vào branch release thay vì develop. Vì sau này khi merge branch release và branch develop thì những gì của branch hotfix vẫn sẽ được ốp vào develop.
Bước cuối cùng là xoá branch hotfix:
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
Release number
Release number
  • Phase Number: phụ thuộc kế hoạch phát triển của product (phase number là level lớn nhất)
  • Release Number: sau phase number là release number, trong mỗi phase sẽ được chia ra từng giai đoạn release, chính là những quá trình thêm các tính năng lớn vào product. Tương ứng với branch release.
  • Fixbug number: mỗi lần fix bug trên master thì lại tăng số này lên.

Tham khảo

Thursday, October 5, 2017

Giới thiệu về Git - Phần 1

Git là gì?

Git là 1 hệ thống Distributed revision control (Distributed version control or Decentralized version control), tạm dịch là hệ thống quản lý source phân tán. Git được phát triển và phân phối trên Linux kernel bởi Linus Torvalds (Người tạo ra Linux) vào năm 2005 và ngày càng trở thành công cụ phổ biến để phát triển phần mềm.
Được phát triển khi có nhiều nhà phát triển nhân Linux bắt đầu từ bỏ BitKeeper (1 tool distributed revision control). Torvalds muốn 1 hệ thống phân tán mà sử dụng tương tự như BitKeeper nhưng vào thời điểm đó không có 1 service nào free như vậy cả, đặc biệt là với hiệu năng cao.
Ông mường tượng ra 1 hệ thống SCM (Source Control Management) chỉ trong vòng 3s sẽ thực thi được mọi thao tác để update mọi dữ liệu metadata của source code, project mà ông muốn sử dụng chính là project kernel của linux, project này mỗi lần để đồng bộ các dữ liệu maintain cần tới hơn 250 actions để thực thi, và ông muốn nó phải diễn ra chỉ trong vòng 3s. Ông đã nghĩ tới 1 hệ thống với những đặc tính sau:
Sử dụng Concurrent Versions System như 1 ví dụ mà sẽ không làm: nếu trong trường hợp có nghi vấn thì sẽ đưa ra những quyết định đối lập. Hỗ trợ phân tán (giống với BitKeeper) Tool đảm bảo chống lại những sai lầm, những vi phạm ngẫu nhiên hay những hành động thâm độc, phá hoại.
Torvalds gọi nó 1 cách châm biếm là git, git theo tiếng lóng của Anh có nghĩa là "người khó ưa" (unpleasant person). Ông nói "Tôi là 1 kẻ ngốc ích kỉ và tôi đặt tên tất cả các project của tôi đều ám chỉ tới tôi", giống như là ông đặt tên cho Linux (Linus là tên ông) vậy.

Lược sử

  • Bắt đầu được phát triển tháng 03/04/2005
  • Public 06/04/2005
  • Self-hosting vào 07/04/2005
  • Lần merge đầu tiên giữa nhiều branch diễn ra vào 18/04/2005
  • Torvals đã đạt được mục tiêu của ông vào 29/04/2005 khi ông thử kiểm với Linux Kernel trong 6.7s
  • Release cùng kernel 2.6.12 vào 16/06/2005
  • Release phiên bản 1.0 vào 21/12/2005

Đôi điều về git

  • Strong support for non-linear development: hỗ trợ mạnh mẽ phát triển không tuyến tính (phát triển song song các chức năng)
  • Distributed development: Hỗ trợ phát triển và lưu source 1 cách phân tán giống như Darcs, BitKeeper, Mercurial, SVK, Bazaar and Monotone. Người dùng sẽ có 1 bản copy trên local và sẽ sử dụng nó để phát triển, merger branch,...
  • Compatibility with existing systems/protocols: thích ứng được với những hệ thống và giao thức hiện có (HTTP,FTP,rsync,ssh, plain socket,…)
  • Efficient handling of large projects: có khả năng quản lý được những project lớn, git hoạt động nhanh, mạnh mẽ, hiệu suất cao.
  • Cryptographic authentication of history: xác thực history bằng mật mã.
  • Toolkit-based design: git được viết bằng C để nâng cao tốc độ thực thi.
  • Pluggable merge strategies: git có 1 model để meger không toàn vẹn và cũng hỗ trợ rất nhiều thuật toán để hoàn thiện quá trình merge, chỉ với trường hợp ko thể meger được thì mới cần người dùng phải tiến hành merge bằng tay.
  • Garbage accumulates unless collected:
  • Periodic explicit object packing

Sử dụng git cơ bản

Mô hình git

Git Workflow
Như sơ đồ trên, git chia ra làm 2 môi trường là Remote và Local.
  • Remote: là môi trường lưu trữ và phân phối source của project.
  • Local: là môi trường làm việc local của nhà phát triển, nó là 1 bản sao của source trên remote, giúp ta commit code cũng như các thao tác khác 1 cách nhanh hơn so với CVS, SVN,…

Các lệnh git cơ bản

  • git clone <git_path>: clone source về local
  • git status: check branch status
  • git branch: list branch trên local
  • git branch -a: list branch cả trên local và remote
  • git checkout -b <branch_name>: tạo branch mới
  • git add <file_path1> <file_path2>: add file để commit
  • git commit -m "<commit_mess>": commit to local
  • git push <remote> <branch>: push to remote

3 Trạng thái trong git (local)

Mỗi tập tin trong Git được quản lý dựa trên ba trạng thái: committed, modified, và staged. Committed có nghĩa là dữ liệu đã được lưu trữ một cách an toàn trong cơ sở dữ liệu. Modified có nghĩa là bạn đã thay đổi tập tin nhưng chưa commit vào cơ sở dữ liệu. Và staged là bạn đã đánh dấu sẽ commit phiên bản hiện tại của một tập tin đã chỉnh sửa trong lần commit sắp tới.
Điều này tạo ra ba phần riêng biệt của một dự án sử dụng Git: thư mục Git, thư mục làm việc, và khu vực tổ chức (staging area). Local Operations
Thư mục Git là nơi Git lưu trữ các "siêu dữ kiện" (metadata) và cơ sở dữ liệu cho dự án của bạn. Đây là phần quan trọng nhất của Git, nó là phần được sao lưu về khi bạn tạo một bản sao (clone) của một kho chứa từ một máy tính khác.
Thư mục làm việc là bản sao một phiên bản của dự án. Những tập tin này được kéo về (pulled) từ cơ sở dữ liệu được nén lại trong thư mục Git và lưu trên ổ cứng cho bạn sử dụng hoặc chỉnh sửa.
Khu vực staging là một tập tin đơn giản được chứa trong thư mục Git, nó chứa thông tin về những gì sẽ được commit trong lần commit sắp tới. Nó còn được biết đến với cái tên “chỉ mục” (index), nhưng khu vực tổ chức (staging area) đang dần được coi là tên tiêu chuẩn.
Tiến trình công việc (workflow) cơ bản của Git:
  1. Bạn thay đổi các tập tin trong thư mục làm việc.
  2. Bạn tổ chức các tập tin, tạo mới ảnh của các tập tin đó vào khu vực tổ chức.
  3. Bạn commit, ảnh của các tập tin trong khu vực tổ chức sẽ được lưu trữ vĩnh viễn vào thư mục Git.
Nếu một phiên bản nào đó của một tập tin ở trong thư mục Git, nó được coi là đã commit. Nếu như nó đã được sửa và thêm vào khu vực tổ chức, nghĩa là nó đã được staged. Và nếu nó được thay đổi từ khi checkout nhưng chưa được staged, nó được coi là đã thay đổi.
Trong Chương 2, bạn sẽ được tìm hiểu kỹ hơn về những trạng thái này cũng như làm thế nào để tận dụng lợi thế của chúng hoặc bỏ qua hoàn toàn giai đoạn tổ chức (staged).

Tham khảo

Connecting to GitHub with SSH

You can connect to GitHub using SSH.

About SSH

Using the SSH protocol, you can connect and authenticate to remote servers and services. With SSH keys, you can connect to GitHub without supplying your username or password at each visit.

Checking for existing SSH keys

Before you generate an SSH key, you can check to see if you have any existing SSH keys.

Generating a new SSH key and adding it to the ssh-agent

After you've checked for existing SSH keys, you can generate a new SSH key to use for authentication, then add it to the ssh-agent.

Adding a new SSH key to your GitHub account

To configure your GitHub account to use your new (or existing) SSH key, you'll also need to add it to your GitHub account.

Testing your SSH connection

After you've set up your SSH key and added it to your GitHub account, you can test your connection.

Working with SSH key passphrases

You can secure your SSH keys and configure an authentication agent so that you won't have to reenter your passphrase every time you use your SSH keys.

git stash

Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.

git add * (asterisk) vs git add . (period)

add * means add all files in the current directory, except for files, whose name begin with a dot. This is your shell functionality and Git only ever receives a list of files.
add . has no special meaning in your shell, and thus Git adds the entire directory recursively, which is almost the same, but including files whose names begin with a dot.