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.

Git tutorial

NAME

gittutorial - A tutorial introduction to Git

SYNOPSIS

git *

DESCRIPTION

This tutorial explains how to import a new project into Git, make changes to it, and share changes with other developers.
If you are instead primarily interested in using Git to fetch a project, for example, to test the latest version, you may prefer to start with the first two chapters of The Git User’s Manual.
First, note that you can get documentation for a command such as git log --graph with:
$ man git-log
or:
$ git help log
With the latter, you can use the manual viewer of your choice; see git-help[1] for more information.
It is a good idea to introduce yourself to Git with your name and public email address before doing any operation. The easiest way to do so is:
$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com

Importing a new project

Assume you have a tarball project.tar.gz with your initial work. You can place it under Git revision control as follows.
$ tar xzf project.tar.gz
$ cd project
$ git init
Git will reply
Initialized empty Git repository in .git/
You’ve now initialized the working directory—​you may notice a new directory created, named ".git".
Next, tell Git to take a snapshot of the contents of all files under the current directory (note the .), with git add:
$ git add .
This snapshot is now stored in a temporary staging area which Git calls the "index". You can permanently store the contents of the index in the repository with git commit:
$ git commit
This will prompt you for a commit message. You’ve now stored the first version of your project in Git.

Making changes

Modify some files, then add their updated contents to the index:
$ git add file1 file2 file3
You are now ready to commit. You can see what is about to be committed using git diff with the --cached option:
$ git diff --cached
(Without --cached, git diff will show you any changes that you’ve made but not yet added to the index.) You can also get a brief summary of the situation with git status:
$ git status
On branch master
Changes to be committed:
Your branch is up-to-date with 'origin/master'.
  (use "git reset HEAD <file>..." to unstage)

 modified:   file1
 modified:   file2
 modified:   file3
If you need to make any further adjustments, do so now, and then add any newly modified content to the index. Finally, commit your changes with:
$ git commit
This will again prompt you for a message describing the change, and then record a new version of the project.
Alternatively, instead of running git add beforehand, you can use
$ git commit -a
which will automatically notice any modified (but not new) files, add them to the index, and commit, all in one step.
A note on commit messages: Though not required, it’s a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. The text up to the first blank line in a commit message is treated as the commit title, and that title is used throughout Git. For example, git-format-patch[1] turns a commit into email, and it uses the title on the Subject line and the rest of the commit in the body.

Git tracks content not files

Many revision control systems provide an add command that tells the system to start tracking changes to a new file. Git’s add command does something simpler and more powerful: git add is used both for new and newly modified files, and in both cases it takes a snapshot of the given files and stages that content in the index, ready for inclusion in the next commit.

Viewing project history

At any point you can view the history of your changes using
$ git log
If you also want to see complete diffs at each step, use
$ git log -p
Often the overview of the change is useful to get a feel of each step
$ git log --stat --summary

Managing branches

A single Git repository can maintain multiple branches of development. To create a new branch named "experimental", use
$ git branch experimental
If you now run
$ git branch
you’ll get a list of all existing branches:
  experimental
* master
The "experimental" branch is the one you just created, and the "master" branch is a default branch that was created for you automatically. The asterisk marks the branch you are currently on; type
$ git checkout experimental
to switch to the experimental branch. Now edit a file, commit the change, and switch back to the master branch:
(edit file)
$ git commit -a
$ git checkout master
Check that the change you made is no longer visible, since it was made on the experimental branch and you’re back on the master branch.
You can make a different change on the master branch:
(edit file)
$ git commit -a
at this point the two branches have diverged, with different changes made in each. To merge the changes made in experimental into master, run
$ git merge experimental
If the changes don’t conflict, you’re done. If there are conflicts, markers will be left in the problematic files showing the conflict;
$ git diff
will show this. Once you’ve edited the files to resolve the conflicts,
$ git commit -a
will commit the result of the merge. Finally,
$ gitk
will show a nice graphical representation of the resulting history.
At this point you could delete the experimental branch with
$ git branch -d experimental
This command ensures that the changes in the experimental branch are already in the current branch.
If you develop on a branch crazy-idea, then regret it, you can always delete the branch with
$ git branch -D crazy-idea
Branches are cheap and easy, so this is a good way to try something out.

