Git使用指南
Udacity
Git课程学习笔记
为什么要使用Git
Git是一种版本控制(version control) 工具。在我们做一些个人项目时,版本控制似乎不那么重要,我们先开发出一个原型,然后再小心翼翼的进行迭代,增加新的功能。如果我们将版本控制应用于开发个人项目,那么我们可以在保留主线开发的同时,不用那么小心翼翼的实验新的功能。而对于多人协作项目,版本控制更加不可或缺,因为在相同的时间段并在同一文件上进行编辑,冲突几乎不可避免。我们需要使用像Git一样的版本控制工具来协调大家的工作。首先考虑同一文件不同版本的问题,为了比较两个版本的不同,在Linux下,我们可以使用diff命令来输出两个文件的不同,例如
diff -u old.txt new.txt
同样,Git也有类似的git diff来比较同一文件不同历史版本的不同,这两个命令的输出结果是很相似的。
需要注意的是,这两个diff命令都是逐行比较的,如果一行中有多处不同,diff只会告诉你这行有不同,而不会告诉你有多少不同,所以如果想使用diff命令来比较文件版本,编辑文件时,每行控制在80 - 120个字符为宜。
版本控制
不同版本控制方法比较-人工保存:给不同版本起不同的文件名以达到版本控制的目的
-Dropbox:会保存30天内的文件版本
-Google Docs
-Wikipedia
-Git
-SVN
多久进行一次commit
在一次logical change后进行commit,比如修复了一个bug,增添了一个功能,git -stat查看
git -version 查看电脑git的版本
克隆整个目录Repository
Git clone-查看最近的commit以及相关信息,git log,退出git log按下q
-彩色化diff输出,git config --global color.ui auto,git diff first_id second_id
-在终端内复制粘贴Ctrl+Shift+C and Ctrl+Shift+V.
Git checkout
Git checkout 和 svn checkout 不同。git checkout 可以帮助我们回到某一次commit时文件的状态。如果我们在测试程序时发现bug而不知道bug在哪一次commit中引入,那么我们可以checkout历史commit来定位bug。Git checkout commit_id,其中commit_id 可以只输入前四位
工作环境设置
详细步骤请查阅《给Ubuntu安装sublime并配置git工作环境》总结四个常用git command
git diff
Git diff old_file new_file,用来比较两次commit,输出两个版本的不同git clone
Git clone http_url复制整个git repository到本地目录,包括历史版本记录git checkout
Git checkout commit_id暂时性把一个repository里的所有文件重置到特定commit时期。一次commit就好像snapshot了一个repository下的所有文件,使用checkout就像用时光机一样把这个目录下的所有文件恢复到commit发生时的状态。git log
输出一个repository下的所有历史commit记录,并从最新的commit开始输出初始化Git目录
Git init,初始化当前目录为git repository。这时系统在当前目录初始化一个空的版本库,其文件名为.git,是一个隐藏文件,其中包括当前目录下的版本控制信息。这时候如果我们用git log以图查看历史commit记录,此时系统会显示fatal: bad default revision 'HEAD' |
Working directory | Staging area | repository |
如何写commit信息
git commit -m “Commit message” 而不是直接使用git commit,我们可以在“Commit message”里写上有关此次commit的一些评论信息,有关写作这个信息的规范,可以查阅http://udacity.github.io/git-styleguide/
如果之前工作环境配置成功,在输入git commit命令后会自动弹出sublime,并提示我们输入commit message。commit成功后再次使用git status我们会得到
位于分支 master
未跟踪的文件: (使用 "git add <file>..." 以包含要提交的内容) lesson_1_reflections.txt 提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪) |
Git diff 详解
一共有三种git diffWorking directory | Staging area | repository |
file1 file2 |
file1 file2 |
commit1 commit2 |
git diff
比较Working directory和Staging area的不同git diff –staged
比较Staging area和repository的不同git diff commit1 commit2
比较repository中commit1与commit2中的不同,就是我们之前使用的commitgit reset –hard
使用这条命令可以放弃Working directory与Staging area中的所有改变,要谨慎使用。先使用git diff和git diff --staged确保Working directory与Staging area中的改变确实是自己想要放弃的,否则reset的过程是不可逆的。进入“detached HEAD”状态
HEAD相当与一个指针,默认情况下,它指向我们的master分支,如果我们使用命令git checkout c1(c1是历史中的某一个commit),那么HEAD便指向了这个commit而不是一个分支,我们便进入了“detached HEAD”状态版权声明:以下图片来自于在线Git Branch教程Learn Git Branching,地址为:http://pcottle.github.io/learnGitBranching/
开始 | Git命令 | 结束 |
git
checkout c1 注意:c1代表commit 1的hash值,我们可以通过git log来查看某次commit的hash值 |
从“detached HEAD”状态中离开
如果我们checkout了历史中的一个commit,就会进入detached HEAD状态。在terminal中输入git checkout master命令能使我们离开这个状态,重新回到master分支。HEAD表示当前commit,如果我们checkout 一个不是current commit的历史commit,我们就会收到”detached HEAD” state警告。
在”detached HEAD” 状态中,我们可以
- 做出试验性质的改变并commit
- 使用另外一个checkout,在不影响任何branches的情况下放弃这个状态下的所有commit
- 使用git
checkout -b
new_branch_name建立新的branch并进入该branch来保留我们在这个状态下做出的commit,之后terminal会提示HEAD已经转移到当前branch下的current
commit
git
branch new_branch_name #建立新branch,此时master标签和新branch标签都指向当前commit git checkout new_branch_name #进入新branch,此时branch标签领先master标签一个commit |
一个例子
commit1提交与commit2之前,commit2中发现程序bug而通过git checkout commit1却发现程序运行正常,如何修改master brunch的代码并commit呢?Working directory | Staging area | repository |
file1 file2 |
file1 file2 |
commit1 commit2 |
2,修改file1中有bug的代码片段
Working directory | Staging area | repository |
file1* file2 |
file1 file2 |
commit1 commit2 |
Working directory | Staging area | repository |
file1* file2 |
file1* file2 |
commit1 commit2 |
5,最后再用git commit
Working directory | Staging area | repository |
file1* file2 |
file1* file2 |
commit1 commit2 commit3 |
创建分支
使用git branch可以查看当前分支,terminal输出*master中的星号表示master branch是当前默认分支,我们将来所做的更改会自动更新master branch的内容。使用git branch branch_name 来创建新的分支,并使用git checkout branch_name来切换到branch_name分支,这样branch_name变成为默认分支,我们将来所做的改变会自动应用到该分支上。图形化查看commit历史
如果想要图形化不同分支间的commit历史,我们可以使用git log –graph –oneline master branch_name来显示图形化的git log表示。合并分支:使用merge
合并分支的原则:简单情况
我们用大写字母A,B,C,D,E表示代码块,合并kevin和lisa的分支为一个分支的 final version会包含哪些代码块呢?初始代码 | 工作了一天的kevin的代码 | 工作了一天的lisa的代码 |
? | A,B,D | B,C,D,E |
初始代码 | 工作了一天的kevin的代码 | 工作了一天的lisa的代码 |
A,C,D | A,B,D | B,C,D,E |
合并分支的原则:复杂情况
初始代码 | 工作了一天的kevin的代码 | 工作了一天的lisa的代码 |
A,C,D | A,C',D | B,C”,E |
这时候git会告诉我们这个情况,并且有我们(users)来决定哪个版本应该留下来。
进行合并(Merge)
假设我们要合并branch1和banch2,并以branch1为当前分支(current branch),也就是把branch2合并到branch1中,步骤如下- git
checkout branch1
- git
merge branch2 (等价与git
merge branch1 branch2)
合并冲突(Merge conflict)
- 使用git
merge –abort终止合并
- 使用git
log和git
diff来查找冲突产生的原因
- 找到冲突原因后修改相应的文件,再进行一次commit
- 重新合并分支
合并冲突的另一种情形
在master branch工作的同时,我们也许有一个实验性质的exp branch。随着master branch的更新,我们也希望exp branch有master branch的新特性。如何去做呢?- 切换到exp
branch,git
checkout exp
- 在exp
branch下合并master
branch,git
merge master exp
- 如果terminal提示合并冲突与某个文件,那么用文本编辑器打开这个文件来修正冲突
<<<<<<<
HEAD
// exp branch上的代码 ||||||| merged common ancestors // exp 与master共同parent的代码 ======= //master branch上的代码 >>>>>>> master |
- 发生冲突的代码段会有上述符号帮助我们判断哪些代码应该留下来,哪些应该删除。使用git
status查看当前合并状态,terminal会提示有both
modified的文件,这是因为要合并的两个分支都修改了该文件,正是如此,才会造成冲突
- 修改冲突文件(both
modified文件)后,使用git
add both_modified_file,再用git
status查看当前状态,terminal提示我们冲突已经解决但我们仍在合并状态中。这时再使用git
commit来结束当前合并状态
- 如果之前配置好了工作环境,这时sublime会弹出并为我们填写好了commit
message,之后使用git
log -n1查看最新一次commit来确保merge成功。
分支合并后对git log的影响
例如将两个分支合并,我们使用git log来查看历史commit记录,terminal的输出会怎么样呢?这时git log的会按照commit的时间戳(time stamp)来依次显示历史commit。这样做会造成一个问题,在我们使用git diff比较两次相邻的commit时,时间上相邻的两次commit也许并不是父子关系,这样比较的结果会现实两个文件有较大出入,而这并不是我们想要的。如何比较一次commit和它parent的不同呢?我们可以使用 git show commit_id命令,来比较commit_id和它parent的不同。我们假设commit2的id是commit_id,commit1的parent,commit1的id是commit_parent,那么git show commit_id命令等价与git diff commit_parent commit_id,注意两者的顺序。合并分支:使用rebase
使用rebase是要注意当前分支是什么版权声明:以下图片来自于在线Git Branch教程Learn Git Branching,地址为:http://pcottle.github.io/learnGitBranching/
开始 | Git命令 | 结束 |
当前位于bugFix分支 Git checkout bugFix git rebase master |
||
当前位于master分支 git rebase bugFix 解释:master所在commit是bugFix所在commit的ancestor,在master分支下使用rebase bugFix使得master在commit历史中前进了一步 |
删除分支
使用git branch -d branch_name来删除分支如果一个分支被删除,现有分支就无法到达已删除分支中的commit。这些分支却仍然可以用commit id到达,直到Git的垃圾回收开始运行。Git的垃圾回收会定期的运行,清除这些无法到达的commit,除非我们手动将它关闭。我们可以使用git gc开手动开启Git的垃圾回收,以此清除不必要文件以及优化本地repository。
在线学习Git网站
https://www.udacity.com/courses/ud775http://pcottle.github.io/learnGitBranching/
No comments:
Post a Comment