GitHub是个git仓库(相当于Git服务器),安装在远程服务器端。 git是一个客户端工具,安装在用户的电脑上,用户通过git命令从GitHub上pull和push数据。
接下来我们就来介绍git的常用指令
重要的 在Git中,用HEAD表示当前版本。 上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。
git我们的工作区有一个.git的文件夹,这是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
创建基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 git init 初始化本地仓库 touch readme.txt 新建文件 git add readme.txt 添加文件到暂存区 git status 掌握仓库当前的状态 git diff 查看修改 暂存区和工作区的代码差异 git diff HEAD 查看工作区和版本库里面最新版本的区别 git commit -m "first comomit" 提交文件到本地仓库,first comomit为备注 git log --pretty=oneline 简单的描述从最近到最远的提交日志 git reset --hard HEAD^ 将提交返回到上一个版本,这是一个head指针的改变 git reflog 记录我的每一次命令,可以查找恢复到最新的版本 // HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。 // 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。 // 要重返未来,用git reflog查看命令历史,以便确定要回到以前的哪个版本。
修改 场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout – file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD ,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。git reset –hard HEAD^
1 2 3 4 git checkout -- readme.txt //把readme.txt文件在工作区的修改全部撤销,就是让这个文件回到最近一次git commit或git add时的状态。 // reset是返回到之前的版本,checkout是把本地的修改撤销 // -- 很重要,不然是切换至另一个分支的命令 git reset HEAD <file> //把暂存区的修改撤销掉(unstage),重新放回工作区
删除 1 2 3 4 5 rm test.txt //删了文件 git rm test.txt + git commit //告诉git,从版本库中删除该文件 git checkout -- test.txt //还没有上传版本库,直接恢复
远程仓库 Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。 由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置: 第1步:创建SSH Key。GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
1 2 3 4 5 6 7 git remote add origin git@git.yongche.org:mooory/git-test.git 在本地仓库添加一个远程仓库。 git push 或者 git push -u origin master //提交文件到远程仓库, 第一次加上-u参数, // Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来, // 在以后的推送或者拉取时就可以简化命令。 git push origin master 把本地master分支的最新修改推送至GitHub
克隆 1 git clone git@github.com:mooory/git-test.git
分支管理 HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。 开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点 当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上 不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变
1 2 3 4 5 6 7 git checkout -b dev 创建dev分支,然后切换到dev分支,相当于以下两条命令 = git branch dev + git checkout dev git branch 查看当前所有分支 git merge dev 把dev分支的工作成果合并到master分支上 git branch -d dev 删除dev分支
解决冲突:当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。 合并分支时,一般Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。 如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
1 2 git merge --no-ff -m "merge with no-ff" dev //--no-ff参数,表示禁用Fast forward //因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
解决bug分支 当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交。 并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
1 2 3 4 5 git stash //将当前工作现场储藏,工作环境就是干净的了 git stash list // 查看我们存储的环境 git stash apply stash@{0}
恢复: 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除; 另一种方式是用git stash pop,恢复的同时把stash内容也删了
分支不合并 如果分支不合并就要被删除,会提示错误1 2 3 4 5 6 7 8 $ git branch -d feature-vulcan error: The branch 'feature-vulcan' is not fully merged. If you are sure you want to delete it, run 'git branch -D feature-vulcan'. 如果要强行删除,需要使用大写的-D参数 git branch -D feature-vulcan Deleted branch feature-vulcan (was 287773e).
多人协作 推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上 并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。 现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:1 git checkout -b dev origin/dev
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程。
当有冲突时,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送1 2 3 4 5 6 7 8 9 10 $ git pullThere is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details. git pull <remote> <branch> If you wish to set tracking information for this branch you can do so with: git branch --set-upstream-to=origin/<branch> dev
git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接
1 git branch --set-upstream-to=origin/dev dev
再进行pull。再解决冲突。
新建代码库 remote:远程
repository :仓库
checkout:检出
1 2 3 4 5 6 7 8 # 在当前目录新建一个Git代码库$ git init# 新建一个目录,将其初始化为Git代码库$ git init [project-name]# 下载一个项目和它的整个代码历史$ git clone [url]
配置 Git的设置文件为.gitconfig1 2 3 4 5 6 7 8 9 # 显示当前的Git配置$ git config --list# 编辑Git配置文件$ git config -e [--global]# 设置提交代码时的用户信息$ git config [--global] user.name "[name]"$ git config [--global] user.email "[email address]"
增删文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # 添加指定文件到暂存区$ git add [file1] [file2] ...# 添加指定目录到暂存区,包括子目录$ git add [dir]# 添加当前目录的所有文件到暂存区$ git add .# 添加每个变化前,都会要求确认# 对于同一个文件的多处变化,可以实现分次提交$ git add -p# 删除工作区文件,并且将这次删除放入暂存区$ git rm [file1] [file2] ...# 停止追踪指定文件,但该文件会保留在工作区$ git rm --cached [file]# 改名文件,并且将这个改名放入暂存区$ git mv [file-original] [file-renamed]
提交 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 提交暂存区到仓库区$ git commit -m [message] //重要# 提交暂存区的指定文件到仓库区$ git commit [file1] [file2] ... -m [message]# 提交工作区自上次commit之后的变化,直接到仓库区$ git commit -a# 提交时显示所有diff信息$ git commit -v# 使用一次新的commit,替代上一次提交# 如果代码没有任何新变化,则用来改写上一次commit的提交信息$ git commit --amend -m [message]# 重做上一次commit,并包括指定文件的新变化$ git commit --amend [file1] [file2] ...
分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 # 列出所有本地分支$ git branch# 列出所有远程分支$ git branch -r# 列出所有本地分支和远程分支$ git branch -a# 新建一个分支,但依然停留在当前分支$ git branch [branch-name]# 新建一个分支,并切换到该分支$ git checkout -b [branch]# 新建一个分支,指向指定commit$ git branch [branch] [commit]# 新建一个分支,与指定的远程分支建立追踪关系$ git branch --track [branch] [remote-branch]# 切换到指定分支,并更新工作区$ git checkout [branch-name]# 切换到上一个分支$ git checkout -# 建立追踪关系,在现有分支与指定的远程分支之间$ git branch --set-upstream [branch] [remote-branch]# 合并指定分支到当前分支$ git merge [branch]# 选择一个commit,合并进当前分支$ git cherry-pick [commit]# 删除分支$ git branch -d [branch-name]# 删除远程分支$ git push origin --delete [branch-name]$ git branch -dr [remote/branch]
查看 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 显示有变更的文件$ git status# 显示当前分支的版本历史$ git log# 显示commit历史,以及每次commit发生变更的文件$ git log --stat# 搜索提交历史,根据关键词$ git log -S [keyword]# 显示某个commit之后的所有变动,每个commit占据一行$ git log [tag] HEAD --pretty=format:%s# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件$ git log [tag] HEAD --grep feature# 显示某个文件的版本历史,包括文件改名$ git log --follow [file]$ git whatchanged [file]# 显示指定文件相关的每一次diff$ git log -p [file]# 显示过去5次提交$ git log -5 --pretty --oneline# 显示所有提交过的用户,按提交次数排序$ git shortlog -sn# 显示指定文件是什么人在什么时间修改过$ git blame [file]# 显示暂存区和工作区的代码差异$ git diff // 重要# 显示暂存区和上一个commit的差异$ git diff --cached [file]# 显示工作区与当前分支最新commit之间的差异$ git diff HEAD# 显示两次提交之间的差异$ git diff [first-branch]...[second-branch]# 显示今天你写了多少行代码$ git diff --shortstat "@{0 day ago}"# 显示某次提交的元数据和内容变化$ git show [commit]# 显示某次提交发生变化的文件$ git show --name-only [commit]# 显示某次提交时,某个文件的内容$ git show [commit]:[filename]# 显示当前分支的最近几次提交$ git reflog# 从本地master拉取代码更新当前分支:branch 一般为master$ git rebase [branch]
同步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ git remote update --更新远程仓储# 下载远程仓库的所有变动$ git fetch [remote]# 显示所有远程仓库$ git remote -v# 显示某个远程仓库的信息$ git remote show [remote]# 增加一个新的远程仓库,并命名$ git remote add [shortname] [url]# 取回远程仓库的变化,并与本地分支合并$ git pull [remote] [branch]# 上传本地指定分支到远程仓库$ git push [remote] [branch]# 强行推送当前分支到远程仓库,即使有冲突$ git push [remote] --force# 推送所有分支到远程仓库$ git push [remote] --all
撤销 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # 恢复暂存区的指定文件到工作区$ git checkout [file]# 恢复某个commit的指定文件到暂存区和工作区$ git checkout [commit] [file]# 恢复暂存区的所有文件到工作区$ git checkout .# 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变$ git reset [file]# 重置暂存区与工作区,与上一次commit保持一致$ git reset --hard //重要# 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变$ git reset [commit]# 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致$ git reset --hard [commit]# 重置当前HEAD为指定commit,但保持暂存区和工作区不变$ git reset --keep [commit]# 新建一个commit,用来撤销指定commit# 后者的所有变化都将被前者抵消,并且应用到当前分支$ git revert [commit]# 暂时将未提交的变化移除,稍后再移入$ git stash // 重要$ git stash pop
其他 1 2 # 生成一个可供发布的压缩包$ git archive