Using Git for collaboration

Suppose that Alice has started a new project with a Git repository in /home/alice/project, and that Bob, who has a home directory on the same machine, wants to contribute.
Bob begins with:
bob$ git clone /home/alice/project myrepo
This creates a new directory "myrepo" containing a clone of Alice’s repository. The clone is on an equal footing with the original project, possessing its own copy of the original project’s history.
Bob then makes some changes and commits them:
(edit files)
bob$ git commit -a
(repeat as necessary)
When he’s ready, he tells Alice to pull changes from the repository at /home/bob/myrepo. She does this with:
alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
This merges the changes from Bob’s "master" branch into Alice’s current branch. If Alice has made her own changes in the meantime, then she may need to manually fix any conflicts.
The "pull" command thus performs two operations: it fetches changes from a remote branch, then merges them into the current branch.
Note that in general, Alice would want her local changes committed before initiating this "pull". If Bob’s work conflicts with what Alice did since their histories forked, Alice will use her working tree and the index to resolve conflicts, and existing local changes will interfere with the conflict resolution process (Git will still perform the fetch but will refuse to merge --- Alice will have to get rid of her local changes in some way and pull again when this happens).
Alice can peek at what Bob did without merging first, using the "fetch" command; this allows Alice to inspect what Bob did, using a special symbol "FETCH_HEAD", in order to determine if he has anything worth pulling, like this:
alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD
This operation is safe even if Alice has uncommitted local changes. The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable from the FETCH_HEAD but exclude anything that is reachable from HEAD". Alice already knows everything that leads to her current state (HEAD), and reviews what Bob has in his state (FETCH_HEAD) that she has not seen with this command.
If Alice wants to visualize what Bob did since their histories forked she can issue the following command:
$ gitk HEAD..FETCH_HEAD
This uses the same two-dot range notation we saw earlier with git log.
Alice may want to view what both of them did since they forked. She can use three-dot form instead of the two-dot form:
$ gitk HEAD...FETCH_HEAD
This means "show everything that is reachable from either one, but exclude anything that is reachable from both of them".
Please note that these range notation can be used with both gitk and "git log".
After inspecting what Bob did, if there is nothing urgent, Alice may decide to continue working without pulling from Bob. If Bob’s history does have something Alice would immediately need, Alice may choose to stash her work-in-progress first, do a "pull", and then finally unstash her work-in-progress on top of the resulting history.
When you are working in a small closely knit group, it is not unusual to interact with the same repository over and over again. By defining remote repository shorthand, you can make it easier:
alice$ git remote add bob /home/bob/myrepo
With this, Alice can perform the first part of the "pull" operation alone using the git fetch command without merging them with her own branch, using:
alice$ git fetch bob
Unlike the longhand form, when Alice fetches from Bob using a remote repository shorthand set up with git remote, what was fetched is stored in a remote-tracking branch, in this case bob/master. So after this:
alice$ git log -p master..bob/master
shows a list of all the changes that Bob made since he branched from Alice’s master branch.
After examining those changes, Alice could merge the changes into her master branch:
alice$ git merge bob/master
This merge can also be done by pulling from her own remote-tracking branch, like this:
alice$ git pull . remotes/bob/master
Note that git pull always merges into the current branch, regardless of what else is given on the command line.
Later, Bob can update his repo with Alice’s latest changes using
bob$ git pull
Note that he doesn’t need to give the path to Alice’s repository; when Bob cloned Alice’s repository, Git stored the location of her repository in the repository configuration, and that location is used for pulls:
bob$ git config --get remote.origin.url
/home/alice/project
(The complete configuration created by git clone is visible using git config -l, and the git-config[1] man page explains the meaning of each option.)
Git also keeps a pristine copy of Alice’s master branch under the name "origin/master":
bob$ git branch -r
  origin/master
If Bob later decides to work from a different host, he can still perform clones and pulls using the ssh protocol:
bob$ git clone alice.org:/home/alice/project myrepo
Alternatively, Git has a native protocol, or can use http; see git-pull[1] for details.
Git can also be used in a CVS-like mode, with a central repository that various users push changes to; see git-push[1] and gitcvs-migration[7].

Exploring history

