// 将所有以 Hello 开头的文件的修改添加到暂存区 例
// 将 commit 信息简化成一行显示
// 将以 Controller 结尾的文件的所有修改添加到暂存区
$ git init // 初始化一个 Git 仓库
// 查看仓库的状态
$ git status
$ git add .
// 将所有修改添加到暂存区
$ git add * // Ant 风格添加修改
$ git add *Controller
$ git add Hello*
如:HelloWorld.txt,Hello.java,HelloGit.txt ...
$ git add Hello?
// 将以 Hello 开头后面只有一位的文件的修改提交到暂存区 例
如:Hello1.txt,HelloA.java 如果是 HelloGit.txt 或者 Hello.java 是不会被添加的
可以多次添加然后在提交
$ git commit -m "comment" // 将暂存区的修改提交到仓库 后面添加上有意义的注视信息
$ git diff file // 在 file 被修改了还未提交的时候查看修改的部分(和版本库中最新版本的不同
diff == difference 不同)
$ git log // 查看 git 的 commit 信息,每次提交的信息包括注视在内,从最新提交到最久提交
$ git log --pretty=oneline
注意 Git 的版本号(commit id)是 SHA1 值 ea34578d5496d7dd233c827ed32a8cd576c5ee85
$ git reset --hard HEAD^
// 退回到相对于当前版本的上一个版本 HEAD 表示当前版本
$ git reset --hard HEAD^^ // 退回到相对于当前版本的上上一个版本 HEAD 代表当前版本
$ git reset --hard HEAD~100 //退回到相对于当前版本的上 100 个版本去 HEAD 表示当前版本
$ git reset --hard 3628164 // 退回到指定的版本 这里不需要全部写 commit id Git 回去自
动适配
Git 的版本回退速度非常快,因为 Git 在内部有个指向当前版本的 HEAD 指针,当你回退版本的时候,Git
仅仅是把 HEAD 从指向 append GPL
$ git reflog
当我们想从一个旧版本退回到新版本但是我们关闭了 shell 窗口,不能查看之前的 commit id 了,就可以
通过
$ git reflog 查看到之前的版本的 commit id
$ git reset --hard 3628164
// 在退回到旧版本之后可以查看旧版本之前的提交日志
工作区和暂存区
工作区: 就是我们通$ git init 创建的代码库的所有文件但是不包括 .git 文件(版本库)
暂存区: 我们通过$ git add ./*/*Xxx/Xxxx* 添加的修改,都是进入到暂存区了,肉眼不可见 通过
$ git status 可以看到修改的状态
什么是修改?
比如你新增了一行,这就是一个修改,
删除了一行,也是一个修改,
更改了某些字符,也是一个修改,
删了一些又加了一些,也是一个修改,
甚至创建一个新文件,也算一个修改。
修改只能在被 add 到暂存区以后才能被提交
在 file 已经修改还未 add 的时候
$ git checkout --file // 表示丢弃工作区的修改退回原始状态(不包括以及添加到暂存区的修改)
file 已经修改和添加到了暂存区,还未 commit
$ git reset HEAD file
// 丢弃 file 已经添加到暂存区的修改 HEAD 表示最新版本
如果 file 修改已经提交到本地仓库
$ git reset --hard HEAD^
//退回到上一个版本
$ rm file // 从文件系统中删除文件(Git 中还是有记录),$ git status 的时候 Git 会告诉你有一
个 file 被删除了
$ git rm file // 从 Git 版本库中删除文件(同时从文件系统中删除文件) $ git status 正常
$ git rm file // 从 git 版本库中删除文件
$ git commit -m "delete file" // 提交删除
$ git checkout file // 想要从 git 恢复 会出现:error: pathspec 'README.txt' did not match
any file(s) known to git.
$ git reset --hard HEAD^ // 恢复到上一个版本 可以恢复文件
$ rm file
$ git checkout file // 由于是通过文件系统删除的所以可以通过 checkout 恢复
//在文件系统中删除文件
$ ssh-keygen -t rsa -C "youremail@example.com" // 创建 SSH Key
由于这个 Key 也不是用于军事目的,所以也无需设置密码,所以一路回车就好,
如果顺利会在 user 下 UserName 目录中生成一个.ssh 目录里面有 id_rsa 和 id_rsa.pub 两个文件
id_rsa 是私钥,不能泄露出去,id_rsa.pub 是公钥,可以告诉他人还有在 github 上添加的也是这个公钥
登陆 GitHub,打开“Account settings”,“SSH Keys”页面,点“Add SSH Key”,填上任意 Title,在
Key 文本框里粘贴 id_rsa.pub 文件的内容
GitHub 允许你添加多个 Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台
电脑的 Key 都添加到 GitHub,就可以在每台电脑上往 GitHub 推送了
添加远程库
做全局的配置
$ git config --global user.name "zhangsan"
$ git config --global user.email "zhangsan@139.com"
$ git remote add origin git@github.com:zhangsan/ylez.git // 添加一个远程仓库
// add origin 就是添加一个远程仓库
// git@github.com:zhangsan/ylez.git 是远程仓库的地址
// git@github.com 主机的地址 我们可以通过 GitLab 大家自己的 git 服务器
// zhangsan 是你的用户名
// /ylez.git 是你的仓库名
$ git push -u origin master // 将本地的 master 分支推送到远程的 master 分支中
$ git push -u origin dev
// 本地切换到 dev 分支然后将本地的 dev 分支推送到远程
克隆远程仓库到本地
Git 支持多种协议,包括 https,但通过 ssh 支持的原生 git 协议速度最快。
$ git clone git@192.168.0.8:zhangsan/test.git // 讲一个远程的仓库克隆到本地
每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支
在 Git 里,默认有一个主分支,即 master 分支
HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前
分支
master 分支是一条线,Git 用 master 指向最新的提交,再用 HEAD 指向 master
每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长
Git 新建了一个指针叫 dev,指向 master 相同的提交,再把 HEAD 指向 dev,就表示当前分支在 dev 上
// 查看 git 的所有分支
$ git branch
$ git branch dev // 创建 dev 分支
$ git checkout dev // 切换到一个已经存在的分支
$ git checkout -b dev // 创建 dev 分支,并切换到 dev 分支
$ git branch -d dev // 删除 dev 分支
// 将 dev 分支合并到 master 分支
$ git checkout master // 切换到主分支
$ git merge dev
Updating d17efd8..fec145a
Fast-forward
readme.txt |
1 file changed, 1 insertion(+)
Fast-forward 信息,Git 告诉我们,这次合并是“快进模式”,就是直接把 master 指向 dev 的当前提交,
所以合并速度非常快
$ git branch -d dev // 删除 dev 分支
1 +
现在只是剩下 master 分支,感觉什么事情都没又发生一样
处理冲突
$ git checkout -b feature1
Switched to a new branch 'feature1'
修改 readme.txt 最后一行,改为:
Creating a new branch is quick AND simple.
$ git add readme.txt
$ git commit -m "AND simple"
[feature1 75a857c] AND simple
1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
Git 还会自动提示我们当前 master 分支比远程的 master 分支要超前 1 个提交。
在 master 分支上把 readme.txt 文件的最后一行改为:
Creating a new branch is quick & simple.
$ git add readme.txt
$ git commit -m "& simple"
[master 400b400] & simple
1 file changed, 1 insertion(+), 1 deletion(-)
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
#
#
#
#
readme.txt // 冲突了
(use "git add/rm ..." as appropriate to mark resolution)
both modified:
no changes added to commit (use "git add" and/or "git commit -a")
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.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
Git 用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
Creating a new branch is quick and simple.
再提交:
$ git add readme.txt
$ git commit -m "conflict fixed"
[master 59bc1cb] conflict fixed
59bc1cb conflict fixed
用带参数的 git log 也可以看到分支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
$ git log --graph --pretty=oneline --abbrev-commit
*
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
删除 feature1 分支:
$ git branch -d feature1
Deleted branch feature1 (was 75a857c).
通常,合并分支时,如果可能,Git 会用 Fast forward 模式,但这种模式下,删除分支后,会丢掉分支
信息。
如果要强制禁用 Fast forward 模式,Git 就会在 merge 时生成一个新的 commit,这样,从分支历史上
就可以看出分支信息
$ git merge --no-ff -m "comment" dev // 准备合并 dev 分支,请注意--no-ff 参数,表示禁用
Fast forward
7825a50 merge with no-ff
$ git log --graph --pretty=oneline --abbrev-commit //图形化展示分支情况
*
|\
| * 6224937 add merge
|/
*
...
59bc1cb conflict fixed
修复一个代号 101 的 bug 的任务时,很自然地,你想创建一个分支 issue-101 来修复它
在修复 bug 时候,手里还有工作没有完成但是又不能提交可以将进度冻结
在你当前的工作区(分支)
$ git stash // 冻结当前的分支修改
查看所有的 stash
$ git stash list // 列出所有的工作现场存储
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
$ git stash apply (stash@{n}) // 恢复工作现场(只有一个的时候可以省略后面的,如果有多个可以
恢复指定的某一个 stash)但是不删除存储中的 stash
$ git stash drop (stash@{n}) // 删除存储的工作现场(只有一个的时候可以省略后面的,如果又多
个就指定删除某一个)
$ git stash pop (stash@{n}) // 恢复的同时把 stash 内容也删了(只有一个的时候可以省略后面的,
如果又多个就指定删除某一个)
$ git branch -d branchName // 删除某一个分支,前提是在该分支和产生该分支的主分支已经合并了
(merge)
$ git branch -D branchName // 删除某一个分支,无论是否合并都强制删除
当你从远程仓库克隆时,实际上 Git 自动把本地的 master 分支和远程的 master 分支对应起来了,并且,
远程仓库的默认名称是 origin。
要查看远程库的信息,用 git remote:
$ git remote
origin
或者,用 git remote -v 显示更详细的信息:
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master 分支是主分支,因此要时刻与远程同步;
dev 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug 分支只用于在本地修复 bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个 bug;
feature 分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
推送的时候如果有人在你之前已经推送了,推送失败
$ git push origin dev
dev -> dev (non-fast-forward)
To git@github.com:michaelliao/learngit.git
! [rejected]
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,
Git 已经提示我们,先用 git pull 把最新的提交从 origin/dev 抓下来,然后,在本地合并,解决冲突,
再推送
$ git pull //抓去远程的分支的提交到本地
没有指定本地 dev 分支与远程 origin/dev 分支的链接,推送也会失败,所以首先我们需要建立本地分支和
远程分支的联系
$ git branch --set-upstream dev origin/dev // 建立本地 dev 分支和远程 dev 分支的联系
Branch dev set up to track remote branch dev from origin.
总结:
查看远程库信息,使用 git remote -v;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用 git push origin branch-name,如果推送失败,先用 git pull 抓取远程的新
提交;
在本地创建和远程分支对应的分支,使用 git checkout -b branch-name origin/branch-name,本地
和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用 git branch --set-upstream branch-name
origin/branch-name;
从远程抓取分支,使用 git pull,如果有冲突,要先处理冲突。
发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。
将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版
本库的一个快照。
Git 的标签虽然是版本库的快照,但其实它就是指向某个 commit 的指针(跟分支很像对不对?但是分支
可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
标签一般打在 master 分支上
$ git tag v1.0 // 在当前版本 HEAD 上打一个名称为 v1.0 的标签
$ git tag
// 查看所有标签,会列表出所有的标签名
为历史 commit 打 tag(有时候忘记打标签了本来该星期一打结果星期五才想起来)
$ git log --pretty=oneline --abbrev-commit
6a5819e merged bug fix 101
cc17032 fix bug 101
7825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
$ git tag v0.8 59bc1cb // 为 commit id 为 59bc1cb...的 commit 打上 v0.8 标签
标签不是按时间顺序列出,而是按字母排序的。可以用 git show 查看标签信息
还可以创建带有说明的标签,用-a 指定标签名,-m 指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164 // 为 commit id 为 3628164...的 commit
打上 v0.1 的标签注视内容是 version 0.1 released
$ git tag v0.1 //可以查看标签的信息包括文字说明
还可以通过-s 用私钥签名一个标签: