转:http://www.cnblogs.com/qianxudetianxia/p/4824536.html
公司规模不大,成立之初,选择了svn作为版本控制系统。这对于用惯了git的我来说,将就了一段时间后,极为不爽,切换到git-svn勉强能用。随后,因为产品需要发布不同的版本,而git-svn对远程分支的支持又甚为不好,于是提出搭建git环境的想法。鉴于呆过的前公司,没有一家使用svn不出事的(印象最深的是,阿里云OS就出现了一次svn重大事故),我不是svn黑,领导欣然同意。
需求
一共php,android,ios三个小团队,所以分别为php,android端,ios端搭建三个git仓库。
当然三十个git仓库都可以,和三个仓库是一样。
环境
这里以ubuntu为例(工作上实际使用的是centos)
安装软件
sudo apt-get install git
sudo apt-get install openssh-server
ssh配置相关操作:
sudo vim /etc/ssh/sshd_config
ps -e | grep ssh
sudo /etc/init.d/ssh start
sudo /etc/init.d/ssh resart
sudo /etc/init.d/ssh stop
创建git用户
专门创建git用户,便于控制权限和管理
sudo adduser git
sudo passwd jayfeng
初始化仓库
以android为例子,创建一个对应的仓库
cd
mkdir git-repo
cd git-repo
git init --bare ANDROID_CODE.git
配置ssh key
如果不做这一步,后面从局域网clone代码的时候每次都要输入git用户的密码,所以这一步的目的是通过配置ssh认证,实现免密码同步代码。
下图展示了如何生成ssh key的私钥和公钥:
私钥id_rsa自己用,把公钥id_rsa.pub配置到服务器端git用户的~/.ssh/authorized_keys(即,把id_rsa.pub的内容添加到authorized_keys新一行),同时配置权限:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
并把生成的私钥id_rsa共享给团队的开发人员。
局域网访问
如果服务器的IP是192.168.1.18,那么局域网的机器就可以通过下面的方式访问了:
mv id_rsa ~/.ssh
cd ~/.ssh
chmod 700 id_rsa
git clone git@192.168.1.18:~/git-repo/ANDROID_CODE.git
小结
小团队使用git,一方面要利用起git的强大功能,一方面要还要摒弃冗余的配置。本次记录了局域网内的git环境搭建。接下来的难点就是如何在公司中培训推广git的使用,克服初学git的陡峭曲线>(相对于svn来说)。
对于初学者,从使用上先入手,往往学的最快,并从中汲取教训,再回头更深入的学习,效果尤佳。
安装git
安装git自不必说,mac已经内置了git,linux下一个命令就能搞定,windows下需要下载一个客户端安装,一切尽在官方网站:
http://git-scm.com/
配置自定义信息
1
2
3
|
git config --global user.name "Jayfeng"
git config --global user.email jayfeng@gmail.com
|
同步仓库代码
假设服务器IP是192.168.1.18:
1
| git clone git@192.168.1.18:~/git-repo/ANDROID_CODE.git
|
提交
1
2
3
4
5
6
|
git add .
git commit .
git push origin master
|
更新代码
1
2
3
4
5
6
7
|
git pull
git fetch origin master
git rebase origin/master
|
冲突
在上步中,很有可能会冲突,解决冲突的步骤如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
git status
git add .
git rebase --continue
git rebase --abort
git rebase --skip
|
分支(branch)和标签(tag)
标签,也叫里程碑,顾名思义,就是一个重要的标示,以commit的形式存在。
1
2
3
4
5
6
7
8
9
10
11
|
git tag -a 1.0.3 -m 'publish a version 1.0.3'
git show 1.0.3
git push origin 1.0.3
git push origin --tags
git checkout -b myTagBranch 1.0.3
|
分支,相当于独立承载另外需求的代码副本,常用于区分管理不同版本的代码。
1
2
3
4
5
6
|
git checkout -b dev
git push origin dev:dev
git branch -D dev
|
git的分支功能是非常强大和灵活的,能够提供多个代码副本共存的方便,大大节省了维护多版本的人力成本。
重置(reset)
回退到某个版本。
1
2
3
4
| // 回到到324214130的tree index,默认参数--mixed, 保留源码,代码状态回退到工作区
git reset 3242a4130142478023231225551a9b7dcb4441e3
// 另外两个参数分别是--soft、--hard, 分别是比--mixed回退的更少一步和更彻底一步。
// 放到下篇文章继续深讲。
|
反悔/撤销(revert)
回退某个版本,注意区分和reset的不同。revert是属于commit级别的操作。
1
2
| // 回退324214130的commit,相当于把这个commit的改动再反向操作了一次
git revert 3242a4130142478023231225551a9b7dcb4441e3
|
revert只针对这个提交,对它的前面和后面的提交没有直接的影响(相对于reset来说)。同时git会把revert操作当成一个新的commit,可以在git log中看的到。
小结
本篇把基本使用git的一些命令一一讲解了一番,以期初学者能上手实用起来。而有些地方则是蜻蜓点水,未作深入,因为我们还有最后一章深入篇,敬请期待!
在上篇中,我们已经能基本使用git了,接下来继续更深入的挖掘一下git。
更多的配置自定义信息
除了前面讲的用户名和邮箱的配置,还可以自定义其他配置:
1
2
3
4
5
6
7
|
git config --global core.editor vim
git config --global merge.tool vimdiff
git config --global mergetool.prompt false
git config --global color.ui true
|
还有一些配置,比如core.autocrlf,core.whitespace等等就点到为止,不做赘述。
忽略文件 — 使用.gitignore
git支持使用.gitignore文件定义忽略规则,一行一个。
gitignore文件只能忽略非版本库的文件,对于已经添加到版本库的文件,需要先删除掉才能忽略。
所以,一般.gitignore文件建议在创建项目的时候就加进来,这样可以减少不必要的麻烦,不必把一些中间生成文件添加到版本库。
以Android为例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
*.apk
*.ap_
*.dex
*.class
bin/
gen/
local.properties
.classpath
.project
.idea/
.gradle
/*/local.properties
/*/out
build
/*/*/production
*.iml
*.iws
*.ipr
*~
*.swp
|
两个重要概念
git最基础也是最重要的两个概念:对象模型和版本跟踪结构。
-
对象模型定义了git版本存储的方式。
每一次提交git会根据内容生成一个SHA1值,作为对象名。
-
版本跟踪结构分为4个部分:工作区,暂存区,本地仓库,远程仓库。
修改提交
难免在提交之后发现一些错误,希望能亡羊补牢补救一下,这就需要使用如下命令。
1
2
3
4
5
6
7
|
git commit --amend
git rebase -i origin/master
git rebase -i HEAD~2
|
简单的修改提交可能是合理的,但是合并提交,就需要考虑到提交的目的,不建议把完全独立的提交硬是合并在一起, 从工程上会降低版本管理的意义,同时增大了合并到其他分支出错的可能性。
cherry-pick — 分支之间的smart merge
前面讲到了branch,它的使用场景下,有一种常见的操作,就是把某个commit也合并到另外一个分支B,怎么做呢?
1
2
3
4
| // 切换到分支B
git checkout B
// 把之前的commit使用cherry-pick命令到当前分支
git cherry-pick 5d1c8562cd3d6b902e7d1542940ba39a97179017
|
reset的艺术
git reset的艺术就在于它的几个参数的使用。
当了解上面定义的版本库,暂存区,工作区概念之后,reset的几个参数的区别就非常好说明了,我画了一张图:
二分法定位问题 — git bisect的使用
如果一个项目的提交非常对,面对一个不知道什么时候出现的bug,git借用了二分法平均时间最快的思想,提供了git bisect命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 开始查找, 对应最后面的结束查找
git bisect start
// 标记当前版本为错误
git bisect bad
// 标记5d1c8562cd3d6b902e为正确的版本
git bisect good 5d1c8562cd3d6b902e
// 现在git会自动选取bad和good的中间版本
// ...
// 我们能做的就是不断的测试并标记这些中间版本时good还是bad,直到找到问题
// git bisect good 或者git bisect bad
// ...
// 结束查找,回到开始查找之前的状态
git bisect reset
|
这行代码是谁加的 — git blame助你火眼金睛
git blame命令可以查看每个文件的每一行的版本信息,包括提交SHA,日期,作者:
1
| git blame ./lesscode-core/src/main/java/com/jayfeng/lesscode/core/AdapterLess.java
|
结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| 406962f0 (Jay 2015-02-05 19:31:17 +0800 1) package com.jayfeng.lesscode.core;
406962f0 (Jay 2015-02-05 19:31:17 +0800 2)
406962f0 (Jay 2015-02-05 19:31:17 +0800 3) import android.content.Context;
8ee8388a (Jay 2015-05-23 18:20:40 +0800 4) import android.support.v4.app.Fragment;
8ee8388a (Jay 2015-05-23 18:20:40 +0800 5) import android.support.v4.app.FragmentManager;
8ee8388a (Jay 2015-05-23 18:20:40 +0800 6) import android.support.v4.app.FragmentPagerAdapter;
a03f8aa3 (Jay 2015-05-23 16:59:05 +0800 7) import android.support.v4.view.PagerAdapter;
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 8) import android.support.v7.widget.RecyclerView;
406962f0 (Jay 2015-02-05 19:31:17 +0800 9) import android.util.SparseArray;
406962f0 (Jay 2015-02-05 19:31:17 +0800 10) import android.view.LayoutInflater;
406962f0 (Jay 2015-02-05 19:31:17 +0800 11) import android.view.View;
406962f0 (Jay 2015-02-05 19:31:17 +0800 12) import android.view.ViewGroup;
406962f0 (Jay 2015-02-05 19:31:17 +0800 13) import android.widget.BaseAdapter;
406962f0 (Jay 2015-02-05 19:31:17 +0800 14)
406962f0 (Jay 2015-02-05 19:31:17 +0800 15) import java.util.List;
406962f0 (Jay 2015-02-05 19:31:17 +0800 16)
4719215f (think 2015-02-06 22:06:50 +0800 17) public class AdapterLess {
406962f0 (Jay 2015-02-05 19:31:17 +0800 18)
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 19) public static <T> RecyclerView.Adapter<RecycleViewHolder> $recycle(final Context context,
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 20) final List<T> list,
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 21) final int layoutId,
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 22) final RecycleCallBack recycleCallBack) {
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 23) RecyclerView.Adapter<RecycleViewHolder> result = new RecyclerView.Adapter<RecycleViewHolder>() {
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 24) @Override
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 25) public RecycleViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 26) View view = LayoutInflater.from(context)
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 27) .inflate(layoutId, viewGroup, false);
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 28) RecycleViewHolder recycleViewHolder = new RecycleViewHolder(view);
2cf7bb1c (Jay 2015-07-26 11:59:18 +0800 44) ... ...
|
小结
git作为小而美的工具,开创了一个版本控制的新时代。
学习git是一个循序渐进的过程,通过结合基本使用方法和实践场景的练习,达到熟练使用的程度,可成!