Git使用总结之命令篇
一直以来要写一篇关于git命令使用的文章,最近终于挤出来时间把常用的命令汇总一下方便自己和同学们查考,阅读本文需要同学们有点git使用基础。网上入门教程很多可以稍做了解,楼主很不赞成开发者开始就使用可视化界面去操作平时的代码管理。因为如果开发团队人数少的话还可以,人数几十上百个的话,如果开发对于git的原理不熟悉就很容易导致项目管理的混乱。
概念
git 最让人迷惑的就是一些概念名称,我把这些不太容易理解或者混淆的单独拎出来做下回顾。
工作区
暂存区
仓库
在初始化git版本库之后会生成一个隐藏的文件 .git ,可以将该文件理解为git的版本库 repository,而我们自己建立的项目文件夹即工作区 working directory ,在.git 文件夹里面还有很多文件,其中有一个index 文件 就是暂存区也可以叫做 stage ,git还为我们自动生成了一个分支master以及指向该分支的指针head ,可以看到版本库里维护了暂存区和分支两大部分。当然分支可以有很多个
工作区: 一般是我们项目的目录
暂存区: 本地项目如果有内容修改后 通过git add 命令就把工作区的修改记录同步到了暂存区(使用git checkout 命令把暂存区域的修改撤销,会在撤销相关进行详细描述)
分支: 当我们在某个分支上进行commit 操作就把当前暂存区的 (通过git reset 把提交到分支的commit 记录撤销到暂存区。会在撤销相关进行详细描述)
下面的内容我们就会围绕这几个区域进行详细的说明
HEAD
,HEAD^
, HEAD~
https://blog.csdn.net/fly_zxy/article/details/82593842
参考-选择修订版本
HEAD: 可以理解为我们每次提交的commit都为一个指针,HEAD即为指向当前分支最后一次提交的一个指针
HEAD^ : 在HEAD的基础上的父提交,如果^n n为数字(查看当前comitid的第n次父提交的内容)
HEAD~:当前HEAD基础上的上一次提交内容(区别于^), ~n 为往上数第n次提交记录
合并使用HEAD~3^2 :当前分支最新提交的前三次提交的第二个父提交的指针。
容易引起迷惑的一些点
分支合并(git rebase,git merge)
git 分支合并原则 尽可能保留分支的操作过程,也就是分支信息和commit提交信息
参考
git rebase
:使用原则: 对于不再有子分支的branch,并且因为rebase而会被重写的commits都还没有push分享过,可以比较安全地做rebase,如果满足上面的条件则非常建议使用git rebase
git cherry-pick <commit id>
git rebase 针对的是分支,此命令针对的是特定的commit id 使用场景可按照rebase的原则来
git merge
: 按照合并的原则是尽可能保存commit的分支以及提交记录,–no-ff比较常用
--no-ff
指的是强行关闭fast-forward方式,不使用fast-forward方式合并,保留分支的commit历史
--squash
是用来把一些不必要commit进行压缩,比如说,你的feature在开发的时候写的commit很乱,那么我们合并的时候不希望把这些历史commit带过来,于是使用–squash进行合并
错误案例:
下面展示了已经在中央库存在的feature分支,两个开发人员Bob和Anna做了对feature分支针对master做rebase操作后,再次push并且同步工作带来的灾难:历史混乱,并且merge后存在多个完全相同的changeset。
也就是说,Master 这个分支是一个共享分支,多个开发人员都在其上有提交的commit,如果对rebase Master到自己的分支然后再次提交的自己的feture就会造成如上的一些混乱的历史。
正确范例:
假如有两个分支并行开发 一个叫Feture 一个叫 John/Feture
git 合并一个独立的分支到自己的私有分支上。
如上图展示了 git rebase Feature 到 John/Feature ,虽然 rebase和merge 都能达到效果,但是如上的rebase 更清爽一些。
可以总结为:git rebase 后面的分支名一定不要是多人共享的分支,可以是本地的私有分支,可以是仓库里独立开发的分支
撤销 (git reset ,git revert, git reflog)
常用的两个撤销相关的命令git reset
和git checkout
git resest --hard
commitid 比较危险直接把选中的commitid作为当前分支的HEAD,并且清空暂存区。合理使用
git reset --soft
commitid 把commitid之前的恢复到暂存区。注意这个commit是需要回退的commit的前一个commit
git revert commitid
把commitid 回退到当前的版本库,和git reset --hard的区别是HEAD 指针继续向前,而不是直接退回到某个commit并且删除记录。revert 后会在原有提交记录的基础上新增一条记录但是内容会返回到commitid对应的提交内容。
git reflog
分支被删除或者git reset --hard 删除了一些提交记录后 也可以通过此命令查看一些提交的记录。
记录(git log)
git log --graph --decorate --oneline --simplify-by-decoration --all
所有的tag和历史branch都会被列出来,即使branch被delete了
–decorate 标记会让git log显示每个commit的引用(如:分支、tag等)
–oneline 一行显示
–simplify-by-decoration 只显示被branch或tag引用的commit
–all 表示显示所有的branch,这里也可以选择,比如我指向显示分支ABC的关系,则将–all替换为branchA branchB branchC
常用:git log --graph master >查看master 的详细提交合并记录
项目管理
正常公司级别的git 分支管理需要拆分如下几个如Master
,Release
,Feture
,HotFix
等
分支名称 | 使用场景 |
---|---|
Master |
一直接收从其他分支上合并过来的提交,本身分支不做开发使用 |
Release |
版本分支,每次版本迭代新开一个release分支,和版本绑定 ; 从Master出 根据公司运营情况决定Release分支的保存时间 |
Feture |
功能分支 ,一次版本迭代可能有多个功能并行开发根据功能差异分为不同的功能分支,从Release出,合并到Release分支并上线后删除此分支 |
HotFix |
快速修复分支:当一次产品升级后,出现了需要紧急修复的bug时切换的分支,可以从master出,也可以从release出。看具体版本合并情况;上线完成后删除该分支 |
基础命令备份
- git配置(config)
git version
# 查看版本
git config -l
# 查看当前配置
git config --global user.name "Dean"
# 设置用户名,邮箱
git config --global user.email [email protected]
# 设置用户名,邮箱
git config --global alias.ci commit
# 设置git命令的别名
git config --global alias.co checkout
# 设置git命令的别名
- git仓库(repository)
创建一个本地的git仓库并命名:
git init demo
克隆一个远程的git仓库到指定路径:
git clone
https://github.com/a396901990/android.git /path/workpsace
- git分支(branch)
git branch
# 查看分支
git remote show origin
# 查看所有分支
git branch <branchname>
# 创建新分支
git checkout <branchname>
# 切换到分支
git checkout -b <new_branch>
# 创建并切换到新分支
git branch -d <branchname>
# 删除分支(-D强删)
git branch -m <old> <new>
# 本地分支重命名
- git添加(add)
git add <file>
# 将本地指定文件名或目录(新增和修改,没有删除)的文件添加到暂存区
git add .
# 将本地所有的(新增和修改,没有删除)文件添加到暂存区
git add -u
# 将本地的(修改和删除,没有新增)文件添加到暂存区
git add -A
# 将本地所有改动添加到暂存区(git add -A = git add . + git add -u)
git add -i
# 打开一个交互式界面按需求添加文件
- git删除/重命名(rm/mv)
git rm <file>
# 删除文件
git rm -r <floder>
# 删除文件夹
git rm --cached <file>
# 从版本库中删除文件,但不删除文件
git mv <old_name> <new_name>
# 文件重命名
- git提交(commit)
git commit -m "comment"
# 提交暂存区中的内容(已经add)并添加注释
git commit -a
# 把修改的文件添加到暂存区(不包括新建(untracked)的文件),然后提交。
git commit --amend
# 修改提交的commit(没有push)
git commit --amend -m "comment"
# 修改commit注解
- git差异(diff)
git diff
# 查看工作目录(working tree)暂存区(index)的差别
git diff --cached
# 查看暂存起来的文件(stage)与并未提交(commit)的差别
git diff --staged
# 同上
git diff HEAD
# 查看最后一次提交之后的的差别(HEAD代表最近一次commit的信息)
git diff --stat
# 查看显示简略结果(文件列表)
git diff commit1 commit2
# 对比两次提交的内容(也可以是branch,哈希值)
- git查看历史(log)
git log
git log -3
# 查看前3次修改
git log --oneline
# 一行显示一条log
git log -p
# 查看详细修改内容
git log --stat
# 查看提交统计信息
git log --graph
# 显示何时出现了分支和合并等信息
- git查看状态(status)
git status
# 查看你的代码在缓存与当前工作目录的状态
git status -s
# 将结果以简短的形式输出
git status --ignored
# 显示被忽略的文件
- git存储(stash)
git stash
# 保存当前的工作进度
git stash save "message"
# 保存进度加说明
git stash list
# 显示进度列表
git stash pop
# 恢复最新保存的工作进度,并将恢复的工作进度从存储的列表中删除
git stash apply
# 恢复最新保存工作进度,但不删除
git stash drop
# 删除一个进度,默认删除最新的
git stash clear
# 删除所有
- git重置(reset)
git reset --mixed
# 同不带任何参数的git reset一样,重置暂存区,但不改变工作区
git reset --soft
# 回退到某个版本,不改变暂存区和工作区(如果还要提交,直接commit即可)
git reset --hard
# 彻底回退到某个版本,替换暂存区和工作区,本地的源码也会变为上一个版本的内容
git reset
# 将之前用git add命令添加到暂存区的内容撤出暂存区(相当于git add -A 的反向操作)
git reset HEAD
# HEAD 效果同上,因为引用重置到HEAD相当与没有重置
git reset filename
# 将文件撤出暂存区(相当于git add filename的反向操作)
git reset HEAD^
# 引用回退一次(工作区不变,暂存区回退)
git reset --soft HEAD~3
# 引用回退三次(工作区不变,暂存区不变)
- git撤销(revert)
git revert commit
# 撤销指定commit
git revert HEAD
# 撤销上一次commit
git revert -no-edit HEAD
# 撤销上一次并直接使用默认注释
git revert -n HEAD
# 撤销上一次但不commit
- git合并(merge)
git merge <branch_name>
# 合并
git merge --no-ff <branch_name>
# 采用no fast forward的合并方式,这种方式在合并的同时会生成一个新的commit
git merge --abort
# 尽量回退到merge前的状态(可能会失败)
- git重新基变(rebase)
git rebase <branch_name>
#
git rebase --continue
# 执行rebase出现冲突解决后,执行该命令会继续应用(apply)余下的补丁
git rebase --skip
# 跳过当前提交
git rebase --abort
# 终止rebase, 分支会回到rebase开始前的状态
- git获取/拉(fetch/pull)
git fetch
# 从远程获取最新版本到本地,不会自动merge
git pull
# 从远程获取最新版本并merge到本地
git pull --rebase
# 暂存本地变更,合并远程最新改动,合并刚刚暂存的本地变更(不产生无用的merge的同步)
- git推(push)
git push origin master
# 将本地分支推送到origin主机的master分支
git push -u origin master
# -u指定origin为默认主机,后面就可以不加任何参数使用git push了
git push -f origin
# -f强推,在远程主机产生一个"非直进式"的合并(non-fast-forward merge)
git push --all origin
# 将所有本地分支都推送到origin主## 不常用但比较实用
比较实用的一些高级命令
命令 | 解释 |
---|---|
git reflog --date=local | grep '分支名' |
查看特定分支是从哪个分支checkout出来的 |
git archive -o ../updated.zip HEAD $(git diff --name-only HEAD^ ) |
把最近修改的记录打一个压缩包 |
git archive -o ../latest.zip NEW_COMMIT_ID_HERE $(git diff --name-only OLD_COMMIT_ID_HERE NEW_COMMIT_ID_HERE) |
输出两个commitid之间的区别到zip文件中 |
只检出特定的分支而不是全部内容
git init
git remote add -t BRANCH_NAME_HERE -f origin REMOTE_REPO_URL_PATH_HERE
git checkout BRANCH_NAME_HERE|
开始一个无历史的新分支
git checkout --orphan NEW_BRANCH_NAME_HERE
不想切换分支,但是又想从其它分支中获得你需要的文件:
git checkout BRANCH_NAME_HERE -- PATH_TO_FILE_IN_BRANCH_HERE
如果您正在一个团队中工作,而且大家都在同一条branch上面工作,那么您很有可能会经常用到fetch和merge。但是有时候这样会重置您的环境配置文件,如此的话,您就得在每次merge后修改它。使用这一命令,您就能要求git忽视指定文件的变动。这样,下回你再merge的话,这个文件就不会被修改了。
git update-index --assume-unchanged PATH_TO_FILE_HERE
有时,你可能需要将Git仓库中某个特定的目录转换为一个全新的仓库
$ git filter-branch --prune-empty --subdirectory-filter master
# Filter the master branch to your directory and remove empty commits
Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89)
Ref 'refs/heads/master' was rewritten
有时,你需要将项目副本提供给无法访问GitHub仓库的外部成员。最简单的方式就是使用tar或zip来打包所有的项目文件。不过,如果不小心,隐藏的.git目录就会包含到tar文件中,这会导致文件体积变大;同时,如果里面的文件与接收者自己的Git仓库弄混了,那就更加令人头疼了。轻松的做法则是自动从tar文件中排除掉.git目录
ar cJf .tar.xz / --exclude-vcs