4.6 我的 Git 使用指南¶
一、Hello world¶
1.1 创建版本库¶
$ mkdir learngit
$ cd learngit
$ git init
1.2 添加提交¶
$ git add readme.txt
$ git commit -m "版本说明"
git add 的各种区别:
git add -A // 添加所有改动
git add * // 添加新建文件和修改,但是不包括删除
git add . // 添加新建文件和修改,但是不包括删除
git add -u // 添加修改和删除,但是不包括新建文件
在 commit 前撤销 add
git reset <file> // 撤销单个文件的add
git reset // 撤销所有文件的add
add/commit 前撤销对文件的修改
git checkout -- README.md // 如果你误删工作区实体文件,可以通过这个命令,将master最新版本还原到工作区
1.3 删除文件¶
$ rm readme.txt # 删除工作区的实体文件
$ git rm readme.txt # 删除工作区和暂存区文件,commit后版本库也将删除,如果不commit,版本库未删除,那么 git checkout -- readme.txt可以将版本库恢复到工作区。
1.4 远程仓库¶
origin 并不是指得是远程的仓库,而是指得是远程仓库在本地的一个指针。
为什么是这个名字呢?仅仅是因为 git 用它做为默认名被广泛使用,一个习惯而已,你也可以叫其他名字。
对一个在本地创建的仓库,如果添加远程仓库?
$ git remote add [shortname] [url]
# shortname是你命名的远程仓库名字,url格式如下:git@github.com:github_account/repository_name.git
#注意记得先在GitHub上先新建仓库,my_repository,不然后面 push 会出错
$ git remote add learn_git git@github.com:wongbingming/my_repository.git
推送/克隆
$ git push -u learn_git master #learn_git是之前命名的远程仓库名,master是你要推送到的远程仓库的分支名字
$ git push -u learn-git master:master
$ git clone [github url]
# 举例
$ git clone git@github.com:iswbm/test.git
更改远程仓库地址
$ git remote set-url origin git@<new_server>:you_repo.git
upstream 和 downstream
Git中的upstream和downstream的概念是相对的。
如果A库中的分支x被push到B库中的分支y,则y就是x的upstream,而x就是y的downstream。
1.5 GitHub合并至本地¶
$ git merge origin/master
1.6 创建SSHkeys¶
$ ssh-keygen -t rsa -C "youremail@example.com"
一路回车然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码
然后就会生成id_rsa和id_rsa.pub 两个文件
id_rsa是私钥,不能泄露
id_rsa.pub是公钥,可以放心告诉别人,而我们也只需要这个公钥,来连接我们GitHub。
建完成后,使用如下命令查找位置
$ find / -name id_rsa.pub
二、查看状态¶
2.1 文件状态¶
$ git status #如果修改了文件,状态会提示你有文件被修改(但不能告诉你哪里被修改),提示你要commit
$ cat readme.txt #查看实体文件的内容
$ git ls-files #查看哪些文件在版本控制下
查看当前目录下有哪些远程仓库
$ git remote # 远程仓库名字
$ git remote -v # verbose的缩写,显示详细信息,包括项目url
需要注意的是,当前Git Shell在不同目录下,git remote显示的远程仓库就不同
查看提交的历史
$ git log --pretty=oneline --abbrev-commit
查看不同的地方(修改)
$ git diff # 工作区(work dict)和暂存区(stage)的比较
$ git diff --cached # 是暂存区(stage)和分支(master)的比较
意思就是说,我们修改文件并保存实体文件,可以使用git diff查看不同之处,再确定是否add到暂存区
保存到暂存区后可以用git diff --cached查看stage暂存区和master分支的不同之处,决定是否commit
$ git diff HEAD -- readme.txt # 比较工作区和master最新版本readme.txt的不同
查看某个文件的变更记录
# 列出某个文件的变更记录,有 commitID
$ git log -- filename <filename>
# 查看具体变更了啥
$ git show <commitID>
# 若该次提交的文件很多,可以只查看指定文件
$ git show <commitID> <filename>
或者
# 相当于上面两个命令的合体
git log -p <filename>
2.2 Git日志¶
$ git log # 可以查看who在when修改了文件(会写出版本说明),但是这个看着眼花缭乱
$ git log --pretty=online # 这样,每行只显示一次修改,修改信息只有:commitid + 版本说明
$ git reflog # 显示所有修改的日志
$ git log --graph --all --decorate # 以可视化图的形式展示
2.3 查看修改¶
使用 diff 进行查看
查看两个 commit 之间的修改
$ git diff commit_id1 commit_id2
$ git diff commit_id^!
# 如果只想看改了哪些文件
$ git diff commit_id1 commit_id2 --stat
查看某个 commit 的改动
$ git show commit_id
$ git show --stat commit_id
查看两个分支之间的差异
# 查看两个分支有哪些文件发生改变了
git diff stable/2.2.9 stable/2.3.0 --stat
# 对比某一个文件在两个文件中的变化
git diff stable/2.2.9 stable/2.3.0 -- README.md
git diff stable/2.2.9:README.md stable/2.3.0:README.md
三、状态回滚¶
往下看之前,请先理解这三个Git区域: 工作区
-> 暂存区(stage)
->
版本库
3.1 撤消工作区修改¶
这里分为两种情况:
实体文件被修改,但还没add到暂存区
add到暂存区,但是实体文件又被修改
无论是哪种情况的撤消,本质都是将工作区的修改直接丢弃,并选择还原到该文件最近的一个状态。
对于第一种情况,离它最近的是版本库,所以撤消完后会还原到版本库的状态;
对于第二种情况,离它最近的是暂存区,所以撤消完后会还原到暂存区的状态。
那么如何撤消呢?
# 注意--之后有空格,最后加你要撤消的文件
$ git checkout -- readme.txt
3.3 撤消 commit¶
撤消 commit,并且撤消 add,不删除工作区修改
如下两条命令效果一样,因为 --mixed
是默认参数,它的意思是
不删除工作空间改动代码,撤销 commit,并且撤销git add . 操作。
其中 HEAD^
的意思是上一个版本,它等同于 HEAD~1
,如果你进行了 2
次 commit,想都撤回,可以使用 HEAD~2
。
$ git reset HEAD^
$ git reset --mixed HEAD^
只撤消 commit,不撤消 add,不删除工作区修改
$ git reset --soft HEAD^
撤消 commit,撤消 add,删除工作区修改
$ git reset --hard HEAD^
若只想修改commit message
执行如下命令,就会进入 vim 编辑器,对应修改即可
$ git commit --amend
3.4 回退到特定版本¶
上面都是介绍回退到上一版本,如果要回退到前几个版本,怎么整呢?
用 HEAD 指定是前几个版本
使用 git reset
,直接回退,不生成新的提交
# HEAD是当前版本
# HEAD^是上一个版本
# HEAD^^是上上个版本
# HEAD~100是前100个版本
# 回到上一个版本
$ git reset --hard HEAD^
# 若本地不小心修改或删除了很多文件,一个一个恢复太麻烦,可以这样,回到上一个版本
$ git reset --hard HEAD
使用 git revert
,间接回退,会生成新的提交
# 会生成一次新的提交,提交重新会有三次提交
$ git revert HEAD
# 相反使用 reset,直接将指针指向上一次提交之前,会有 0 次提交
$ git reset HEAD
使用 commit id 回退
如果有很多个版本,你也不想去数到底前几个版本,可以使用 commit id 精准回退,就像下面这样
$ git reset --hard 04c632e244
# hard后面这一串字符是commit id(版本号),只要前面几位就ok,但是如果我们关掉git,想恢复到之前的新版本,但是不知道id了,那就要用第三种方法了
那么问题就来了,如何获取这个 commit id呢?主要有如下两种方法
# 最前面那个即是 commit id,这个commit id 是短的
$ git reflog
$ git log --oneline
# 这里的 commit id 是长的
$ git log
$ git log --pretty=online
3.5 撤消你的撤消¶
当你对本地工作区的修改已经add并commit后,你发现你想撤消你的这些commit,但是你一不小心执行了
$ git reset --hard HEAD^
这条命令会将你的本地工作区的修改也还原到上一次commit。相当于你之前做的所有修改全部都丢失了。
而我们原本只是想撤消 commit 和 add,而不想连本地的修改也丢弃。
这时候如何补救呢?
很简单,先使用 git reflog
找到你的 reset 的 commit id
然后再次使用 git reset
指定 commit id 回到一次修改add前的状态
3.6 回退远程提交¶
# 可能需要先回退本地,再执行第二条命令,有可能不用,需要再试
$ git reset --hard commit_id
# 回退一个版本
$ git push origin HEAD --force
3.7 删除版本库里的文件¶
# 加了 --cached 就不会删除工作区的文件
$ git rm --cached file1.txt
$ git commit -m "remove file1.txt"
$ git push origin branch_name
四、分支管理¶
4.1 新建-切换-删除分支¶
$ git checkout -b dev # 创建dev分支,把HEAD指针切换到dev
# 相当于下面两条命令
------------------------
$ git branch dev # 新建
$ git checkout dev # 切换指针
------------------------
$ git branch # 查看所有分支,*表示当前分支
# 合并分支:把dev合并到当前master分支(已经切换到master分支的状态下)
$ git merge dev
# 删除dev分支:dev不能是当前分支
# 如果dev之前和远程仓库同步过,这次要删除前如果有修改需要先同步才能修改,不然需要用-D
$ git branch -d dev
# 删除本地的远程分支
git branch --delete --remotes <remote>/<branch>
git branch --delete --remotes origin/stable/2.2.5
git branch -dr origin/stable/2.2.5
# 直接删除远程分支
git push origin --delete stable/2.2.5
4.2 分支冲突¶
两个分支都修改了合并冲突问题
请查阅:廖雪峰:解决合并冲突问题
【合并分支的见解】
1. master分支:只有a.txt,但在分支dev提交了b.txt,b.txt在master分支是没有的。这种合并是不会有问题的,合并后,master,将增加b.txt
2. 在分支dev修改了内容,切换到master,对同一文件修改同一处地方的不同内容。这时候合并,就会出现冲突,我们需要手动修改文件为我们需要的内容,然后最后提交。
4.3 合并分支¶
请参阅:廖雪峰:分支管理策略
$ git merge # 默认使用Fast Forward快速合并,这种不会留下合并信息
$ git merge --no-ff -m "sometext" # 由于不采用快速合并,会生成一次commit,所以需要-m 说明,这个好处可以查到合并信息
# 多个分支,暂存区是公用的。
4.4 本地分支与远程分支¶
1. 本地分支如果和远程分支同名,push时只要写一个分支名即可
2. 如果不同名,可以使用"git push -u origin local_branch_name:remote_branch_name"
五、保存现场stash¶
假如我们当前正在dev分支工作,但是master主分支有bug需要紧急修复,但是dev的工作才进行到一半,完成还需要一天,我们想在不提交的情况下,把bug修复好,改怎么做?
# 这时候就可以用git stash,保存
# 然后切换到master修复bug,修复完成后再切换到dev
$ git stash list # 查看保存的list
stash@{0}: WIP on dev: 6224937 add merge
$ git stash apply # 恢复但不删除stash
$ git stash drop # 删除
# 如果list中有多个stash,可以选择
$ git stash apply stash@{1}
#"git stash pop"(在恢复的时候,同时把stash内容也删了)==""(恢复)+""(删除stash内容)
六、标签管理¶
标签的意义
标签的作用相当于commit ID
区别在于commit ID是机器生成的,不便于记忆和可读性,tag是人为设定的,有特殊意义,有很强的可读性
如何打标签
首先切换到你要打标签的分支上,通常是master
$ git tag v1.0 #给当前分支打上v1.0的标签
$ git tag v1.0 6a5819e #如应该在之前版本打的标签没打,可以这样补打
-------------------------------------------------------------------------------
$ git tag #显示当前分支的所有标签
$ git show v1.0 #查看v1.0的信息:commit ID,Author,Date
--------------------------------------------------------------------------------
$ git tag -a v1.1 -m "version 1.1 released" 3628164
# -m 添加说明文字,-a v0.1:使用git show v1.1,有tag的信息
标签不自动push到远程,若要push,可以使用命令
$ git push origin v1.0 #推送单个tag
$ git push origin --tags #一次性推送所有tag
删除标签
1. 本地删除
$ git tag -d v1.0 #删除标签v1.0
2. 远程删除(如果已经推送到远程,要先本地删除,再远程删除两个步骤)
$ git push origin :refs/tags/v1.0
# 要查看是否远程删除了,可以上GitHub上看
七、Github 使用¶
7.1 认证授权¶
当我们刚开始使用Github的时候,如果要将仓库里的代码clone到本地,需要对这台HOST进行授权。
本地创建 SSH Keys
ssh-keygen -t rsa -C "wongbingming@163.com"
生成的私钥
/c/Users/wangbm/.ssh/id_rsa
,由本机电脑保存。
生成的仅钥 /c/Users/wangbm/.ssh/id_rsa.pub
,需要在Github上添加。
在github上添加ssh keys方法如下:
添加完后,可以使用这个命令测试一下。
ssh -T git@github.com
Hi BingmingWong! You've successfully authenticated, but GitHub does not provide shell access.
至此,我们的PC已经认证通过。
7.2 添加用户¶
虽然我们已经认证通过,但是如果要对线上的仓库进行操作,我们肯定还需要进行登陆操作。
参过执行如下两个配置用户信息的命令
git config --global user.name 'BingmingWong'
git config --global user.email wongbingming@163.com
配置完后我们就可以进行clone线上代码了。
7.3 使用 SourceTree¶
Git 的使用全都是命令行的,由于没有那么直观,所以很容易就会误操作。
在这里,我推荐使用 SourceTree 这个Git可视化管理工具(Github出品的Github Desktop真心觉得不好用)。
可以点击这里下载:https://cn.atlassian.com/software/sourcetree
在Mac 上安装很方便,在 Windows 上可能会需要你安装 .net Framwork 4.7.2 。
下载安装完后,进入初始界面,需要登陆一下https://bitbucket.org/(没有的话就注册一下 )。
然后你可以将你的本地仓库直接拖进来管理,也可以直接连接github。
需要注意的是,使用它需要你进行一步操作。在 7.2 章节,我在机器上生成了一对私钥和公钥,在这里需要配置一下才能正常访问和提交我们的Github仓库。
如果想要用户名和密码登陆,可以将上面的 OpenSSH 改成 PuTTY/Plink就行了。