Git 详细使用指南
一、Git 入门操作
1.1 创建版本库
$ mkdir learngit
$ cd learngit
$ git init
1.2 添加文件
$ git add readme.txt
git add 的各种区别:
git add -A // 添加所有改动
git add * // 添加新建文件和修改,但是不包括删除
git add . // 添加新建文件和修改,但是不包括删除
git add -u // 添加修改和删除,但是不包括新建文件
1.3 提交修改
$ git commit -m "新增文件"
1.4 远程仓库
$ git remote add [shortname] [url]
# 举例
$ git remote add origin git@github.com:iswbm/magic-python.git
1.5 推送提交
# origin 是之前为远程仓库设置的别名,master是你要推送到的远程仓库的分支名字
git push -u origin master
# 它等价于 git push -u origin master:master
1.6 克隆项目
$ git clone git@github.com:iswbm/magic-python.git
1.7 拉取提交
$ git pull
$ git pull origin
有些可视化软件上的按键对应的是 git fetch
二、其他操作
2.1 删除文件
# 删除工作区的实体文件
$ git rm readme.txt
2.2 查看远程
$ git remote
origin
再加 -v
就可以 看到远程仓库的地址,v 是 verbose的缩写,显示详细信息
$ git remote -v
origingit@github.com:iswbm/magic-python.git (fetch)
origingit@github.com:iswbm/magic-python.git (push)
2.3 更改远程
$ git remote set-url origin git@gitee.com:iswbm/magic-python.git
三、状态回滚
**往下看之前,请先理解这三个Git区域: ** -> ->
3.1 撤消工作区修改
这里分为两种情况:
- 实体文件被修改,但还没add到暂存区
- add到暂存区,但是实体文件又被修改
无论是哪种情况的撤消,本质都是将工作区的修改直接丢弃,并选择还原到该文件最近的一个状态。
对于第一种情况,离它最近的是版本库,所以撤消完后会还原到版本库的状态;
对于第二种情况,离它最近的是暂存区,所以撤消完后会还原到暂存区的状态。
那么如何撤消呢?
可以用直接删除的方式
git restore <file>
也可以用回退到版本库中版本的方式来
# 注意--之后有空格,最后加你要撤消的文件u
$ git checkout -- readme.txt
3.2 撤消你的 add
可以用删除 add 的方式
# 也可以用 restore,只要加上 --staged
git restore --staged <file>
也可以用回退到版本库中版本的方式来
# 回退到版本库中的版本
git reset HEAD readme.txt
# 由于 HEAD 是默认的选项,因此下面两条命令都是将文件回退到版本库中的版本 git reset <file> // 撤销单个文件的add
$ git reset // 撤销所有文件的add
3.3 撤消 commit
撤消 commit,并且撤消 add,不删除工作区修改
如下两条命令效果一样,因为 --mixed
是默认参数,它的意思是 不删除工作空间改动代码,撤销 commit,并且撤销git add . 操作。
其中 的意思是上一个版本,它等同于 ,如果你进行了 2 次 commit,想都撤回,可以使用 。
$ git reset HEAD^
$ git reset --mixed HEAD^
**只撤消 commit 到暂存区:soft 模式 **
不管暂存区(不管工作区)现在是啥,都删除掉,并回退到上一次 commit 的状态
$ git reset --soft HEAD^
**撤消 commit 到工作区:hard 模式 **
不管暂存区和工作区现在是啥,都删除掉,并回退到上上一次 commit 的状态
$ git reset --hard HEAD^
若只想修改commit message
$ 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 撤消已经Push到远程的提交
有时,在git push之后,才发现还有一些代码需要进行很小的改动,这些改动在原则上不应该作为一次新的提交。
这时,我们需要撤销这次推送(git push)与提交(git commit),然后进行代码修改,再重新进行提交和推送。
分为两步:
- 本地先回退到上一个版本:
git reset --soft HEAD^
(使用 hard 会删除本地修改) - 将本地的这次回退推送到远程:
git push origin stable/2.3.9 --force
(不加–force是推送不了的,stable/2.3.9 是分支名,请对应更改)
如果你不仅是撤消一个提交,而是要回退到多个提交之前,就要找出你要回退到的那个 commit 的 id
- 使用
git log --oneline
找出 commit id - 回退到该 commit id 的版本:
git reset --soft commit_id
- 将本地的这次回退推送到远程:
git push origin stable/2.3.9 --force
3.7 回退到远程均分支的版本
$ git reset --hard origin/master
3.7 删除版本库里的文件
# 加了 --cached 就不会删除工作区的文件
git rm --cached file1.txt git commit -m "remove file1.txt"
$ git push origin branch_name
四、分支管理
4.1 新建分支
新建分支
$ git branch -f dev # 新建, -f 是强制的意思,视情况加不加
但一般情况下,我们希望创建完成后,能立马切换过去,那可以使用下面这条命令
# 创建dev分支,把HEAD指针切换到dev
$ git checkout -b dev
上面这条命令相当于下面两条命令
$ git branch -f dev # 新建, -f 是强制的意思,视情况加不加
$ git checkout dev # 切换指针
4.2 查看分支
查看分支
# 查看所有本地分支,*表示当前分支
git branch
# 查看所有远程分支 git branch -r
# 查看所有分支
$ git branch -a
4.3 切换分支
# 切换到 dev
git checkout dev
# 切换到 master git checkout master
4.4 合并分支
请参阅:廖雪峰:分支管理策略
合并分支可以一个一个合并,也可以将多个分支一起合并
# 将dev合并到当前分支
git merge dev
# 静默合并,不会输出任何信息 git merge –quiet dev
# 将 dev1 和 dev2 合并到当前分支的顶部
$ git merge dev1 dev2
第一种情况
默认情况下,使用 merge 合并分支,git 会先优先使用 Fast Forward 快速合并,这种模式不会产生新的 commit,如果 master 分支在创建 dev 分支后有内容更新,那么就会产生一个新的 commit
$ git merge dev
# 等价于
$ git merge --ff dev
具体什么情况下使用快速合并,什么情况下不使用 快速合并,可前往 分支的合并 ,里面有图解,可以帮助你理解。
你可能发现了,有时候使用 快速合并,有时候又不使用 快速合并,这实在太不可控了。
第二种情况
如果你想在可以进行 Fast Forward 快速合并的时候,而不使用快速合并,该怎么做呢?
你只要加上 --no-ff
参数即可,由于会产生一个新的 commit ,你可以加上 -m
添加合并信息,当然不加的话,Git 会帮你生成默认的合并信息
$ git merge dev --no-ff -m "sometext"
第三种情况
如果你只想使用 Fast Forward 快速合并呢,又该怎么做呢?
只要加上 --ff-only
参数即可
$ git merge dev --ff-only
4.5 删除分支
# 删除本地dev分支:dev不能是当前分支
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.6 分支冲突
请查阅:廖雪峰:解决合并冲突问题
- master分支:只有a.txt,但在分支dev提交了b.txt,b.txt在master分支是没有的。这种合并是不会有问题的,合并后,master,将增加b.txt
- 在分支dev修改了内容,切换到master,对同一文件修改同一处地方的不同内容。这时候合并,就会出现冲突,我们需要手动修改文件为我们需要的内容,然后最后提交。
当合并代码时出现冲突的时候,有两种情况:
1、在本地 merge 就发现冲突
2、在远程 pr 才发现冲突
如果是远程 pr 才发现有冲突,可以将远程的 pr 及 commit 撤消掉
git reset --soft head
git push origin -f
然后在本地要合并的分支里,pull 一下
git checkout feature/2.5.1
git pull origin
再切换到个人分支,支持 merge
git checkout 2.5.1-by-wangbm
git merge feature/2.5.1
这时候本地就会发现冲突,切换到 idea 中,右键项目就会有一个 解决冲突的按钮(这个按钮只有在有冲突的时候才会出现),然后就可以看到有冲突的文件,对每个文件点 merge,进行冲突的处理。
都处理好后,再提交代码到远程,再提交 pr 合并代码。
4.7 本地分支与远程分支
- 本地分支如果和远程分支同名,push时只要写一个分支名即可
- 如果不同名,可以使用”git push -u origin local_branch_name:remote_branch_name”
五、保存现场stash
假如我们当前正在dev分支工作,但是master主分支有bug需要紧急修复,但是dev的工作才进行到一半,完成还需要一天,我们想在不提交的情况下,把bug修复好,改怎么做?
1、先使用 git stash
将当下修改的内容很保存,此时 git status 就不会有已修改的任何内容
2、然后在当前分支将 bug 修复
3、将修复 bug 的代码合并提交到 master 上
4、再通过 git stash list
可以看到自己保存的内容,使用 git stash pop
恢复之前保存的内容
5、如果 list 中有多个stash,可以选择 git stash apply stash@{1}
6、git stash pop
= git stash apply
+ git stash drop
六、标签管理
6.1 标签的意义
- 标签的作用相当于commit ID
- 区别在于commit ID是机器生成的,不便于记忆和可读性,tag是人为设定的,有特殊意义,有很强的可读性
6.2 如何打标签
首先切换到你要打标签的分支上,通常是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
6.3 删除标签
1. 本地删除
git tag -d v1.0 #删除标签v1.0
2. 远程删除(如果已经推送到远程,要先本地删除,再远程删除两个步骤)
git push origin :refs/tags/v1.0
# 要查看是否远程删除了,可以上GitHub上看
七、查看状态
7.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>
7.2 Git日志
第一种方法
可以查看who在when修改了文件(会写出版本说明),但是这个看着眼花缭乱
$ git log
第二种方法
显示所有修改的日志
$ git reflog
第三种方法
以图表的方法
$ git log --oneline --graph -10
7.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
八、实用命令
8.1 打包最近修改的文件
打包最近一次提交的文件到 zip 包里
git archive --format=zip -o update.zip HEAD $(git diff --name-only HEAD^)
8.2 保留开源项目提交
首先当然是要 git clone
git clone https://github.com/kubevirt/containerized-data-importer.git
然后修改一下 remote
git remote remove origin
git remote add origin https://code.ecp.xxxx.net/scm/kubevirt/containerized-data-importer.git
删除原来的 origin 后,会丢失所有的 release 提交记录,最后只能提交 main 分支
git push -u origin main
8.3 私有仓库用户更换
内网仓库原来的用户名是域帐号,现在全换成名字全拼。
因此底下的 git 凭据要更换,正常来说,是修改两个地方
1、git config
# 如果仓库存在,且有 local 配置才执行,没有就不执行
git config --local user.name "xxx"
git config --local user.email "xxx"
# 都要执行
git config --global user.name "xxx" //非必须执行
git config --global user.email "xxx" //非必须执行
2、windows 凭据
win 里搜索 凭据,删除git仓库的凭据(如果有的话)
正常来说是以上两个步骤,但我这种情况属于第三种情况。
该仓库只有部分人有权限,意味着去 clone 的时候,就会检查是不是 public 的,如果不是,就没有权限查看,这样一来连出现重新输入用户名的机会都没有
因为需要将该 git url 与用户名绑定,当访问该 git url 时,就使用该用户名去访问。
两个方法:
1、使用 git config –global key "value" 格式设置下面两个配置
credential.https://code.ecp.xxxx.net.helper=store
credential.https://code.ecp.xxxx.net.username=wangbingming
2、使用 TortoiseGit 可以 点 Setting ,在 Credential 里添加一个 Helper
URL: https://code.ecp.xxxx.net
Helper: store
Username: wangbingming