转自:http://stormzhang.com
详见:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Git.md
Git配置
git config --global user.name "storm"
git config --global user.email "[email protected]"
git config --global color.ui true
git config --global alias.co checkout # 别名
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
git config --global core.editor "vim" # 设置Editor使用vim
git config --global core.quotepath false # 设置显示中文文件名
用户的git配置文件~/.gitconfig
Git常用命令
查看、添加、提交、删除、找回,重置修改文件
git help # 显示command的help
git show # 显示某次提交的内容
git show $id
git co -- # 抛弃工作区修改
git co . # 抛弃工作区修改
git add # 将工作文件修改提交到本地暂存区
git add . # 将所有修改过的工作文件提交暂存区
git rm # 从版本库中删除文件
git rm --cached # 从版本库中删除文件,但不删除文件
git reset # 从暂存区恢复到工作文件
git reset -- . # 从暂存区恢复到工作文件
git reset --hard # 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改
git ci
git ci .
git ci -a # 将git add, git rm和git ci等操作都合并在一起做
git ci -am "some comments"
git ci --amend # 修改最后一次提交记录
git revert <$id> # 恢复某次提交的状态,恢复动作本身也创建了一次提交对象
git revert HEAD # 恢复最后一次提交的状态
查看文件diff
git diff # 比较当前文件和暂存区文件差异
git diff
git diff <$id1> <$id2> # 比较两次提交之间的差异
git diff .. # 在两个分支之间比较
git diff --staged # 比较暂存区和版本库差异
git diff --cached # 比较暂存区和版本库差异
git diff --stat # 仅仅比较统计信息
查看提交记录
git log
git log # 查看该文件每次提交记录
git log -p # 查看每次详细修改内容的diff
git log -p -2 # 查看最近两次详细
tig
Mac上可以使用tig代替diff和log,brew install tig
Git 本地分支管理
查看、切换、创建和删除分支
git br -r # 查看远程分支
git br # 创建新的分支
git br -v # 查看各个分支最后提交信息
git br --merged # 查看已经被合并到当前分支的分支
git br --no-merged # 查看尚未被合并到当前分支的分支
git co # 切换到某个分支
git co -b # 创建新的分支,并且切换过去
git co -b # 基于branch创建新的new_branch
git co $id # 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除
git co $id -b # 把某次历史提交记录checkout出来,创建成一个分支
git br -d # 删除某个分支
git br -D # 强制删除某个分支 (未被合并的分支被删除的时候需要强制)
分支合并和rebase
git merge # 将branch分支合并到当前分支
git merge origin/master --no-ff # 不要Fast-Foward合并,这样可以生成merge提交
git rebase master # 将master rebase到branch,相当于:
git co && git rebase master && git co master && git merge
Git补丁管理(方便在多台机器上开发同步时用)
git diff > ../sync.patch # 生成补丁
git apply ../sync.patch # 打补丁
git apply --check ../sync.patch # 测试补丁能否成功
Git暂存管理
git stash # 暂存
git stash list # 列所有stash
git stash apply # 恢复暂存的内容
git stash drop # 删除暂存区
git stash clear
Git远程分支管理
git pull # 抓取远程仓库所有分支更新并合并到本地
git pull --no-ff # 抓取远程仓库所有分支更新并合并到本地,不要快进合并
git fetch origin # 抓取远程仓库更新
git merge origin/master # 将远程主分支合并到本地当前分支
git co --track origin/branch # 跟踪某个远程分支创建相应的本地分支
git co -b origin/ # 基于远程分支创建本地分支,功能同上
git push # push所有分支
git push origin master # 将本地主分支推到远程主分支
git push -u origin master # 将本地主分支推到远程(如无远程主分支则创建,用于初始化远程仓库)
git push origin # 创建远程分支, origin是远程仓库名
git push origin : # 创建远程分支
git push origin : #先删除本地分支(git br -d ),然后再push删除远程分支
Git远程仓库管理
git remote -v # 查看远程服务器地址和仓库名称
git remote show origin # 查看远程服务器仓库状态
git remote add origin git@github:stormzhang/demo.git # 添加远程仓库地址
git remote set-url origin git@github.com:stormzhang/demo.git # 设置远程仓库地址(用于修改远程仓库地址
创建远程仓库
git clone --bare robbin_site robbin_site.git # 用带版本的项目创建纯版本仓库
scp -r my_project.git git@git.csdn.net:~ # 将纯仓库上传到服务器上
mkdir robbin_site.git && cd robbin_site.git && git --bare init # 在服务器创建纯仓库
git remote add origin git@github.com:robbin/robbin_site.git # 设置远程仓库地址
git push -u origin master # 客户端首次提交
git push -u origin develop # 首次将本地develop分支提交到远程develop分支,并且track
git remote set-head origin master # 设置远程仓库的HEAD指向master分支
也可以命令设置跟踪远程库和本地库
git branch --set-upstream master origin/master
git branch --set-upstream develop origin/develop
Git 所有的操作命令开头都要以 git 开头
在进行任何 Git 操作之前,都要先切换到 Git 仓库目录,也就是要先切换到项目的文件夹目录下。
mkdir test (创建文件夹test)
cd test (切换到test目录)
touch a.md (新建a.md文件)
git status(查看Git仓库状态)
git init(初始化 git 仓库)
当前仓库默认就直接在 master 分支
git add a.md (将a.md 文件添加到缓冲区,等待提交)
git rm –cached a.md (将 a.md 文件移除缓冲区)
git commit -m ‘first commit’ (将缓冲区文件提交到本地仓库,-m 代表是提交信息)
git log (查看所有产生的 commit 记录)
git branch (查看当前分支情况)
git branch a (就新建了一个名字叫 a 的分支,这时候分支 a 跟分支 master 是一模一样的内容)
git checkout a (切换到 a 分支)
那有人就说了,我要先新建再切换,未免有点麻烦,有没有一步到位的:
git checkout -b a (新建一个a分支,并且自动切换到a分支)
git merge
A同学在a分支代码写的不亦乐乎,终于他的功能完工了,并且测试也都ok了,准备要上线了,这个时候就需要把他的代码合并到主分支master上来,然后发布。git merge 就是合并分支用到的命令,针对这个情况,需要先做两步,第一步是切换到 master 分支,如果你已经在了就不用切换了,第二步执行 git merge a ,意思就是把a分支的代码合并过来,不出意外,这个时候a分支的代码就顺利合并到 master 分支来了。为什么说不出意外呢?因为这个时候可能会有冲突而合并失败,留个包袱,这个到后面进阶的时候再讲。
git branch -d
有新建分支,那肯定有删除分支,假如这个分支新建错了,或者a分支的代码已经顺利合并到 master 分支来了,那么a分支没用了,需要删除,这个时候执行 git branch -d a 就可以把a分支删除了。
git branch -D
有些时候可能会删除失败,比如如果a分支的代码还没有合并到master,你执行 git branch -d a 是删除不了的,它会智能的提示你a分支还有未合并的代码,但是如果你非要删除,那就执行 git branch -D a 就可以强制删除a分支。
git tag
我们在客户端开发的时候经常有版本的概念,比如v1.0、v1.1之类的,不同的版本肯定对应不同的代码,所以我一般要给我们的代码加上标签,这样假设v1.1版本出了一个新bug,但是又不晓得v1.0是不是有这个bug,有了标签就可以顺利切换到v1.0的代码,重新打个包测试了。所以如果想要新建一个标签很简单,比如 git tag v1.0 就代表我在当前代码状态下新建了一个v1.0的标签,输入 git tag 可以查看历史 tag 记录。
想要切换到某个tag怎么办?也很简单,执行 git checkout v1.0 ,这样就顺利的切换到 v1.0 tag的代码状态了。
生成SSH key
SSH是一种网络协议,用于计算机之间的加密登录。
ssh -keygen -t rsa
指定 rsa 算法生成密钥,接着连续三个回车键(不需要输入密码),然后就会生成两个文件 id_rsa 和 id_rsa.pub ,而 id_rsa 是密钥,id_rsa.pub 就是公钥。这两文件默认分别在如下目录里生成:Linux/Mac 系统 在 ~/.ssh 下,win系统在 /c/Documents and Settings/username/.ssh 下,都是隐藏文件
接下来要做的是把 id_rsa.pub 的内容添加到 GitHub 上,这样你本地的 id_rsa 密钥跟 GitHub 上的 id_rsa.pub 公钥进行配对,授权成功才可以提交代码。
在 GitHub 上的设置页面,点击最左侧 SSH and GPG keys :New SSH key 按钮:在 Key 那栏把 id_rsa.pub 公钥文件里的内容复制粘贴进去就可以了
SSH key 添加成功之后,输入 ssh -T [email protected] 进行测试
Push & Pull
这两个命令需要跟远程仓库配合
Push :直译过来就是「推」的意思,如果你本地代码有更新了,那么就需要把本地代码推到远程仓库,这样本地仓库跟远程仓库就可以保持同步了。
代码示例: git push origin master
意思就是把本地代码推到远程 master 分支。
Pull:直译过来就是「拉」的意思,如果别人提交代码到远程仓库,这个时候你需要把远程仓库的最新代码拉下来,然后保证两端代码的同步。
代码示例: git pull origin master
意思就是把远程最新的代码更新到本地。一般我们在 push 之前都会先 pull ,这样不容易冲突。
提交代码
提交代码有两种方法:
Clone自己的项目 我们以我在 GitHub 上创建的 test 项目为例,执行如下命令:
git clone [email protected]:stormzhang/test.git
这样就把 test 项目 clone 到了本地,你可以把 clone 命令理解为高级点的复制,这个时候该项目本身就已经是一个git 仓库了,不需要执行 git init 进行初始化,而且甚至都已经关联好了远程仓库,我们只需要在这个 test 目录下任意修改或者添加文件,然后进行 commit ,之后就可以执行:
git push origin master
进行代码提交,这种是最简单方便的一种方式。
至于怎么获取项目的仓库地址呢?如下图:
关联本地已有项目 如果我们本地已经有一个完整的 git 仓库,并且已经进行了很多次 commit ,这个时候第一种方法就不适合了。
假设我们本地有个 test2 的项目,我们需要的是在 GitHub 上建一个 test 的项目,然后把本地 test2 上的所有代码 commit 记录提交到 GitHub 上的 test 项目。
第一步就是在 GitHub 上建一个 test 项目,这个想必大家都会了,就不用多讲了。
第二步把本地 test2 项目与 GitHub 上的 test 项目进行关联,切换到 test2 目录,执行如下命令:
git remote add origin [email protected]:stormzhang/test.git
就是添加一个远程仓库,他的地址是 [email protected]:stormzhang/test.git ,而 origin 是给这个项目的远程仓库起的名字,是的,名字你可以随便取,只不过大家公认的只有一个远程仓库时名字就是 origin ,为什么要给远程仓库取名字?因为我们可能一个项目有多个远程仓库?比如 GitHub 一个,比如公司一个,这样的话提交到不同的远程仓库就需要指定不同的仓库名字了。
查看我们当前项目有哪些远程仓库可以执行如下命令:
git remote -v
接下来,我们本地的仓库就可以向远程仓库进行代码提交了:
git push origin master
就是默认向 GitHub 上的 test 目录提交了代码,而这个代码是在 master 分支。当然你可以提交到指定的分支,这个之后的文章再详细讲解。
友情提醒,在提交代码之前先要设置下自己的用户名与邮箱,这些信息会出现在所有的 commit 记录里,执行以下代码就可以设置:
git config —global user.name “stormzhang”
git config —global user.email “[email protected]”
以上进行了全局配置,当然有些时候我们的某一个项目想要用特定的邮箱,这个时候只需切换到你的项目,以上代码把 –global 参数去除,再重新执行一遍就ok了
alias
为命令设置别名
git config --global alias.co checkout # 别名
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
当然以上别名不是固定的,你完全可以根据自己的习惯去定制,除此之外还可以设置组合,比如:
git config --global alias.psm 'push origin master'
git config --global alias.plm 'pull origin master'
之后经常用到的git push origin master 和 git pull origin master 直接就用 git psm 和 git plm 代替了
一个很强大的 alias 命令
输入git log –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit –date=relative
是不是比较清晰,整个分支的走向也很明确,使用alias命令设置别名
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
这样以后直接输入 git lg 就行了。
其他配置
默认情况下 git 用的编辑器是 vi,将其改为vim
git config --global core.editor "vim" # 设置Editor使用vim
开启给 Git 着色
git config --global color.ui true
设置显示中文文件名
git config --global core.quotepath false # 设置显示中文文件名
默认这些配置都在 ~/.gitconfig 文件下
diff
直接输入 git diff 只能比较当前文件和暂存区文件差异,什么是暂存区?就是你还没有执行 git add 的文件。
具体用法如下:
git diff <$id1> <$id2> # 比较两次提交之间的差异
git diff .. # 在两个分支之间比较
git diff --staged # 比较暂存区和版本库差异
checkout
checkout 不只用作切换分支,他可以用来切换tag,切换到某次commit,如:
git checkout v1.0
git checkout ffd9f2dd68f1eb21d36cee50dbdd504e95d9c8f7 # 后面的一长串是commit_id,是每次commit的SHA1值,可以根据 git log 看到。
除了有“切换”的意思,checkout 还有一个撤销的作用,举个例子,假设我们在一个分支开发一个小功能,刚写完一半,这时候需求变了,而且是大变化,之前写的代码完全用不了了,好在你刚写,甚至都没有 git add 进暂存区,这个时候很简单的一个操作就直接把原文件还原:
git checkout a.md
checkout 命令只能撤销还没有 add 进暂存区的文件
stash
设想一个场景,假设我们正在一个新的分支做新的功能,这个时候突然有一个紧急的bug需要修复,而且修复完之后需要立即发布。当然你说我先把刚写的一点代码进行提交不就行了么?这样理论上当然是ok的,但是这会产品垃圾commit,原则上我们每次的commit都要有实际的意义,你的代码只是刚写了一半,还没有什么实际的意义是不建议就这样commit的,那么有没有一种比较好的办法,可以让我暂时切到别的分支,修复完bug再切回来,而且代码也能保留的呢?
这个时候 stash 命令就大有用处了,前提是我们的代码没有进行 commit ,哪怕你执行了 add 也没关系,我们先执行
git stash
命令,什么意思呢?意思就是把当前分支所有没有 commit 的代码先暂存起来,这个时候你再执行 git status 你会发现当前分支很干净,几乎看不到任何改动,你的代码改动也看不见了,但其实是暂存起来了。执行
git stash list
你会发现此时暂存区已经有了一条记录。
这个时候你可以切换会其他分支,赶紧把bug修复好,然后发布。之后一切都解决了,你再切换回来继续做你之前没做完的功能,但是之前的代码怎么还原呢?
git stash apply
你会发现你之前的代码全部又回来了,就好像一切都没发生过一样,紧接着你最好需要把暂存区的这次 stash 记录删除,执行:
git stash drop
其实还有更方便的,你可以使用:
git stash pop
来代替 apply 命令,pop 跟 apply 的唯一区别就是 pop 不但会帮你把代码还原,还自动帮你把这条 stash 记录删除,省的自己再 drop 一次了
git stash clear
就是清空所有暂存区的记录,drop 是只删除一条,当然后面可以跟 stash_id 参数来删除指定的某条记录,不跟参数就是删除最近的,而 clear 是清空。
merge & rebase
我们知道 merge 分支是合并的意思,我们在一个 featureA 分支开发完了一个功能,这个时候需要合并到主分支 master 上去,我们只需要进行如下操作:
git checkout master
git merge featureA
其实 rebase 命令也是合并的意思,上面的需求我们一样可以如下操作:
git checkout master
git rebase featureA
rebase 跟 merge 的区别你们可以理解成有两个书架,你需要把两个书架的书整理到一起去,第一种做法是 merge ,比较粗鲁暴力,就直接腾出一块地方把另一个书架的书全部放进去,虽然暴力,但是这种做法你可以知道哪些书是来自另一个书架的;第二种做法就是 rebase ,他会把两个书架的书先进行比较,按照购书的时间来给他重新排序,然后重新放置好,这样做的好处就是合并之后的书架看起来很有逻辑,但是你很难清晰的知道哪些书来自哪个书架的。
只能说各有好处的,不同的团队根据不同的需要以及不同的习惯来选择就好。
新建一个叫 develop 的分支
git branch develop
即以上是基于 mater 分支新建了一个叫做 develop 的分支,此时 develop 分支跟 master 分支的内容完全一样
切换到 develop 分支
git checkout develop
如果把以上两步合并,即新建并且自动切换到 develop 分支:
git checkout -b develop
把 develop 分支推送到远程仓库
git push origin develop
如果你远程的分支想取名叫 develop2 ,那执行以下代码:
git push origin develop:develop2
但是强烈不建议这样,这会导致很混乱,很难管理,所以建议本地分支跟远程分支名要保持一致。
查看本地分支列表
git branch
查看远程分支列表
git branch -r
删除本地分支
git branch -d develop
git branch -D develop (强制删除)
删除远程分支
git push origin :develop
如果远程分支有个 develop ,而本地没有,你想把远程的 develop 分支迁到本地:
git branch develop origin/develop
同样的把远程分支迁到本地顺便切换到该分支:
git checkout -b develop origin/develop
Git Flow
分支管理流程
http://stormzhang.com/git/2014/01/29/git-flow/
搭建Git服务器在远程仓库
搭建Git服务器在远程仓库一节中,我们讲了远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改。
GitHub就是一个免费托管开源代码的远程仓库。但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给GitHub交保护费,那就只能自己搭建一台Git服务器作为私有仓库使用。
搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,通过几条简单的apt命令就可以完成安装。
假设你已经有sudo权限的用户账号,下面,正式开始安装。
第一步,安装git:
$ sudo apt-get install git
第二步,创建一个git用户,用来运行git服务:
$ sudo adduser git
第三步,创建证书登录:
收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。
第四步,初始化Git仓库:
先选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令:
$ sudo git init –bare sample.git
Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾。
然后,把owner改为git:
$ sudo chown -R git:git sample.git
第五步,禁用shell登录:
出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改为:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。
第六步,克隆远程仓库:
现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:
$ git clone git@server:/srv/sample.git
Cloning into ‘sample’…
warning: You appear to have cloned an empty repository.
剩下的推送就简单了。
管理公钥
如果团队很小,把每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件里就是可行的。
如果团队有几百号人,就没法这么玩了,这时,可以用Gitosis来管理公钥。
这里我们不介绍怎么玩Gitosis了,几百号人的团队基本都在500强了,相信找个高水平的Linux管理员问题不大。
管理权限
有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。
因为Git是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。不过,因为Git支持钩子(hook),所以,可以在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。
Gitolite就是这个工具。
这里我们也不介绍Gitolite了,不要把有限的生命浪费到权限斗争中。
其他GIT教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000