Git管理的是修改,而不是文件
- 第一次修改 ->
git add
-> 第二次修改 ->git commit
用
git add
命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit
只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
- 第一次修改 ->
git add
-> 第二次修改 ->git add
->git commit
那怎么提交第二次修改呢?你可以继续
git add
再git commit
,也可以别着急提交第一次修改,先git add
第二次修改,再git commit
,就相当于把两次修改合并后一块提交了。
- git init 初始化一个仓库
例:
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
- git add <file> 把文件添加到仓库
例:
$ git add file1.txt
$ git add file2.txt file3.txt
- git commit -m <message> 把文件提交到仓库,-m后面是本次提交说明
例:
$ git commit -m "wrote a readme file"
- git status 查看仓库当前状态
例:
$ git status
On branch master
nothing to commit, working tree clean
- git diff <file> 查看文件修改内容
例:
$ 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 diff HEAD -- <file> 工作区和版本库里面最新版本的区别
例:
$ git diff HEAD -- readme.txt
diff --git a/readme.txt b/readme.txt
index 76d770f..a9c5755 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,4 +1,4 @@
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.
+Git tracks changes of files.
- git log 查看最近到最远的提交日志
例:
$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: Michael Jake<JakeRame@gmail.com>
Date: Fri May 18 21:06:15 2018 +0800
append GPL
commit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Jake<JakeRame@gmail.com>
Date: Fri May 18 21:03:36 2018 +0800
add distributed
commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Jake<JakeRame@gmail.com>
Date: Fri May 18 20:59:18 2018 +0800
wrote a readme file
- git log --graph 命令可以看到分支合并图
例:
$ git log --graph --pretty=oneline --abbrev-commit
* cf810e4 (HEAD -> master) conflict fixed
|\
| * 14096d0 (feature1) AND simple
* | 5dc6824 & simple
|/
* b17d20e branch test
* d46f35e (origin/master) remove test.txt
* b84166e add test.txt
* 519219b git tracks changes
* e43a48b understand how stage works
* 1094adb append GPL
* e475afc add distributed
* eaadf4e wrote a readme file
- git log --pretty=oneline 简短输出提交日志
例:
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file
1094adb....是commit id(版本号)
在GIT中用HEAD表示当前版本也就是最新提交的1094adb....,上一个版本为HEAD^,上上个版本就是HEAD^^,再往上100个版本写100个^太复杂了,所以写成HEAD~100。
- git reset --hard commit_id 版本切换
例:
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD
指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL
:
┌────┐
│HEAD│
└────┘
│
└──> ○ append GPL
│
○ add distributed
│
○ wrote a readme file
改为指向add distributed
:
┌────┐
│HEAD│
└────┘
│
│ ○ append GPL
│ │
└──> ○ add distributed
│
○ wrote a readme file
然后顺便把工作区的文件更新了。所以你让HEAD
指向哪个版本号,你就把当前版本定位在哪。
- git reset HEAD <file> 把暂存区的修改撤销掉,重新放回工作区
例:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
注:
git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD
时,表示最新的版本。
- git reflog 查看所有提交记录
例:
$ git reflog
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file
注:
-
穿梭前,用
git log
可以查看提交历史,以便确定要回退到哪个版本。 -
要重返未来,用
git reflog
查看命令历史,以便确定要回到未来的哪个版本。
- git checkout --<file> 丢弃工作区的修改(用版本库里的版本替换工作区的版本)
例:
$ git checkout -- readme.txt
注:
命令git checkout -- readme.txt
意思就是,把readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
- 一种是
readme.txt
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态; - 一种是
readme.txt
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
- git rm <file> ,git commit(从版本库中删除该文件)
例:
$ git rm test.txt
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt
Git分支管理
- Git每次提交都会产生一个节点,Git把它串成一条时间线,这条时间线就是一条分支,开始创建开始,只有一条时间线,在Git里,这个分支叫主分支,即master分支,HEAD严格来说不是指向提交,而是指向master,master指向提交,即HEAD指向的是当前分支。
- 我们创建新的分支dev,Git新建一个指针dev,指向master相同的提交,再把HEAD指向dev,表示当前分支在dev上。
- 现在工作区的修改和提交就是针对
dev
分支了,比如新提交一次后,dev
指针往前移动一步,而master
指针不变。
- 现在dev上的工作已经完成,需要把dev合并到master上,方法:直接把master指向dev的当前提交,即完成合并。
- 合并完分支后,甚至可以删除dev分支,方法:只需要把dev指针删掉,就只剩下一条master分支 。
- git branch 查看分支
例:
$ git branch
* dev
master
注:
git branch会列出所有分支,当前分支前面会标记*号。
- git branch <name> 创建分支
例:
$ git branch dev
- git checkout <name> 或者 git switch <name> 切换分支
例:
$ git checkout master
Switched to branch 'master'
$ git switch master
Switched to branch 'master'
- git checkout -b <name> 或者 git switch -c <name> 创建+切换分支
例:,
$ git checkout -b dev
Switched to a new branch 'dev'
$ git switch -c dev
Switched to a new branch 'dev'
- git merge <name> 合并name分支到当前分支(Git会启用Fast forward)模式
例:
$ git merge dev
Updating d46f35e..b17d20e
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
- git branch -d <name> 删除分支
例:
$ git branch -d dev
Deleted branch dev (was b17d20e).
- --no-ff 方式的git merge(禁用
Fast forward
模式,Git就会在merge时生成一个新的commit)
例:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
注:
因为本次合并要创建一个新的commit,所以加上-m
参数,把commit描述写进去。
- git stash 把当前工作现场“储藏”起来,等以后恢复现场后继续工作
例:
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge
- git stash list 查看工作现场
例:
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
- git stash apply 恢复工作现场,stash 内容不删除
- git stash drop 删除stash内容
- git stash pop,恢复的同时把stash内容也删掉
例:
$ git stash pop
On branch dev
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: hello.py
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
Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)
- git stash apply stash@{0} 恢复指定的stash
例:
$ git stash apply stash@{0}
- git cherry-pick <commit> 复制一个特定的提交到当前分支
例:
$ git branch
* dev
master
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 101
1 file changed, 1 insertion(+), 1 deletion(-)
- git branch -D <name> 强行删除一个没有被合并过的分支
例:
$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e)
Git标签管理
- 创建标签
- 首先,切换到需要打标签的分支上
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
- 再git tag <name> 打一个新标签
$ git tag v1.0
- git tag -a <name> -m "说明文字" <commit_id> 创建带有说明的标签
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
注:
用-a
指定标签名,-m
指定说明文字
- git tag 查看所有标签
$ git tag
v1.0
- 如果忘记打标签,可以用git log找到历史提交的commit id,然后用命令git tag <name> <commit_id>打上标签
$ git log --pretty=oneline --abbrev-commit
12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
5dc6824 & simple
14096d0 AND simple
$ git tag v0.9 f52c633
- git show <tagname> 查看标签信息
$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Jake <JakeRame@gmail.com>
Date: Fri May 18 21:56:54 2018 +0800
add merge
diff --git a/readme.txt b/readme.txt
...
- git tag -d <tagname> 删除指定标签
$ git tag -d v0.1
Deleted tag 'v0.1' (was f15b0dd)
- git push origin <tagname> 推送某个标签到远程
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v1.0 -> v1.0
- git push origin --tags 一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v0.9 -> v0.9
- git push origin :refs/tags/<tagname> 删除一个远程标签
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git
- [deleted] v0.9
- 如果标签已经推送到远程,要删除远程标签就分两步:
- 先用命令 git tag -d <tagname> 删除本地标签
- 再用命令 git push origin :refs/tags/<tagname> 删除远程标签
$ git tag -d v0.9
Deleted tag 'v0.9' (was f52c633)
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git
- [deleted] v0.9
注:
可以登陆GitHub查看是否真正的从远程库中删除了标签