Git history is represented as a series of interrelated commits. We have already seen that the git log command can list those commits. Note that first line of each git log entry also gives a name for the commit:
$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date:   Tue May 16 17:18:22 2006 -0700

    merge-base: Clarify the comments on post processing.
We can give this name to git show to see the details about this commit.
$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
But there are other ways to refer to commits. You can use any initial part of the name that is long enough to uniquely identify the commit:
$ git show c82a22c39c # the first few characters of the name are
   # usually enough
$ git show HEAD  # the tip of the current branch
$ git show experimental # the tip of the "experimental" branch
Every commit usually has one "parent" commit which points to the previous state of the project:
$ git show HEAD^  # to see the parent of HEAD
$ git show HEAD^^ # to see the grandparent of HEAD
$ git show HEAD~4 # to see the great-great grandparent of HEAD
Note that merge commits may have more than one parent:
$ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
$ git show HEAD^2 # show the second parent of HEAD
You can also give commits names of your own; after running
$ git tag v2.5 1b2e1d63ff
you can refer to 1b2e1d63ff by the name "v2.5". If you intend to share this name with other people (for example, to identify a release version), you should create a "tag" object, and perhaps sign it; see git-tag[1] for details.
Any Git command that needs to know a commit can take any of these names. For example:
$ git diff v2.5 HEAD  # compare the current HEAD to v2.5
$ git branch stable v2.5 # start a new branch named "stable" based
    # at v2.5
$ git reset --hard HEAD^ # reset your current branch and working
    # directory to its state at HEAD^
Be careful with that last command: in addition to losing any changes in the working directory, it will also remove all later commits from this branch. If this branch is the only branch containing those commits, they will be lost. Also, don’t use git reset on a publicly-visible branch that other developers pull from, as it will force needless merges on other developers to clean up the history. If you need to undo changes that you have pushed, use git revert instead.
The git grep command can search for strings in any version of your project, so
$ git grep "hello" v2.5
searches for all occurrences of "hello" in v2.5.
If you leave out the commit name, git grep will search any of the files it manages in your current directory. So
$ git grep "hello"
is a quick way to search just the files that are tracked by Git.
Many Git commands also take sets of commits, which can be specified in a number of ways. Here are some examples with git log:
$ git log v2.5..v2.6            # commits between v2.5 and v2.6
$ git log v2.5..                # commits since v2.5
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log v2.5.. Makefile       # commits since v2.5 which modify
    # Makefile
You can also give git log a "range" of commits where the first is not necessarily an ancestor of the second; for example, if the tips of the branches "stable" and "master" diverged from a common commit some time ago, then
$ git log stable..master
will list commits made in the master branch but not in the stable branch, while
$ git log master..stable
will show the list of commits made on the stable branch but not the master branch.
The git log command has a weakness: it must present commits in a list. When the history has lines of development that diverged and then merged back together, the order in which git log presents those commits is meaningless.
Most projects with multiple contributors (such as the Linux kernel, or Git itself) have frequent merges, and gitk does a better job of visualizing their history. For example,
$ gitk --since="2 weeks ago" drivers/
allows you to browse any commits from the last 2 weeks of commits that modified files under the "drivers" directory. (Note: you can adjust gitk’s fonts by holding down the control key while pressing "-" or "+".)
Finally, most commands that take filenames will optionally allow you to precede any filename by a commit, to specify a particular version of the file:
$ git diff v2.5:Makefile HEAD:Makefile.in
You can also use git show to see any such file:
$ git show v2.5:Makefile

Next Steps

This tutorial should be enough to perform basic distributed revision control for your projects. However, to fully understand the depth and power of Git you need to understand two simple ideas on which it is based:
  • The object database is the rather elegant system used to store the history of your project—​files, directories, and commits.
  • The index file is a cache of the state of a directory tree, used to create commits, check out working directories, and hold the various trees involved in a merge.
