Skip to content

Commit ba7fab5

Browse files
author
jerryzhang
committed
加版本管理
1 parent 4919e29 commit ba7fab5

File tree

2 files changed

+266
-0
lines changed

2 files changed

+266
-0
lines changed

版本管理/git.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# 分布式管理系统 Git
2+
3+
## 一、Git基础
4+
5+
### 1.1 环境配置
6+
7+
+ `git config user.name your_name` : 设置你的用户名, 提交会显示
8+
+ `git config user.email your_email` : 设置你的邮箱
9+
+ `git config core.quotepath false` : 解决中文文件名显示为数字问题
10+
11+
### 1.2 基本操作
12+
13+
+ `git init` : 初始化一个 git 仓库
14+
+ `git add <filename>` : 添加一个文件到 git 仓库中
15+
+ `git commit -m "commit message"`: 提交到本地
16+
+ `git push [remote-name] [branch-name]` : 把本地的提交记录推送到远端分支
17+
+ `git pull`: 更新仓库 `git pull` = `git fetch` + `git merge`
18+
+ `git checkout -- <file>` : 还原未暂存(staged)的文件
19+
+ `git reset HEAD <file>...` : 取消暂存,那么还原一个暂存文件,应该是先 `reset``checkout`
20+
+ `git stash` : 隐藏本地提交记录, 恢复的时候 `git stash pop`。这样可以在本地和远程有冲突的情况下,更新其他文件
21+
22+
### 1.3 分支
23+
24+
+ `git branch <branch-name>` : 基于当前 commit 新建一个分支,但是不切换到新分支
25+
+ `git checkout -b <branch-name>` : 新建并切换分支
26+
+ `git checkout <branch-name>` : 切换分支
27+
+ `git branch -d <branch-name>` : 删除分支
28+
+ `git push origin <branch-name>` : 推送本地分支
29+
+ `git checkout -b <local-branch-name> origin/<origin-branch-name>` : 基于某个远程分支新建一个分支开发
30+
+ `git checkout --track origin/<origin-branch-name>` : 跟踪远程分支(创建跟踪远程分支,Git 在 `git push` 的时候不需要指定 `origin``branch-name` ,其实当我们 `clone` 一个 repo 到本地的时候,`master` 分支就是 origin/master 的跟踪分支,所以提交的时候直接 `git push`)。
31+
+ `git push origin :<origin-branch-name>` : 删除远程分支
32+
33+
### 1.4 标签
34+
35+
+ `git tag -a <tagname> -m <message>` : 创建一个标签
36+
+ `git tag` : 显示已有的标签
37+
+ `git show tagname`: 显示某个标签的详细信息
38+
+ `git checkout -b <tag-name>` : 基于某个 tag 创建一个新的分支
39+
40+
### 1.5 补丁
41+
42+
先占个坑。
43+
44+
### 1.6 Git shortcuts/aliases
45+
46+
git config --global alias.co checkout
47+
git config --global alias.br branch
48+
git config --global alias.ci commit
49+
git config --global alias.st status
50+
51+
## 二、知识点
52+
53+
基本命令让你快速的上手使用Git,知识点能让你更好的理解Git。
54+
55+
### 2.1 文件的几种状态
56+
57+
+ untracked: 未被跟踪的,没有纳入 Git 版本控制,使用 `git add <filename>` 纳入版本控制
58+
+ unmodified: 未修改的,已经纳入版本控制,但是没有修改过的文件
59+
+ modified: 对纳入版本控制的文件做了修改,git 将标记为 modified
60+
+ staged: 暂存的文件,简单理解: 暂存文件就是 add 之后,commit 之前的文件状态
61+
62+
理解这几种文件状态对于理解 Git 是非常关键的(至少可以看懂一些错误提示了)。
63+
64+
### 2.2 快照和差异
65+
66+
详细可看:[Pro Git: Git基础](http://iissnan.com/progit/html/zh/ch1_3.html)中有讲到 *直接记录快照,而非差异比较*,这里只讲我个人的理解。
67+
68+
Git 关心的是文件数据整体的变化,其他版本管理系统(以svn为例)关心的某个具体文件的*差异*。这个差异是好理解的,也就是两个版本具体文件的不同点,比如某一行的某个字符发生了改变。
69+
70+
Git 不保存文件提交前后的差异,不变的文件不会发生任何改变,对于变化的文件,前后两次提交则保存两个文件。举个例子:
71+
72+
SVN:
73+
74+
1. 新建3个文件a, b, c,做第一次提交 -> `version1 : file_a file_b file_c`
75+
2. 修改文件 b, 做第二次提交(真正提交的是 修改后的文件 b 和修改前的 `file_b` 的 diff) -> `version2: diff_b_2_1`
76+
3. 当我要 checkout version2 的时候,实际上得到的是 `file_a file_b+diff_b_2_1 file_c`
77+
78+
Git:
79+
80+
1. 新建3个文件a, b, c,做第一次提交 -> `version1 : file_a file_b file_c`
81+
2. 修改文件 b (得到`file_b1`), 做第二次提交 -> `version2: file_a file_b1 file_c`
82+
3. 当我要用 version2 的时候,实际上得到的是 `file_a file_b1 file_c`
83+
84+
上面的 `file_a file_b1 file_c` 就是 version2 的 *快照*
85+
86+
### 2.3 Git数据结构
87+
88+
Git的核心数是很简单的,就是一个链表(或者一棵树更准确一些?无所谓了),一旦你理解了它的基本数据结构,再去看Git,相信你有不同的感受。继续用上面的例子(所有的物理文件都对应一个 SHA-1 的值)
89+
90+
当我们做第一次提交时,数据结构是这样的:
91+
92+
93+
sha1_2_file_map:
94+
28415f07ca9281d0ed86cdc766629fb4ea35ea38 => file_a
95+
ed5cfa40b80da97b56698466d03ab126c5eec5a9 => file_b
96+
1b5ca12a6cf11a9b89dbeee2e5431a1a98ea5e39 => file_c
97+
98+
commit_26b985d269d3a617af4064489199c3e0d4791bb5:
99+
base_info:
100+
Auther: "JerryZhang(chinajiezhang@gmail.com)"
101+
Date: "Tue Jul 15 19:19:22 2014 +0800"
102+
commit_content: "第一次提交"
103+
file_list:
104+
[1]: 28415f07ca9281d0ed86cdc766629fb4ea35ea38
105+
[2]: ed5cfa40b80da97b56698466d03ab126c5eec5a9
106+
[3]: 1b5ca12a6cf11a9b89dbeee2e5431a1a98ea5e39
107+
pre_commit: null
108+
next_commit: null
109+
110+
当修改了 `file_b`, 再提交一次时,数据结构应该是这样的:
111+
112+
sha1_2_file_map:
113+
28415f07ca9281d0ed86cdc766629fb4ea35ea38 => file_a
114+
ed5cfa40b80da97b56698466d03ab126c5eec5a9 => file_b
115+
1b5ca12a6cf11a9b89dbeee2e5431a1a98ea5e39 => file_c
116+
39015ba6f80eb9e7fdad3602ef2b1af0521eba89 => file_b1
117+
118+
commit_26b985d269d3a617af4064489199c3e0d4791bb5:
119+
base_info:
120+
Auther: "JerryZhang(chinajiezhang@gmail.com)"
121+
Date: "Tue Jul 15 19:19:22 2014 +0800"
122+
commit_content: "第一次提交"
123+
file_list:
124+
[1]: 28415f07ca9281d0ed86cdc766629fb4ea35ea38
125+
[2]: ed5cfa40b80da97b56698466d03ab126c5eec5a9
126+
[3]: 1b5ca12a6cf11a9b89dbeee2e5431a1a98ea5e39
127+
pre_commit: commit_a08a57561b5c30b9c0bf33829349e14fad1f5cff
128+
next_commit: null
129+
130+
commit_a08a57561b5c30b9c0bf33829349e14fad1f5cff:
131+
base_info:
132+
Auther: "JerryZhang(chinajiezhang@gmail.com)"
133+
Date: "Tue Jul 15 22:19:22 2014 +0800"
134+
commit_content: "更新文件b"
135+
file_list:
136+
[1]: 28415f07ca9281d0ed86cdc766629fb4ea35ea38
137+
[2]: 39015ba6f80eb9e7fdad3602ef2b1af0521eba89
138+
[3]: 1b5ca12a6cf11a9b89dbeee2e5431a1a98ea5e39
139+
pre_commit: null
140+
next_commit: commit_26b985d269d3a617af4064489199c3e0d4791bb5
141+
142+
当提交完第二次的时候,执行 `git log`,实际上就是从 `commit_a08a57561b5c30b9c0bf33829349e14fad1f5cff` 开始遍历然后打印 `base_info` 而已。
143+
144+
实际的 git 实际肯定要比上面的结构((的信息)的)要复杂的多,但是它的核心思想应该是就是,每一次提交就是一个新的结点。通过这个结点,我可以找到所有的快照文件。再思考一下,什么是分支?什么是 Tags,其实他们可能只是某次提交的引用而已(一个 `tag_head_node` 指向了某一次提交的node)。再思考怎么回退一个版本呢?指针偏移!依次类推,上面的基本命令都可以得到一个合理的解释。
145+
146+
**理解git fetch 和 git pull的差异**
147+
148+
上面我们说过 `git pull` 等价于 `git fetch` 和 `git merge` 两条命令。当我们 `clone` 一个 repo 到本地时,就有了本地分支和远端分支的概念(假定我们只有一个主分支),本地分支是 `master`,远端分支是 `origin/master`。通过上面我们对 Git 数据结构的理解,`master` 和 `origin/master` 可以想成是指向最新 commit 结点的两个指针。刚 `clone` 下来的 repo,`master` 和 `origin/master` 指针指向同一个结点,我们在本地提交一次,`origin` 结点就更新一次,此时 `master` 和 `orgin/master` 就不再相同了。很有可能别人已经 commit 改 repo 很多次了,并且进行了提交。那么我们的本地的 `origin/master` 就不再是远程服务器上的最新的位置了。 `git fetch` 干的就是从服务器上同步服务器上最新的 `origin/master` 和一些服务器上新的记录/文件到本地。而 `git merge` 就是合并操作了(解决文件冲突)。`git push` 是把本地的 `origin/master` 和 `master` 指向相同的位置,并且推送到远程的服务器。
149+
150+
*理论部分是我个人对 Git 的理解,难免有偏差,看看就可以了。*
151+
152+
153+
## 三、参考资料
154+
155+
+ [Pro Git](http://iissnan.com/progit/)
156+
+ [Git shortcuts/aliases - How to create](http://alvinalexander.com/git/git-shortcuts-aliases-long-commands-how-to-create)

版本管理/svn.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# 版本管理工具: SVN
2+
3+
本文由 [svn book 1.4](http://svndoc.iusesvn.com/svnbook/1.4) 整理而来。
4+
5+
`svn help <SUBCOMMAND>`: 查看子命令用法、参数及行为方式。
6+
7+
## 一、创建一个svn仓库
8+
9+
+ `svnadmin create /user/local/svn/newrepos`: 创建一个新的 repo
10+
+ `svn import YourDir file:///usr/local/svn/newrepos/some/project -m "Init import"` : 把未版本化的文件导入版本库
11+
+ `svn list file:///usr/local/svn/newrepos/some/project`: 查看文件列表
12+
+ `svn export http://svn.example.com/svn/repos1` : 导出一份干净的仓库(没有.svn文件)
13+
14+
## 二、基本使用
15+
16+
+ `svn checkout <repo-url>` : 检出到本地
17+
+ `svn update` : 更新工作拷贝
18+
+ `svn add foo` : 将文件、目录或者符号链添加到版本库(提交后生效)
19+
+ `svn delete foo` : 将文件、目录或者符号链从版本库中移除(提交后生效)
20+
+ `svn copy foo bar` : 拷贝
21+
+ `svn move foo bar` : 重命名
22+
+ `svn mkdir blort` : 等价于 `mkdir blort; svn add blort`
23+
+ `svn status` : 浏览你所做的修改。`-v` 显示所有项目文件的状态;`-u` 显示是否过期。
24+
- `A item` : 预定加入到版本库的文件、目录或符号链的item
25+
- `C item` : 文件 item 发生冲突,在从服务器更新时与本地版本发生交跌,在你提交到版本库前,必须手工的解决冲突
26+
- `D item` : 文件、目录或是符号链 item 预定从版本库中删除
27+
- `M item` : 文件 item 的内容被修改了
28+
+ `svn diff` : 查看详细的信息,`-r` 指定比较版本
29+
+ `svn revert` : 取消本地修改
30+
+ `svn resolved` : 解决完冲突后通知svn(当 update 有冲突时会生成 3 个临时文件: filename.mine, filename.rOLDREV, filename.rNEWREV,resolved 告诉 svn 删除那3个临时文件)
31+
+ `svn commmit` : 提交修改, `-m` 添加描述修改信息
32+
+ `svn log` : 查看日志,`-r` 显示某一个版本, `-v` 详细模式
33+
+ `svn cat` : 取特定版本的某一个文件显示在当前屏幕,`-r` 显示指定版本
34+
+ `svn list` : 显示一个目录在某一版本存在的文件
35+
+ `svn cleanup` : 它查找工作拷贝中的所有遗留的日志文件,删除进程中工作拷贝的锁
36+
37+
## 三、高级使用
38+
39+
### 3.1 属性
40+
41+
属性不是版本化的,如果你修改,删除一个修订版本属性,SVN 没有办法恢复到以前的值。
42+
43+
+ `svn propset` : 添加和修改文件或目录的属性
44+
+ `svn propedit` : 使用定制的编辑器程序来添加和修改属性
45+
+ `svn proplist` : 列出路径上存在的所有属性名称
46+
+ `svn propget` : 获取属性的值
47+
+ `svn propdel` : 删除某个属性
48+
49+
### 3.2 忽略未版本控制的条目
50+
51+
SVN 忽略方法和 git 不同,git 是在本地加一个 `.gitigore` 即可,SVN 是通过属性(svn:ignore)来实现的。
52+
53+
`svn propedit svn:ignore work_dir` : 在工作目录 work_dir 下添加过滤文件
54+
55+
### 3.3 外部定义
56+
57+
引用场景:多个目录共享同一个目录。以游戏开发为例,UI、服务器、策划共享的数据表,这个时候就可以用到 *外部定义* 这个概念了。我理解外部定义就相当于 linux 下的软链接。
58+
59+
一个外部定义是一个本地路经到 URL 的影射—也有可能一个特定的修订版本—一些版本化的资源。在 SVN 你可以使用 `svn:externals` 属性来定义外部定义,你可以用 `svn propset`` svn propedit` 创建和修改这个属性。它可以设置到任何版本化的路经,它的值是一个多行的子目录,可选的修订版本标记和完全有效的 SVN 版本库 URL 的列表(相对于设置属性的版本化目录)。
60+
61+
可以使用 `--ignore-externals` 来忽略 externals。
62+
63+
64+
## 四、分支与合并
65+
66+
### 4.1 分支创建与删除
67+
68+
SVN 分支其实只是做了一份拷贝而已(svn copy), 但是它并不是物理意义上的拷贝(完全复制一份,可以理解成 Linux 的硬链接, *廉价复制* )。
69+
70+
svn copy http://svn.example.com/repos/calc/trunk \
71+
http://svn.example.com/repos/calc/branches/my-calc-branch \
72+
-m "Creating a private branch of /calc/trunk."
73+
74+
+ `svn delete http://svn.example.com/repos/calc/branches/my-calc-branch -m "Removing obsolete branch of calc project."` : 删除一个分支
75+
76+
### 4.2 在分支上工作
77+
78+
`checkout` 一份呗。
79+
80+
### 4.3 合并分支
81+
82+
svn diff -c 344 http://svn.example.com/repos/calc/trunk
83+
svn merge -c 344 http://svn.example.com/repos/calc/trunk
84+
85+
合并分支看似简单,其实是一件非常头疼的事情(尤其是大项目)。我宁愿去选择一些可视化的文本比较工作,比如 [BeyondCompare](http://www.scootersoftware.com/),可以为你省下太多事情了。
86+
87+
[版本库管理](http://svndoc.iusesvn.com/svnbook/1.4/svn.reposadmin.html) 之后的章节感兴趣去看看(上面提供的命令足够应付大多数使用情况了)
88+
89+
## 五、知识点
90+
91+
### 5.1 四种文件状态(svn status)
92+
93+
1. 未修改且是当前的, 文件在工作目录里没有修改,在工作修订版本之后没有修改提交到版本库。svn commit操作不做任何事情,svn update不做任何事情。
94+
2. 本地已修改且是当前的, 在工作目录已经修改,从基本修订版本之后没有修改提交到版本库。本地修改没有提交,因此svn commit会成功提交,svn update不做任何事情。
95+
3. 未修改且不是当前的了, 这个文件在工作目录没有修改,但在版本库中已经修改了。这个文件最终将更新到最新版本,成为当时的公共修订版本。svn commit不做任何事情,svn update将会取得最新的版本到工作拷贝。
96+
4. 本地已修改且不是最新的, 这个文件在工作目录和版本库都得到修改。一个svn commit将会失败,这个文件必须首先更新,svn update命令会合并公共和本地修改,如果Subversion不可以自动完成,将会让用户解决冲突。
97+
98+
### 5.2 修订版本关键字
99+
100+
这些关键字可以用来代替 `--revision(r)` 的数字参数,这会被 Subversion 解释到特定的修订版本号。
101+
102+
+ `HEAD` : 版本库中最新的(或者是 "最年轻的")版本。
103+
+ `BASE` : 工作拷贝中一个条目的修订版本号,如果这个版本在本地修改了,则“BASE版本”就是这个条目在本地未修改的版本。
104+
+ `COMMITTED` : 项目最近修改的修订版本,与BASE相同或更早。
105+
+ `PREV` : 一个项目最后修改版本之前的那个版本,技术上可以认为是COMMITTED -1。
106+
107+
### 5.3 SVN 和 Git
108+
109+
我感觉 SVN 和 Git 设计的本质区别在于 SVN 核心点在于它的目录,而 Git 的核心点在于它的 Commit(结点)。这也就说明了 SVN 可以 checkout 某一个目录,Git 不行。SVN 的分支可以理解成一个目录,而 Git 的分支只不过是某个 Commit 上的快照而已。
110+

0 commit comments

Comments
 (0)