Git常用指令

本文并不是Git的使用教程!!!因为自己总是记不住Git的一些常用指令,所以写了本文作为一个笔记,方便自己随时查阅。

一、Git 基本概念

git 中的文件可以存在三个地方,分别是工作区、暂存区和版本库。

  1. 工作区:就是你在电脑里能看到的目录。
  2. 暂存区:英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  3. 版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。

二、git config

#全局配置用户名及邮箱,这个配置会应用到所有的Git仓库,在Commit的时候会带上这个信息
$ git config --global user.name "XingyongGuo"
$ git config --global user.email "xingyong.guo@outlook.com"

#设置Git默认使用的文本编辑器, 一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 vscode 的话,可以重新设置
$ git config --global core.editor code

#设置Git差异分析工具
$ git config --global merge.tool vimdiff

#查看Git配置信息
git config --list

#使用vscode作为difftool
$ git config --global core.editor "code --wait"
$ git config --global -e
#添加
[diff]    tool = default-difftool[difftool "default-difftool"]    cmd = code --wait --diff $LOCAL $REMOTEn 

三、基本操作 init/clone/add/commit

git 最基本的用法就是创建一个仓库 -> 添加文件到暂存区 -> 从暂存区提交到版本库。
创建一个仓库可以使用本地init从本地的文件夹创建,或者clone你需要的仓库到本地,然后在仓库下进行正常的开发,当到达某个节点,比如想临时做一个什么尝试,又想保留当前的状态,但是当前状态又不是那么重要的时候,你就可以把文件提交到暂存区,但是如果当前版本还是比较重要,那还是commit一次吧。

######使用本地文件夹创建仓库######
git init                #在当前文件夹下创建git仓库
git init newrepo        #在指定文件夹下创建git仓库

#########clone已有的仓库###########      
git clone <repo>                        #clone指定的仓库
git clone <repo> <directory>            #clone指定的仓库并命名为<directory>
git clone <repo> --recurse-submodules   #clone指定的仓库并clone仓库的子模块

#########将文件添加到暂存区#########
git add [file1] [file2] ...          #添加一个或多个文件到暂存区
git add [dir]                        #添加指定目录到暂存区,包括子目录
git add .                            #添加当前目录下的所有文件到暂存区
git add -A                           #添加所有改变的已跟踪文件和未跟踪文件
git add -u                           #只更新已经跟踪的文件

######提交暂存区到本地仓库中########
git commit -m [message]              #提交暂存区到本地仓库中
git commit [file1] [file2] ... -m [message]     #提交暂存区指定文件到本地仓库中
git commit -a                        #等于 Add + Commit

四、status/diff/log/

git status 是用来查看当前仓库下的文件状态的,可以看到文件是否已经添加到暂存区以及添加到暂存区后有没有再次修改文件。想查看文件的改动就需要使用diff命令。

git status
git status -s    #查看简短的信息
#######
A:  已经添加到暂存区
AM: 这个文件在我们将它添加到缓存之后又有改动。

*********************************************************************

git diff             #尚未缓存的改动
git diff --cached    #查看已缓存的改动
git diff HEAD        #查看已缓存的与未缓存的所有改动
git diff --stat      #显示摘要而非整个 diff

#显示暂存区和工作区的差异
git diff [file]      

#显示暂存区和上一次提交(commit)的差异
git diff --cached [file]
或
git diff --staged [file]  

#显示两次提交之间的差异
git diff [first-branch]...[second-branch]

*********************************************************************

# --oneline 选项来查看历史记录的简洁的版本
git log --oneline

# --graph 选项,查看历史中什么时候出现了分支、合并
git log --oneline --graph

#查看完整log,包含分支结构 
git log --all --decorate  --graph --oneline

# --reverse 参数来逆向显示所有日志
git log --reverse --oneline

#--author只想查找指定用户的提交日志 (查看5条)
git log --author=XingyongGuo --oneline -5

#指定日期,可以执行几个选项:--since 和 --before,但是你也可以用 --until 和 --after
#查看 Git 项目中三周前且在四月十八日之后的所有提交,我可以执行这个(--no-merges 选项以隐藏合并提交)
git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges

#查看指定文件的修改记录
git blame <file>

五、checkout

这个命令有两种用法,第一种是切换分支,第二种是撤销修改

checkout 本意是检出的意思,也就是将某次commit的状态检出到工作区;所以它的过程是先将HEAD指向某个分支的最近一次commit,然后从commit恢复index,最后从index恢复工作区。

切换分支

 #切换到指定分支
git checkout branchname   

#创建并切换到新的分支 = git branch newbranch + git checkout newbranch
git checkout -b branchname 

#切换分支的时候如果暂存区有没有提交的变动,Git则会阻止切换分支,如果需要丢弃未提交的变动可以加 -f 强制切换。但是如果想保留变动则可以先使用reset将文件从暂存区移除,然后再切换,或者stash当前暂存区的文件。

放弃修改

1、只放弃工作区的改动,index 保持不变,其实就是从当前 index 恢复 工作区:

#放弃工作区中全部的修改
git checkout .
#放弃工作区中某个文件的修改 先使用 git status 列出文件
git checkout -- filename

2、强制放弃 index 和 工作区 的改动:
git checkout -f
这是不可逆的操作,会直接覆盖

六、reset

当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

 #--mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。
git reset [--soft | --mixed | --hard] [HEAD]   

git reset HEAD^            # 回退所有内容到上一个版本  
git reset HEAD^ hello.php  # 回退 hello.php 文件的版本到上一个版本  
git reset 052e             # 回退到指定版本

#--soft 参数用于回退到某个版本
git reset --soft HEAD~3 # 回退上上上一个版本

#--hard 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
git reset –hard HEAD~3              # 回退上上上一个版本  
git reset –hard bae128              # 回退到某个版本回退点之前的所有信息。 
git reset --hard origin/master      # 将本地的状态回退到和远程的一样 


HEAD 说明:
    HEAD 表示当前版本
    HEAD^ 上一个版本
    HEAD^^ 上上一个版本
    HEAD^^^ 上上上一个版本
以此类推...

可以使用 ~数字 表示
    HEAD~0 表示当前版本
    HEAD~1 上一个版本
    HEAD^2 上上一个版本
    HEAD^3 上上上一个版本
以此类推...

七、stash

在工作过程中,一定会遇到临时需要切换到别的分支做一些工作的时候,如果此时有未提交的文件但是又不想在此时提交的话就需要暂存当前的文件。

将本地没提交的内容进行缓存并从当前分支移除,缓存的数据结构为堆栈,先进后出。当前工作区没有被追踪的文件是不会被暂存的,所以需要暂存的话需要先add到暂存区。
git stash                    #缓存
git stash save               #缓存
git stash save "*****"       #缓存时加上自己的注解
git stash list               #返回缓存的列表
git stash pop                #将堆栈中最新的内容pop出来应用到当前分支上,且会删除堆中的记录
git stash pop stash@{$num}   #从缓存堆栈中取出指定的一次缓存
git stash apply              #与pop相似,但他不会在堆栈中删除这条缓存,适合在多个分支中进行缓存应用
git stash apply stash@{$num}
git stash drop stash@{$num}  #删除单个缓存
git stash clear              #全清
git stash show stash@{$num}  #显示与当前分支差异加上-p可以看详细差异
git stash branch             #使用缓存创建分支

八、mv/rm

#git mv 命令用于移动或重命名一个文件、目录或软连接

#如果新文件名已经存在,但还是要重命名它,可以使用 -f 参数
git mv -f [file] [newfile]

*****************************************************************************

#将文件从暂存区和工作区中删除
git rm <file>

#如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f
git rm -f <file>

#仅是从跟踪清单中删除(暂存区域移除)
git rm --cached <file>

#递归删除
git rm –r * 

九、remote/pull/push/fetch

#显示所有远程仓库
git remote -v

#显示某个远程仓库的信息
git remote show [remote]

#添加远程版本库
git remote add [shortname] [url]

# 删除远程仓库
git remote rm name  

# 修改仓库名
git remote rename old_name new_name  

*********************************************************************

git pull <远程主机名> <远程分支名>:<本地分支名>

#将远程主机 origin 的 master 分支拉取过来,与本地的 brantest 分支合并
git pull origin master:brantest
or:
git fetch origin master
git checkout brantest
git merge origin/master

#如果远程分支是与当前分支合并,则冒号后面的部分可以省略
git pull origin master

*********************************************************************

git push <远程主机名> <本地分支名>:<远程分支名>
#如果本地分支名与远程分支名相同,则可以省略冒号
git push <远程主机名> <本地分支名>

#如果本地版本与远程版本有差异,但又要强制推送可以使用 --force 参数
git push --force origin master

#删除主机的分支可以使用 --delete 参数,以下命令表示删除 origin 主机的 master 分支
git push origin --delete master

*********************************************************************

#Fetch仓库中所有分支。同时也会下载指定远端的所有commits和文件。
git fetch <remote>

#Fetch 指定分支
git fetch <remote> <branch>

#fetch所有已注册过的远端仓库的全部分支
git fetch --all

十、branch/merge/cherry-pick

#列出分支
git branch

#创建分支命令
git branch (branchname)

#切换分支命令
git checkout (branchname)

#创建新分支并立即切换到该分支下
git checkout -b (branchname) 

#删除分支
git branch -d (branchname)

#合并分支命令
git merge (branchname) 
如果可以使用Fast forward merge模式,Git将会默认使用该模式
git merge --no-ff 不使用快速合并,合并后提交到新的commit

#将某一次提交的修改同步到当前分支并commit到一个新的节点
git cherry-pick <commitHash>

#将某一次提交的修改同步到当前的工作区和暂存区,但是不提交
git cherry-pick -n <commitHash>

#在导入修改commit之前修改提交信息
git cherry-pick -e <commitHash>

#可以直接使用分支名代替<commitHash>导入分支中最新的一次提交
git cherry-pick <branch-name>

#导入多个提交
git cherry-pick <HashA> <HashB>        #将 A 和 B 两个提交应用到当前分支。这会在当前分支生成两个对应的新提交
git cherry-pick A..B                   #转移从 A 到 B 的所有提交,不包括A
git cherry-pick A^..B                  #转移从 A 到 B 的所有提交,包括A

#代码冲突
#解决冲突后
git add .
git cherry-pick --continue
#放弃合并,回到合并之前
git cherry-pick --abort
#退出合并,不回到合并之前
git cherry-pick --quit

#转移另一个代码库的提交,需要先将该库加为远程仓库
git remote add target git://gitUrl     #添加了一个远程仓库target
git fetch target                       #将远程代码抓取到本地
git log target/master                  #检查一下要从远程仓库转移的提交,获取它的哈希值
git cherry-pick <commitHash>           #使用git cherry-pick命令转移提交

git cherry-pick命令的常用配置项如下:
(1)-e,--edit
打开外部编辑器,编辑提交信息。
(2)-n,--no-commit
只更新工作区和暂存区,不产生新的提交。
(3)-x
在提交信息的末尾追加一行(cherry picked from commit ...),方便以后查到这个提交是如何产生的。
(4)-s,--signoff
在提交信息的末尾追加一行操作者的签名,表示是谁进行了这个操作。
(5)-m parent-number,--mainline parent-number
如果原始提交是一个合并节点,来自于两个分支的合并,那么 Cherry pick 默认将失败,因为它不知道应该采用哪个分支的代码变动。
-m配置项告诉 Git,应该采用哪个分支的变动。它的参数parent-number是一个从1开始的整数,代表原始提交的父分支编号。
 $ git cherry-pick -m 1 <commitHash>
上面命令表示,Cherry pick 采用提交commitHash来自编号1的父分支的变动。
一般来说,1号父分支是接受变动的分支(the branch being merged into),2号父分支是作为变动来源的分支(the branch being merged from)。

十一、submodule

git clone <repository> --recursive 递归的方式克隆整个项目
git submodule add <repository> <path> 添加子模块
git submodule init 初始化子模块
git submodule update 更新子模块
git submodule foreach git pull 拉取所有子模块