Part two of this tutorial explains the object database, the index file, and a few other odds and ends that you’ll need to make the most of Git. You can find it at gittutorial-2[7].
If you don’t want to continue with that right away, a few other digressions that may be interesting at this point are:
  • git-format-patch[1], git-am[1]: These convert series of git commits into emailed patches, and vice versa, useful for projects such as the Linux kernel which rely heavily on emailed patches.
  • git-bisect[1]: When there is a regression in your project, one way to track down the bug is by searching through the history to find the exact commit that’s to blame. Git bisect can help you perform a binary search for that commit. It is smart enough to perform a close-to-optimal search even in the case of complex non-linear history with lots of merged branches.
  • gitworkflows[7]: Gives an overview of recommended workflows.
  • giteveryday[7]: Everyday Git with 20 Commands Or So.
  • gitcvs-migration[7]: Git for CVS users.

GIT

Part of the git[1] suite

Wednesday, October 4, 2017

Try git

https://try.github.io/levels/1/challenges/
  1. git init
  2. git status (để xem có file untracked nào không)
  3. git add octocat.txt (để add file vào một staging area mà được git gọi là index)
  4. git status
  5. git commit -m "add cute octocat story"
  6. git add "*.txt"
  7. git commit -m 'add all octocat files'
  8. git log (để xem lịch sử commit)
  9. git remote add origin https://github.com/try-git/try_git.git (để add một remote repo vào, và đặt trên remote repo đó là origin )
  10. git push -u origin master (để đẩy các file trong local repo lên remote repo)
    • origin: tên gọi của remote repo
    • master: là tên của 1 local branch (nằm trong local repo)
    • -u: để yêu cầu git nhơ các tham số (remote repo nào và local branch nào). lần sau chỉ cần gõ 'git push'
  11. git pull origin master (kéo từ remote repo có tên là origin => kéo về local branch có tên là master)
  12. git diff HEAD (để xem sự khác nhau của remote repo: từ lần mình commit cuối cùng => đến hiện tại)
  13. git add octofamily/octodog.txt
  14. git diff --staged (để xem những thay đổi khi mình add thêm file vào staging area)
  15. git reset octofamily/octodog.txt (để unstage file)
  16. git checkout -- octocat.txt (để đưa cả local branch về lần cuối cùng mà tôi commit file octocat.txt )
  17. git branch clean_up (tạo mới 1 local branch tên là clean_up, nó sẽ được khởi tạo ban đầu giống với branch hiện tại)
  18. git branch (để xem hiện tại có những branch nào, và chúng ta đang thao tác trên branch nào)
  19. git checkout clean_up (để chuyển branch hiện tại : master => clean_up)
  20. git rm '*.txt' (vừa xóa file khỏi ổ cứng, và cũng 'stage the removal of the files')
  21. git status (xem trạng thái của staging area)
  22. git commit -m 'remove all the cats'
  23. git checkout master (chuyển branch hiện tại sang master)
  24. git merge clean_up (merge branch clean_up với branch hiện tại)
  25. git branch -d clean_up (xóa branch clean_up)
  26. git push (đẩy từ master => remote repo, branch origin)

Sunday, October 1, 2017

git replacing LF with CRLF

Git has three modes of how it treats line endings:
$ git config core.autocrlf
# that command will print "true" or "false" or "input"
You can set the mode to use by adding an additional parameter of true or false to the above command line.
If core.autocrlf is set to true, that means that any time you add a file to the git repo that git thinks is a text file, it will turn all CRLF line endings to just LF before it stores it in the commit. Whenever you git checkout something, all text files automatically will have their LF line endings converted to CRLF endings. This allows development of a project across platforms that use different line-ending styles without commits being very noisy because each editor changes the line ending style as the line ending style is always consistently LF.
The side-effect of this convenient conversion, and this is what the warning you're seeing is about, is that if a text file you authored originally had LF endings instead of CRLF, it will be stored with LF as usual, but when checked out later it will have CRLF endings. For normal text files this is usually just fine. The warning is a "for your information" in this case, but in case git incorrectly assesses a binary file to be a text file, it is an important warning because git would then be corrupting your binary file.
If core.autocrlf is set to false, no line-ending conversion is ever performed, so text files are checked in as-is. This usually works ok, as long as all your developers are either on Linux or all on Windows. But in my experience I still tend to get text files with mixed line endings that end up causing problems.
My personal preference is to leave the setting turned ON, as a Windows developer.
See http://kernel.org/pub/software/scm/git/docs/git-config.html for updated info that includes the "input" value.