注:本文是通过廖雪峰官网的git学习教程整理出来的个人笔记
git的使用
git的安装
sudo apt-get install git
- 安装homebrew,然后通过homebrew安装Git
- 直接从AppStore安装Xcode,Xcode集成了Git,不过默认没有安装,需要运行Xcode,选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了。
- window上安装
- 安装msysgit
- 安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功
初始化
- 因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
git初始化
$ mkdir gitDir
$ cd gitDir
$ pwd
/Users/michael/gitDir
$ git init
Initialized empty Git repository in /Users/michael/gitDir/.git/
- 所有的版本控制系统,其实只能跟踪纯文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。
- 版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。
- 而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
- word不是纯文本文件,不能跟踪具体修改了什么内容,只能跟踪修改的大小和时间
使用Windows要特别注意:
- 千万不要使用Windows自带的记事本编辑任何文本文件。
- 原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题
- 比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等
- 建议你下载Notepad++代替记事本,不但功能强大,而且免费!记得把Notepad++的默认编码设置为UTF-8 without BOM即可
添加版本控制
$ git add readme.txt
$ git commit -m "wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt
# -m 后面输入的是本次提交的说明
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
- Git is a version control system.
+ Git is a distributed version control system.
Git is free software.
$ git add readme.txt
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: readme.txt
#
git commit -m "add distributed"
[master ea34578] add distributed
1 file changed, 1 insertion(+), 1 deletion(-)
- 查看历史记录
- --pretty=oneline加上这个选项可以美化输出效果
$ git log
commit 3628164fb26d48395383f8f31179f24e0882e1e0
Author: Michael Liao <askxuefeng@gmail.com>
Date: Tue Aug 20 15:11:49 2013 +0800
append GPL
commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao <askxuefeng@gmail.com>
Date: Tue Aug 20 14:53:12 2013 +0800
add distributed
commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao <askxuefeng@gmail.com>
Date: Mon Aug 19 17:51:55 2013 +0800
wrote a readme file
$ git log --pretty=oneline
3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file
版本回退
- 首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD,上上一个版本就是HEAD,当然往上100个版本写100个比较容易数不过来,所以写成HEAD~100。
$ git reset --hard HEAD^
HEAD is now at ea34578 add distributed
- 如果后悔了,想回到最新的版本
- 只要上面的命令行窗口还没有被关掉,你就可以顺着往上找之前打印的log记录,找到那个append GPL的commit id是3628164...,于是就可以指定回到未来的某个版本:
- 版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。
$ git reset --hard 3628164
HEAD is now at 3628164 append GPL
- 如果我想回退到最新版本,又重启了电脑
- 在Git中,总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到add distributed版本时,再想恢复到append GPL,就必须找到append GPL的commit id。Git提供了一个命令git reflog用来记录你的每一次命令:
- 终于舒了口气,第二行显示append GPL的commit id是3628164,现在,你又可以乘坐时光机回到未来了。
$ git reflog
ea34578 HEAD@{0}: reset: moving to HEAD^
3628164 HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file
- ++HEAD指向的版本就是当前版本因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。++
- ++穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。++
- ++要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。++
工作区和暂存区
- 工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库
- Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD
- 前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
- 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
- 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
- 因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
- 你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
管理修改
- Git比其他版本控制系统设计得优秀,是因为Git跟踪并管理的是修改,而非文件。
- 第一次修改 -> git add -> 第二次修改 -> git commit
- Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区
- 准备提交,但是,在工作区的第二次修改并没有放入暂存区
- 所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
撤销修改
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
- git checkout -- file可以丢弃工作区的修改
$ git checkout -- readme.txt
- 命令git checkout --readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销
- 这里有两种情况:
- 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
- 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
- 总之,就是让这个文件回到最近一次git commit或git add时的状态。
- git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
My stupid boss still prefers SVN.
$ git add readme.txt
- commit之前,你发现了这个问题。用git status查看一下,修改只是添加到了暂存区,还没有提交:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: readme.txt
- Git同样告诉我们,用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
- 场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
- 场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
- 场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
删除文件
$ git add test.txt
$ git commit -m "add test.txt"
[master 94cdc44] add test.txt
1 file changed, 1 insertion(+)
create mode 100644 test.txt
$ rm test.txt
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
- 现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit:
$ git rm test.txt
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d17efd8] remove test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt