- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
- Remote:远程仓库
本地仓库操作
配置文件与变量
Git自带一个git config工具来控制Git的外观和行为的配置变量,这些变量分别存储在三个位置
- 1./etc/gitconfig,这是系统上每一个用户的仓库通用配置,如果在执行git config时带上–system参数,name它就会读写该文件中的配置变量,一般需要超级用户权限才能修改它
- 2./.gitconfig或者/.config/git/config文件,只针对当前用户有效,通过参数–global选项让Git读取该文件,这回对当前用户系统上所有的仓库有效
- 3.当前使用仓库的Git目录中的config文件即.git/config,它只针对当前仓库有效,通过参数–local来让Git强制读写此文件,默认情况下是使用该配置文件(在进入到某个具体的仓库时)
Windows 系统中,Git 会查找 $HOME 目录下(一般情况下是 C:\Users$USER )的 .gitconfig 文件
可以通过命令查看所有的配置及它们所在的文件:
# 查看所有配置变量
git config --list
# 编辑git配置文件(全局可选)
git config -e [--global]
# 查看具体变量
git config <变量名>
本地仓库初始化
# 选择项目所在目录执行,初始化目录
git init <项目名称>
# 初始化用户信息
git config --global user.name <用户名>
git config --global user.email <邮箱:xxxxx@xxx.com>
# 生成公私钥,然后一直回车,生成成功后将存在 ~/.ssh目录下,将id_rsa.pub粘贴到geriit上
ssh-keygen -t rsa
# 配置文本编辑器,默认使用操作系统默认的编辑器(可选,非必要)
git config --global core.editor <编辑器名称>
克隆远程代码
# ssh协议url需要在对应代码托管平台添加公钥私钥,自定义仓库名为可选项
git clone <url> <自定义仓库名>
追踪本地修改或添加的代码
# 添加指定文件到暂存区
git add [文件1] [文件2]
# 添加指定文件夹到暂存区
git add [文件夹]
# 每个变化前都会要求确认,同一个文件多处变化可以实现分次提交
git add -p
git add * 追踪所有被修改的文件(git与*之间必须有空格)
git add . 追踪当前文件夹下所有文件(git与.之间必须有空格)
git add *.后缀名(比如*.html)追踪所有是此后缀名的文件
提交代码到本地工作区
注意:下面[文件1],[文件2]这种都是需要输入文件的绝对路径或者相对路径,比如绝对路径D:\xxx\xxx.java,又或者该文件在当前文件夹的子文件夹中,那么就是.\xxx\xxx.java,如果在父级文件夹那就是…\xxx\xxx.java这种形式来单个提交文件
PS: 注意commit只会提交最后一次add的修改记录,未add的记录不会被提交,即使是同一个文件
# 普通全部提交
git commit -m <message>
# 提交指定文件
git commit -m <message> [文件1] [文件2] ... [文件N]
# 跳过add步骤直接提交
git commit -a -m <message>
# 修改提交用户身份
git commit --amend --reset-author
# 附加提交并修改提交信息
git commit --amend -m <message>
# 附加提交文件
git commit --amend [文件1] [文件2]
查看操作记录日志
# 最简单的日志显示commit的SHA1值,创建作者和时间,提交信息
git log
# 一行简洁的记录
git log --oneline
# 详细版本
git log --stat
# 每次提交所引入的差异,n表示显示的记录
git log -p -n
# 查看某个提交者所提交的内容
git log --author=<user.name>
git log --committer=<user.name>
# 在某个日期之后提交的记录
git log --since= "2021.11.25"
git log --after=<date>
# 某个日期之前提交的记录
git log --until=<date>
git log --before=<date>
# 查找包含匹配内容的提交记录
git log --grep=<pattern>
# 某个字符串的变动历史提交
git log -S <string>
# 符合正则表达式内容的历史提交
git log -G <regex>
# 查看合并提交
git log --merges
# 查看非合并提交
git log --no-merges
# 显示当前分支最近的几次提交
git reflog
# 查看某个作者做了哪些提交
git log --author = <user.name>
# 查看某个文件的修改记录
git log -p [filepath]
# 按照作者分类查看所有提交
git shortlog
# 绘制一个图像来查看历史提交和分支结构
git log --graph
# 显示出指向提交的指针
git log --decorate
代码回退
# 放弃工作目录下的所有修改
git reset --hard HEAD
# 跳到指定版本并放弃所有修改
git reset --hard 版本编号
# 移除缓存区的所有文件
git reset HEAD
# 移除缓存区的指定文件
git reset <file path>
# 放弃某个本地文件的修改,其实就是rollback
git checkout <文件名>
# 放弃修改的文件代码(必须未git add)
git checkout .
# 回退到add之前一个版本,也就是可能文件还未被追踪之前的样子,是等级最低的回退,默认就是这个级别,回退的代码是保留的
git reset --mixed HEAD^/~
# 回退到commit之前一个版本,文件已经被追踪了,是次一级的回退,回退的代码是保留的
git reset --soft HEAD^/~
#HEAD重置到上一次提交的版本,并保留未提交的本地修改,如果想保留本地的提交,只是想回退版本可以这么做,会退的代码是没了的
git reset --keep <commit>
# 节点的全部丢失 回退到某次提交,本地的修改和回退的版本都丢失了,本地的代码是干净的
git reset --hard HEAD^/~
# 按照上面的回退等级回退N个版本,几个^/~就是几个版本
git reset --mixed/soft/keep/hard HEAD^^/~~
# 按照上面的等级回退到指定的版本
git reset --mixed/soft/keep/hard <commit>
# 重做指定版本,比如总共提交的A,B,C三次提交,但是B提交我不想要了,但是最后一次提交C我又还是想保留,那么就revert掉B那次的就行
# 首先需要获取B那次的commit id,然后执行revert commit id,然后可能会有冲突,解决冲突最后commit + push按照正常的流程提交即可
# 会生成一个新的记录,就是重做的记录,代码内容就只剩A + C了,B被回退掉了
git revert <commit>
查看当前文件追踪情况
git status
# 简洁显示初始化(一般用这个)
git status -s
# 显示某次提交的元数据和内容变化
git show <commit>
# 显示某次提交发生变化的文件
git show --name-only <commit>
# 显示某次提交时,某个文件的内容
git show <commit>:<filename>
代码对比
# 对比的是工作区与暂存区的共同文件
git diff
# 暂存区(已add但未commit文件)和最后一次commit(HEAD)之间的所有不相同文件的增删改
git diff --cached 或 git diff --staged
# 工作目录(已track但未add文件)和暂存区(已add但未commit文件)与最后一次commit之间的的所有不相同文件的增删改
git diff HEAD
# 可以查看最近一次提交的版本与往过去时间线前数X个的版本之间的所有文件之间的增删改
git diff HEAD~n 或 git diff HEAD^^^
# 比较两个分支上最后 commit 的内容有差异的文件的详细差异(更详细)
git diff <分支名1> <分支名2>
# 显示出所有有差异的文件(不详细,没有对比内容)
git diff branch1 branch2 --stat
# 显示指定文件的详细差异(对比内容)
git diff branch1 branch2 <filepath>
# 显示今天写了多少代码
git diff --shortstatus
# 查看某文件在何时何地被谁改了什么内容
git blame [filepath]
# 查看文件第x到y行的提交记录 git b
git blame -L x,y <filename>
删除文件
# 从已跟踪文件清单中移除
git rm -f <文件名> <文件2>
# 让文件保留在磁盘,但是并不想让 Git 继续跟踪
git rm --cached <文件>
# 递归删除一个文件夹下所有文件
git rm -r *
# 批量删除某文件下某后缀为xxx的文件
git rm \*.xxx
# 修改文件名并且放进缓存区
git mv <原文件名> <新文件名>
# 清理所有未被追踪的文件以及空的子目录(不会删除被忽略的文件)
git clean -f(强制删除)/-n(尝试删除,会提示)/-i(选择模式) -d
# 清理清理所有未被追踪的文件以及空的子目录(包括被忽略的文件)
git clean -d -f -x
暂存
# 存储所有被追踪的文件(push可以省略,可以暂存一部分,不写file默认暂存所有)
git stash [push] [file1] [file2] ... [fileN]
# 存储所有文件包括未追踪的文件
git stash -u
# 存储所有的文件(包含未追踪的和被忽略的文件)
git stash --all
# 存储自定义名(可以用来作为备注,这样的话就好辨认)
git stash -m <存储名>
# 查看所有的暂存列表
git stash list
# 查看stash详情 stash的名字一般为stash@{n} 这里要使用单引号括起来 'stash@{0}',否则可能会报错
git stash show -p <stash名字>
# 弹出最新的stash内容,并且不删除该次stash
git stash apply
# 弹出最新的stash内容,并且删除该次stash
git stash pop
# 弹出指定的stash内容,后面的名字最好使用单引号扩起来,否则可能无法被终端识别
git stash apply/pop 'stash@{0}'
# 删除某一个stash的内容
git stash drop 'stash@{0}'
# 清空所有stash内容
git stash clear
# 利用stash的部分重新创建一个分支
git stash branch <branchname>
二分法查找bug所在提交记录
# 通过二分法查找出现问题的代码提交
git bisect start <startcommit> <endcommit>
# 如果当前提交没有出现问题
git bisect good
# 如果当前提交有问题
git bisect bad
#循环往复一直到确认最后一个提交后复位
git bisect reset
分支操作
查看分支
# 查看当前分支名
git branch
# 查看分支的最后提交记录
git branch -v
# 查看远程分支
git branch -r
# 查看所有分支(包括远程与本地)
git branch -a
# 查看已经合并到当前分支的分支名称
git branch --merge
# 查看还没有合并到当前分支的分支名称
git branch --no-merged
创建分支
# 创建一个分支并且停留在当前分支
git branch <branchname>
# 创建一个分支,指向指定的commit
git branch <branch> <commit>
# 创建一个分支,与指定的分支建立追踪关系
git branch --track <branch> <remote-branch>
切换到指定的分支
# 切换分支
git checkout <branch>
# 创建另一个分支(必须不存在,否则报错)
git checkout -b <branch>
# 强行创建另一个分支,如果已经存在该分支则创建一个覆盖
git checkout -B <branch>
# 基于当前分支的所有提交创建一个全新的分支,没有任何提交历史
git checkout --orphan <branch>
# 切换分支的时候将修改内容一起打包带走 同步到切花你的分支下,但是当前分支的修改内容将会丢失
git checkout --merge <branch>
# 比较两个分支之间的差异内容,并且提供交互式界面进行进一步操作
git checkout -p <branch>
合并分支(快速合并)
# 首先切换到被合入的分支比如为分支develop,拉去到对应的进度,一般使用git pull
# 然后切换到合入到的分支比如叫master
# 合并develop到当前分支(也就是master分支)
git merge develop
# 解决冲突之后,提交解决好冲突的代码
git commit
# 提交到合入的分支
git push develop
# 如果想回滚之前的merge
git merge --abort
合并分支(变基)
与git merge查不到,但是会把被合入的分支的提交记录给冲掉,这样就只会有一个提交记录跟在当前分支后面,没办法看到之前的提交具体次数与内容,优点就是美观,没那么混乱,缺点就是不好溯源代码
git checkout master
git pull
git checkout feature
git rebase master
# 解决冲突
# 继续变基
git rebase --continue
# 如果出现问题需要撤销rebase
git rebase --abort
什么时候用merge?什么时候用rebase?
拉公共分支最新代码——rebase,也就是git pull -r或git pull --rebase。这样的好处很明显,提交记录会比较简洁。但有个缺点就是rebase以后我就不知道我的当前分支最早是从哪个分支拉出来的了,因为基底变了嘛,所以看个人需求了。总体来说,即使是单机也不建议使用
往公共分支上合代码——merge。如果使用rebase,那么其他开发人员想看主分支的历史,就不是原来的历史了,历史已经被你篡改了。举个例子解释下,比如张三和李四从共同的节点拉出来开发,张三先开发完提交了两次然后merge上去了,李四后来开发完如果rebase上去(注意,李四需要切换到自己本地的主分支,假设先pull了张三的最新改动下来,然后执行<git rebase 李四的开发分支>,然后再git push到远端),则李四的新提交变成了张三的新提交的新基底,本来李四的提交是最新的,结果最新的提交显示反而是张三的,就乱套了,以后有问题就不好追溯了
cherry pick
这个命令是将其他分支的某个提交单独合入到当前分支,当不想使用merge合入其他分支的全部提交时,就可以使用这个命令
# 在当前分支查看3次提交记录
git log --oneline -3
# 在需要被合入的分支查看3次提交记录
git checkout xxx
git log --oneline -3
# 显示结果
23d9422 [Description]:branch2 commit 3
2555c6e [Description]:branch2 commit 2
b82ba0f [Description]:branch2 commit 1
# 切换回来然后合入其他分支的提交
git checkout yyy
git cherry-pick 2555c6e
# 如果没有合入成功则说明存在冲突,那么解决完冲突之后再提交
git commit
删除分支
# 删除本地已经合并过的分支
git branch -d 分支名
# 强制删除本地还没合并过的分支
git branch -D 分知名
# 删除远程分支
git push origin --delete <远程分支名>
git branch -dr <远程分支名>
解决合并分支时的冲突
# 本来合并分支只有有冲突才会产生新的一个commit但是这个命令可以手动在没有冲突的前提下合并分支也创建一个commit
git merge --no-ff -m 分支名
# 使用当前分支 HEAD 版本,通常是冲突源文件的 <<<<<<< 标记部分,======= 的上方
git checkout --ours <文件名>
# 使用合并分支版本,通常是源冲突文件的 >>>>>>> 标记部分
git checkout --theirs <文件名>
# 标记为解决状态加入暂存区
git add <文件名>
rebase操作流程:
# 将当前分支的版本追加到从远程 pull 回来的节点之后
git pull --rebase
# 若发生冲突,则按以上其他方法进行解决,解决后继续
git rebase --continue
# 直到所有冲突得以解决,待项目最后上线前再执行
git push origin
# 若多次提交修改了同一文件,可能需要直接跳过后续提交,按提示操作即可
git rebase --skip
# 放弃一次合并
git rebase -abort
worktree
默认情况下,git init 或 git clone 初始化的 repo,只有一个 worktree,叫做 main worktree
# 一般新路径是“../根目录”与项目根目录同级,基于当前分支新建一个目录,新的分支名就是新建目录的名称
git worktree add <新路径>
# 基于当前分支,新建一个目录,新的分支名就是指定的新分支名
git worktree add <新路径> -b <新分支名>
# 基于指定分支新建一个目录,新的分支名就是指定的名称
git worktree add <新路径> -b <新分支名> <指定分支名>
# 查看当前所有的worktree
git worktree list
# 删除所有的worktree
git worktree remove <名字>
# 清理所有的worktree
git worktree prune
远程仓库操作
# 查看所有远程仓库
git remote -v
# 查看远程仓库更多信息
git remote show <remote>
# 添加远程仓库
git remote add <shortname> <url>
# 修改远程仓库名字
git remote rename <oldname> <newname>
# 删除远程仓库
git remote remove <remotename>
# 下载远程仓库代码的指定分支并且合并到本地的指定分支
git pull <remote> <remotebranch> <localbranch>
# 下载远程仓库所有分支代码但是并不合入分支,可以与git merge一起用=git pull
git fetch <remote>
# 拉取指定仓库的指定分支代码
git fetch <remote> <branch>
使用 clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以origin为简写。
提交代码
# 将本地代码库更新到远程仓库
git push <remote> <branch>
# 强行推送当前分支到远程仓库,即使有冲突
git push <remote> --force
# 推送所有分支到远程仓库
git push <remote> --all
# 正常提交到远程的命令
git push origin develop
忽略文件
创建一个名为 .gitignore 的文件,列出要忽略的文件的模式
文件 .gitignore 的格式规范如下:
- 所有空行或者以 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中
- 匹配模式可以以(/)开头防止递归。
- 匹配模式可以以(/)结尾指定目录
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf
查找内容
# 查找匹配的内容
git grep <内容>
# 查找匹配的内容并显示行号
git grep -n <内容>
# 查找出现的次数
git grep -c <内容>
# 查找出现的地方并显示上下文
git grep -p <内容>
标签相关操作
# 列出所有的tag
git tag
# 新建一个tag在当前commit
git tag <tag>
# 新建一个tag在指定的commit
git tag <tag> <commit>
# 删除远程tag
git push origin :refs/tags/<tagName>
# 查看tag信息
git show <tag>
# 提交指定tag
git push <remote> <tag>
# 提交所有tag
git push <remote> --tags
# 创建一个分支,指向某个tag
git checkout -b <branch> <tag>