创建版本库
第一步
1: $ mkdir learngit
2: $ cd learngit
3: 显示当前目录
4: $ pwd
5: /Users/michael/learngit
第二步
1: $ git init
2: Initialized empty Git repository in /Users/michael/learngit/.git/
把文件添加到版本库
以纯文办的方式进行编码,注意编码问题
编写一个readme.txt文件,内容如下:放到learngit目录下(子目录也行)
1: Git is a version control system.
2: Git is free software.
第一步,用命令git add告诉Git,把文件添加到仓库:
1: $ git add readme.txt
执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。
第二步,用命令git commit告诉Git,把文件提交到仓库:
1: $ git commit -m "wrote a readme file"
正确显示,""里面的是本次提交的说明
commit可以一次提交很多文件,所以你可以多次add不同的文件。
1: [master (root-commit) eaadf4e] wrote a readme file
2: 1 file changed, 2 insertions(+)
3: create mode 100644 readme.txt
时光穿梭机
修改readme.txt
1: Git is a distributed version control system.
2: Git is free software.
运行git status命令看看结果:
1: $ git status
2: On branch master
3: Changes not staged for commit:
4: (use "git add <file>..." to update what will be committed)
5: (use "git checkout -- <file>..." to discard changes in working directory)
6:
7: modified: readme.txt
8:
9: no changes added to commit (use "git add" and/or "git commit -a")
git status命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,readme.txt被修改过了,但还没有准备提交的修改。
虽然Git告诉我们readme.txt被修改了,但如果能看看具体修改了什么内容,自然是很好的。比如你休假两周从国外回来,第一天上班时,已经记不清上次怎么修改的readme.txt,所以,需要用git diff这个命令看看:
1: $ git diff readme.txt
2: diff --git a/readme.txt b/readme.txt
3: index 46d49bf..9247db6 100644
4: --- a/readme.txt
5: +++ b/readme.txt
6: @@ -1,2 +1,2 @@
7: -Git is a version control system.
8: +Git is a distributed version control system.
9: Git is free software.
git diff顾名思义就是查看difference,显示的格式正是Unix通用的diff格式,可以从上面的命令输出看到,我们在第一行添加了一个distributed单词。
知道了对readme.txt作了什么修改后,再把它提交到仓库就放心多了
1: $ git commit -m "add distributed"
2: [master e475afc] add distributed
3: 1 file changed, 1 insertion(+), 1 deletion(-)
提交后,我们再用git status命令看看仓库的当前状态。
1: $ git status
2: On branch master
3: nothing to commit, working tree clean
Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working tree clean)的。
版本回退
现在,你已经学会了修改文件,然后把修改提交到Git版本库,现在,再练习一次,修改readme.txt文件如下:
1: Git is a distributed version control system.
2: Git is free software distributed under the GPL.
再提交。
现在,我们回顾一下readme.txt文件一共有几个版本被提交到Git仓库里了:
1: 版本1:wrote a readme file
2: Git is a version control system.
3: Git is free software.
4: 版本2:add distributed
5: Git is a distributed version control system.
6: Git is free software.
7: 版本3:append GPL
8: Git is a distributed version control system.
9: Git is free software distributed under the GPL.
在Git中,我们用git log命令查看:
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:
1: e0aec52e9f786f1d0710c91b19f01a68a6e54e51 (HEAD -> master) append GPL
2: 03acc08c20b060f58c826fc670515547933a4e59 add distributed
3: 7a7429309dfb15c891978d0d3e50385ae188623e wrote a readme file
Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。
每提交一个新版本,实际上Git就会把它们自动串成一条时间线
启动时光穿梭机,准备把readme.txt回退到上一个版本,也就是add distributed的那个版本,
1: $ git reset --hard 7a74
2: HEAD is now at 7a74293 wrote a readme file
查看txt内容
1: cat readme.txt
1: Git is a version control system.
2: Git is free software.
现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?
命令git reflog用来记录你的每一次命令:
1: e0aec52 (HEAD -> master) HEAD@{0}: reset: moving to e0ae
2: 7a74293 HEAD@{1}: reset: moving to 7a74
3: e0aec52 (HEAD -> master) HEAD@{2}: reset: moving to e0ae
4: e0aec52 (HEAD -> master) HEAD@{3}: commit: append GPL
5: 03acc08 HEAD@{4}: commit: add distributed
6: 7a74293 HEAD@{5}: commit (initial): wrote a readme file
append GPL的commit id是1094adb,现在,你又可以乘坐时光机回到未来了。
工作区和暂存区
工作区就是你在电脑里能看到的目录,比如我的learngit
文件夹就是一个工作区。
工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。
it的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add
把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master
分支,所以,现在,git commit
就是往master
分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
先对readme.txt
做个修改,比如加上一行内容:
1: Git is a distributed version control system.
2: Git is free software distributed under the GPL.
3: Git has a mutable index called stage.
然后,在工作区新增一个LICENSE
文本文件(内容随便写)。
先用git status
查看一下状态:
1: On branch master
2: Changes not staged for commit:
3: (use "git add <file>..." to update what will be committed)
4: (use "git checkout -- <file>..." to discard changes in working directory)
5:
6: modified: readme.txt
7:
8: Untracked files:
9: (use "git add <file>..." to include in what will be committed)
10:
11: license.txt
12:
13: no changes added to commit (use "git add" and/or "git commit -a")
14:
Git非常清楚地告诉我们,readme.txt
被修改了,而LICENSE
还从来没有被添加过,所以它的状态是Untracked
。
现在,使用两次命令git add
,把readme.txt
和LICENSE
都添加后,用git status
再查看一下:
1: On branch master
2: Changes to be committed:
3: (use "git reset HEAD <file>..." to unstage)
4:
5: new file: license.txt
6: modified: readme.txt
7:
现在,暂存区的状态就变成这样了:
所以,git add
命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit
就可以一次性把暂存区的所有修改提交到分支。
1: $ git commit -m "understand how stage works"
一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:
1: $ git status
2: On branch master
3: nothing to commit, working tree clean
注意:git diff 比较的是工作区文件与暂存区文件的区别(上次git add 的内容)
git diff --cached 比较的是暂存区的文件与仓库分支里(上次git commit 后的内容)的区别
管理修改
因为Git跟踪并管理的是修改,而非文件。
每次修改,如果不用git add
到暂存区,那就不会加入到commit
中。
用git diff HEAD -- readme.txt
命令可以查看工作区和版本库里面最新版本的区别。
撤销修改
git checkout -- file
可以丢弃工作区的修改:
命令git checkout -- readme.txt
意思就是,把readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
一种是
readme.txt
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;一种是
readme.txt
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。总之,就是让这个文件回到最近一次
git commit
或git add
时的状态。
用命令git reset HEAD <file>
可以把暂存区的修改撤销掉(unstage),重新放回工作区
git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD
时,表示最新的版本。
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- file
。场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令
git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
删除文件
般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm
命令删了:
1: $ rm test.txt
Git知道你删除了文件,因此,工作区和版本库就不一致了,git status
命令会立刻告诉你哪些文件被删除了:
现在你有两个选择,
一是确实要从版本库中删除该文件,那就用命令git rm
删掉,并且git commit
:
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
1: $ git checkout -- test.txt
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。