Git命令速查表
Git介绍
版本控制系统 VCS(Version Control System)
- Git是一个免费开源的分布式版本控制系统(DVCS)
- Git是一个基于内容寻址的存储系统
GitHub就是一个免费托管开源代码的远程仓库。
Git特性
- 快
- 完全的分布式
- 轻量级的分支操作
- Git已经成为现实意义上的标准
- 社区成熟活跃
Git 与常用的版本控制工具CVS、Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。
Git 与 SVN 区别
- Git 是分布式的,SVN不是:这是Git 和其它非分布式的版本控制系统如SVN,CVS等最核心的区别。
- Git 把内容按元数据方式存储,而SVN是按文件:所有的资源控制系统都是把文件的元信息隐藏在一个类似.svn和.cvs等文件夹里。
- Git分支和SVN的分支不同:分支在SVN中不特别,就是版本库中的另外的一个目录。
- Git没有一个全局的版本号,而SVN有:目前为止,这是跟SVN相比GIT缺少的最大的一个特征。
- Git 的内容完整性要优于SVN:Git 的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。
Git仓库模型
与svn最主要的区别在于大多数VCS(如svn)都是保存基于文件变化的列表数据,如p1.png。但是git不是这样的,当你提交一个版本状态到git时,相当于做了一个镜像,这个镜像保持和你提交的内容一致,为了高效,如果某个文件未改动,则git不会再在镜像中保存重复的文件,而是link到之前已存储的文件如p2.png。
git使用sha-1来check区分文件,实际上git保存所有数据都是依据该hash而不是使用文件名。
在git的所有操作中,都是对git数据库的增加操作,包括删除文件等操作,这是为了保证所有的操作都能够undo。
Git工作流程
一般工作流程如下:
- 将Git的一个存储库克隆为工作副本。
- 可以通过添加/编辑文件修改工作副本。
如有必要,还可以通过让其他开发人员一起来更改/更新工作副本。 - 在提交之前查看更改。
- 提交更改:如果一切正常,那么将您的更改推送到存储库。
- 提交后,如果意识到某些错误并修改错误后,则将最后一个正确的修改提交并将推送到存储库。
分支
从目标仓库获得一份项目拷贝,每条拷贝都有和原仓库功能一样的开发线。
分支模型(branching model)/ 工作流(workflow):
一个围绕项目【开发/部署/测试】等工作流程的分支操作(创建、合并等)规范集合。
产品级的分支模型
常驻分支 development
- 从master创建
production(master) - 默认分支
活动分支 feature
- 从development创建
hotfix 如hotfix-36(代码bug修复分支) - 从master创建
release 如release-110 - 从development分支创建
Git命令
git config
用于获取并设置存储库或全局选项,这些变量可以控制Git的外观和操作的各个方面。
- local 默认 高优先级:只影响本仓库
- global 中优先级:影响到所有当前用户的git仓库
- system 低优先级:影响到全系统的git仓库
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
用了这个参数表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。
如果想要检查你的配置,可以使用 git config --list 命令来列出所有 Git 当时能找到的配置。
你可以通过输入 git config
$ git config user.name
John Doe
- ssh-keygen
默认情况下,用户的 SSH 密钥存储在其 ~/.ssh 目录下。
git init
git init 命令执行完后会在当前目录生成一个 .git 目录,使用我们指定目录作为Git仓库。
git init repo
初始化后,会在repo 目录下会出现一个名为 .git 的目录,所有Git需要的数据和资源都存放在这个目录中。如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用
ls -ah命令就可以看见。
git add
添加文件内容到暂存区(同时文件被跟踪)
$ git add . # 将所有修改添加到暂存区
$ git add * # Ant风格添加修改
$ git add *Controller#将以Controller结尾的文件的所有修改添加到暂存区
$ git add Hello* # 将所有以Hello开头的文件的修改添加到暂存区 例如:HelloWorld.txt,Hello.java,HelloGit.txt ...
$ git add Hello? # 将以Hello开头后面只有一位的文件的修改提交到暂存区 例如:Hello1.txt,HelloA.java;如果是HelloGit.txt或者Hello.java是不会被添加的
# 提交被修改(modified)和被删除(deleted)文件,不包括新文件(new)
git add -u
git commit
根据暂存区内容创建一个提交记录,只负责把暂存区的修改提交了。
# -m后面输入的是本次提交的说明
git commit -m "提交记录文字"
添加文件到Git仓库,分两步:
- 使用命令git add
,注意,可反复多次使用,添加多个文件; - 使用命令git commit -m
,完成。
修改提交说明
git commit --amend -m "edit"
给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存 起来一并提交,从而跳过git add步骤。
你提交后发现忘记了暂存某些需要的修改,可以像下面这样
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
最终你只会有一个提交 - 第二次提交将代替第一次提交的结果。
git commit -am = git add + git commit -m
git status
查看目录,对状态的跟踪,用于显示工作目录和暂存区的状态。
git status -s 状态简览
- 未跟踪<>跟踪
- 工作目录 <> 暂存区
- 暂存区 <> 最新提交
Git 项目的三个工作区域的概念:Git 仓库、工作目录以及暂存区域
Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。
工作目录是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘
上供你使用或修改。暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。有时候也被称作“索引”,不过一般说法还是叫暂存区域。
基本的 Git 工作流程如下:
- 在工作目录中修改文件。
- 暂存文件,将文件的快照放入暂存区域。
- 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。
这三个区的转换关系以及转换所使用的命令:
git log
显示从最近到最远的提交日志
- git log --pretty=oneline
--pretty=oneline,只会显示版本号和提交时的备注信息
git reflog
用来记录你的每一次命令
git diff
显示不同版本差异
- git diff 显示工作目录与暂存区的差异
- git diff --cached 或者 git diff --staged 显示暂存区与上次提交快照的差异,默认为HEAD
- git diff master branchB 比较master分支和branchB分支之间的差异
git checkout --file
将文件从暂存区恢复到工作目录
git reset --file
将文件从提交区恢复到暂存区
添加远程仓库
- git remote add
添加一个新的远程Git仓库。
分支操作
git branch 分支的增删查改
$ git branch
iss53
* master
testing
注意看 master 分支前的*字符:它表示当前所在的分支。也就是说,如果现在提交更新,master 分支将随着开发进度前移。若要查看各个分支最后一个提交对象的信息,运行 git branch -v。
要从该清单中筛选出你已经(或尚未)与当前分支合并的分支,可以用 --merged 和 --no-merged 选项
- git branch -v 查看分析信息
- git branch -a 绿色代表当前项目所在的分支,红色就是远程分支列表
- git branch -r 查看远程分支
新建一个远程分支
先在本地准备好一个新的分支, 例如本地先准备好了一个新分支: feature-M5-2:
$ git branch
develop
* feature-M5-2
然后在把本地分支发布到远程库里面
git push origin feature-M5-2
git clone
将存储库克隆到新目录中。
克隆仓库的命令格式为:
git clone
如果我们需要克隆到指定的目录,可以使用以下命令格式:
git clone
参数说明:
- repo:Git 仓库。
- directory:本地目录。
git clone默认会把远程仓库整个给clone下来
但只会在本地默认创建一个master分支
如果远程还有其他的分支,此时用git branch -a查看所有分支。
git help
显示有关Git的帮助信息。
git merge
用于将两个或两个以上的开发历史加入(合并)一起。
- 查看分支:git branch
- 创建分支:git branch
- 切换分支:git checkout
- 创建+切换分支:git checkout -b
- 合并某分支到当前分支:git merge
- 删除分支:git branch -d
合并dev分支到master上
假设我们在dev分支上开发
step 1: 切换到master分支
checkout out master
step 2: 把远程master上的代码pull下来
git pull origin master
step 3: 合并dev分支到master
git merge dev
step 4: 查看状态
git statas
step 5:将commit push到远程分支master上
git push origin master
撤销合并
方法1:
- 退出合并,用于合并时出现冲突但不想现在解决冲突 git merge --abort
方法2:
step 1:找到最后一次提交到master分支的版本号,即【merge前的版本号】
git log --pretty=onelinestep 2:会退到某个版本号
git reset --hard 【merge前的版本号】
git fetch和git pull的区别
- git fetch:相当于是从远程获取最新版本到本地,不会自动合并。
- git pull:相当于是从远程获取最新版本并merge到本地。
git push 推送分支
远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义一样。
同时 “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用,
“origin” 是当你运行 git clone 时默认的远程仓库名字。
推送分支就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。
如果要推送其他分支,比如dev,就改成:
$ git push origin dev
多人在同一个分支上协作时,很容易出现冲突。即使没有冲突,后push的童鞋不得不先pull,在本地合并,然后才能push成功。
git push <远程主机名> <本地分支名>:<远程主机分支名>
这个是push的完整写法,将本地分支上传到远程分支,例如:
git push origin dev:dev
git push <远程主机名> <本地分支名>
如果省略了<远程主机分支名> 即:
git push dev
则git会push到远程分支的同名本地分支,即和
git push dev:dev
等价。如果远程分支dev不存在则会创建dev分支。
$ git push
如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
推送本地分支local_branch到远程分支remote_branch并建立关联关系
- 远程已有remote_branch分支并且已经关联本地分支local_branch且本地已经切换到local_branch
git push
- 远程已有remote_branch分支但未关联本地分支local_branch且本地已经切换到local_branch
git push -u origin/remote_branch
- 远程没有remote_branch分支且本地已经切换到local_branch
git push origin local_branch:remote_branch
git remote -v
查看关联的远程仓库的详细信息
pwd
用于显示当前的目录
mkdir XX
创建一个空目录,XX指目录名
cat XX
查看XX文件内容
git --version
查看git版本信息
撤销修改
git reset --hard HEAD^
git reset --hard HEAD~
回退到上一个版本
如果想回退到100个版本,使用git reset –hard HEAD~100
HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令
git reset --hard commit_id
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD
,就回到了场景1,第二步按场景1操作。 场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
在被 git 管理的目录中删除文件时,可以选择如下两种方式来记录删除动作:
- rm + git commit -am "abc"
- git rm + git commit -m "abc"
编辑冲突
<<<<<<< HEAD
=======
>>>>>>> iss53
可以看到 ======= 隔开的上半部分,是 HEAD(即 master 分支,在运行 merge 命令时所切换到的分支)中的内容,下半部分是在 iss53 分支中的内容。解决冲突的办法无非是二者选其一或者由你亲自整合到一起。比如你可以通过把这段内容替换为下面这样来解决:
这个解决方案各采纳了两个分支中的一部分内容,而且我还删除了 <<<<<<<,======= 和 >>>>>>> 这些行。在解决了所有文件里的所有冲突后,运行 git add 将把它们标记为已解决状态(译注:实际上就是来一次快照保存到暂存区域。)。因为一旦暂存,就表示冲突已经解决。
git stash
Git提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作.
基础命令:
do some work
$git stash pop
Git常见问题
Fast-Forward
bugfix分支是从master分支分叉出来的。
合并 bugfix分支到master分支时,如果master分支的状态没有被更改过,那么这个合并是非常简单的。 bugfix分支的历史记录包含master分支所有的历史记录,所以通过把master分支的位置移动到bugfix的最新分支上,Git 就会合并。这样的合并被称为fast-forward(快进)合并。
说明GIT合并的两种方法以及区别。
答:Git代码合并有两种:Git Merge 和 Git ReBase
Git Merge:这种合并方式是将两个分支的历史合并到一起,现在的分支不会被更改,它会比对双方不同的文件缓存下来,生成一个commit,去push。
Git ReBase:这种合并方法通常被称为“衍合”。他是提交修改历史,比对双方的commit,然后找出不同的去缓存,然后去push,修改commit历史。
merge和rebase区别
如何查看文件的提交历史和分支的提交历史。
答:使用git log查看文件提交历史
Git log filename
使用git log查看分支提交历史
Git log branch file
当GIT出现如下情况时,该如何处理?
your-branch-is-ahead-of-origin-master-by-3-commits
答:
git commit -> git pull -> git push
提交代码注意事项
在提交项目之前必须先对项目进行更新,此项特别重要,如果不进行更新,别人有项目提交到服务器上,那么你的项目将会提交不上去,使用git解决冲突会比较麻烦,即使你解决了冲突,但是有时候不注意会冲掉别人写的代码,不像svn使用那么简单,所以提交自己项目前必须进行更新(特别重要);
git reset和git revert区别
git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。
git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。
git log和git reflog区别
- git log 命令可以显示所有提交过的版本信息
- git reflog 可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)
最佳实践
1. pull first
在修改代码之前,记得先执行git pull,把别人push的代码合并过来,这样可以避免一些无谓的冲突。
2. 小粒度commit,大粒度push
Commit的粒度要尽量适当的小,这对于cherry-pic或者代码回滚都非常有益。往远程push本地的提交的时候,粒度要尽量适当大些。这样其他的开发就不用频繁地去pull代码,同时代码回滚也非常方便。已经push到远程的提交,很多会影响提交历史的回滚操作都是不能进行的。比如,git reset,git commit -amend等等,否则会造成灾难。