新建代码库
在当前目录新建一个Git代码库 $ git init 新建一个目录,将其初始化为Git代码库 $ git init [project-name] 下载一个项目和它的整个代码历史 $ git clone [url]
配置
Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。
显示当前的Git配置 $ git config --list 编辑Git配置文件 $ git config -e [--global] 设置提交代码时的用户信息 $ git config [--global] user.name "[name]" $ git config [--global] user.email "[email address]" 配置使用git仓库的人员姓名 配置使用git仓库的人员email git config --global user.name "weihainna" git config --global user.email "weihainanmail@126.com" 配置到缓存 默认15分钟 git config --global credential.helper cache 修改缓存时间 git config --global credential.helper 'cache --timeout=3600' 配置命令行颜色 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 "mate -w" 设置Editor使用textmate git config -1 列举所有配置 配置中文 /etc/inputrc disable/enable 8 bit input set meta-flag on set input-meta on set output-meta on set convert-meta on /etc/profile declare -x LESSCHARSET=utf-8
基本操作
添加 git add <file> 将工作文件修改提交到本地暂存区 git add .将所有修改过的工作文件提交暂存区 添加指定文件到暂存区 $ git add [file1] [file2] ... 添加指定目录到暂存区,包括子目录 $ git add [dir] 添加当前目录的所有文件到暂存区 $ git add . 添加每个变化前,都会要求确认 对于同一个文件的多处变化,可以实现分次提交 $ git add -p 提交 commit git ci <file> git ci . git ci -a将git add, git rm和git ci等操作都合并在一起做 git ci -am "some comments" git ci --amend 修改最后一次提交记录 提交暂存区到仓库区 $ git commit -m [message] 提交你的修改 git commit –m "你的注释" 提交暂存区的指定文件到仓库区 $ 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] ... 修改--add--暂存区--commit--本地库 每次修改如果不add就不会加入暂存区,commit时就不会提交 删除工作区文件,并且将这次删除放入暂存区 $ git rm [file1] [file2] ... 停止追踪指定文件,但该文件会保留在工作区 $ git rm --cached [file] git rm <file>从版本库中删除文件 git rm <file> --cached 从版本库中删除文件,但不删除文件 从当前跟踪列表移除文件,并完全删除 git rm readme.txt 仅在暂存区删除,保留文件在当前目录,不再跟踪 git rm –cached readme.txt 假设你已经使用git add .,将修改过的文件a、b加到暂存区 现在你只想提交a文件,不想提交b文件,应该这样 git reset HEAD b 改名文件,并且将这个改名放入暂存区 $ git mv [file-original] [file-renamed] 查看文件状态 git status 比较工作区 缓存区 版本库 git statys -s M test.txt --第一个M表示暂存区与版本库不一样 --第二个M表示暂存区与工作空间不一样 取消对文件的修改 git checkout -- readme.txt 退回到最近一次add或commit的状态 直接丢弃工作区的修改 无论修改还是删除 都可以一键还原
比较 日志
git diff git diff HEAD -- readme.txt 工作区与版本库差别 git diff --staged 暂存区和版本库中的差异 --git diff 工作空间与暂存区比较 --git diff HEAD 工作区和HEAD比较 git diff HEAD -- readme.txt 查看版本库与临时区文件区别 --git diff --cached 暂存区与HEAD比较 显示暂存区和工作区的差异 $ git diff 显示暂存区和上一个commit的差异 $ git diff --cached [file] 显示工作区与当前分支最新commit之间的差异 $ git diff HEAD 显示两次提交之间的差异 $ git diff [first-branch]...[second-branch] 显示今天你写了多少行代码 $ git diff --shortstat "@{0 day ago}" git diff <file> 比较当前文件和暂存区文件差异 git diff git diff <$id1> <$id2>比较两次提交之间的差异 git diff <branch1>..<branch2> 在两个分支之间比较 git diff --staged比较暂存区和版本库差异 git diff --cached比较暂存区和版本库差异 git diff --stat 仅仅比较统计信息 git log git log --pretty=oneline git log --pretty=oneline --abbrev-commit 查看提交记录 git log <file> 查看该文件每次提交记录 git log -p <file>查看每次详细修改内容的diff git log -p -2查看最近两次详细修改内容的diff git log --stat 查看提交统计信息 git log 查看提交日志 git log -pretty=oneline 显示当前分支的版本历史 $ git log $ git log --pretty=oneline 显示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 shortlog -sn 显示指定文件是什么人在什么时间修改过 $ git blame [file] 显示某次提交的元数据和内容变化 $ git show [commit] 显示某次提交发生变化的文件 $ git show --name-only [commit] 显示某次提交时,某个文件的内容 $ git show [commit]:[filename] 显示当前分支的最近几次提交 $ git reflog git reflog 查看命令的执行日志 Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作: $ git stash 用git stash list命令看看“储藏”的工作现场: $ git stash list 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除; 另一种方式是用git stash pop,恢复的同时把stash内容也删了: $ git stash pop 暂时将未提交的变化移除,稍后再移入 $ git stash $ git stash pop Git暂存管理 git stash 暂存 git stash list列所有stash git stash apply 恢复暂存的内容 git stash drop删除暂存区
撤销 回退
恢复暂存区的指定文件到工作区 $ 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 reset --hard HEAD^ git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区 上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。 git reset --hard 3628164 git reflog git reset --hard master@{1} 回退: 场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。 git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。 场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时, 想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。 git checkout -- file git reset HEAD file 场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。 $ git log --pretty=oneline$ git reflog $ git reset --hard HEAD^ $ git reset --hard 3628164 上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。 HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。 git reset <file> 从暂存区恢复到工作文件 git reset -- . 从暂存区恢复到工作文件 git reset --hard 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改 git reset --hard HEAD^ git reset --hard HEAD^^ git reset --hard HEAD~100 git reset --hard 3628164 git revert <$id> 恢复某次提交的状态,恢复动作本身也创建了一次提交对象 git revert HEAD 恢复最后一次提交的状态 git co -- <file>抛弃工作区修改 git co .抛弃工作区修改
仓库
取得Git仓库 初始化一个版本仓库 git init Clone远程版本库 git clone git@xbc.me:wordpress.git $ git clone https://github.com/whnhub/learngit.git 添加远程版本库origin,语法为 git remote add [shortname] [url] git remote add origin git@xbc.me:wordpress.git 查看远程仓库 git remote -v git remote -v 查看远程服务器地址和仓库名称 git remote show origin查看远程服务器仓库状态 git remote add origin git@ github:robbin/robbin_site.git 添加远程仓库地址 git remote set-url origin git@ github.com:robbin/robbin_site.git 设置远程仓库地址(用于修改远程仓库地址) git remote rm <repository>删除远程仓库 下载远程仓库的所有变动 $ 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 当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。 要查看远程库的信息,用git remote: $ git remote origin 或者,用git remote -v显示更详细的信息: $ git remote -v origin git@github.com:michaelliao/learngit.git (fetch) origin git@github.com:michaelliao/learngit.git (push) 上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
分支
查看分支:git branch 创建分支:git branch <name> 切换分支:git checkout <name> 创建+切换分支:git checkout -b <name> 合并某分支到当前分支:git merge <name> $ git merge --no-ff -m "merge with no-ff" dev 删除分支:git branch -d <name> git checkout命令加上-b参数表示创建并切换,相当于以下两条命令: $ git branch dev $ git checkout dev 列出所有本地分支 $ 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] 如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除。 查看、切换、创建和删除分支 git br -r查看远程分支 git br <new_branch> 创建新的分支 git br -v查看各个分支最后提交信息 git br --merged 查看已经被合并到当前分支的分支 git br --no-merged 查看尚未被合并到当前分支的分支 git co <branch> 切换到某个分支 git co -b <new_branch> 创建新的分支,并且切换过去 git co -b <new_branch> <branch> 基于branch创建新的new_branch git co $id 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除 git co $id -b <new_branch> 把某次历史提交记录checkout出来,创建成一个分支 git br -d <branch> 删除某个分支 git br -D <branch> 强制删除某个分支 (未被合并的分支被删除的时候需要强制) 分支合并和rebase git merge <branch>将branch分支合并到当前分支 git merge origin/master --no-ff 不要Fast-Foward合并,这样可以生成merge提交 git rebase master <branch>将master rebase到branch,相当于: git co <branch> && git rebase master && git co master && git merge <branch> 创建一个分支 git branch iss53 切换工作目录到iss53 git chekcout iss53 将上面的命令合在一起,创建iss53分支并切换到iss53 git chekcout –b iss53 合并iss53分支,当前工作目录为master git merge iss53 合并完成后,没有出现冲突,删除iss53分支 git branch –d iss53 拉去远程仓库的数据,语法为 git fetch [remote-name] git fetch fetch 会拉去最新的远程仓库数据,但不会自动到当前目录下,要自动合并 git pull 查看远程仓库的信息 git remote show origin 建立本地的dev分支追踪远程仓库的develop分支 git checkout –b dev origin/develop git pull 抓取远程仓库所有分支更新并合并到本地 git pull --no-ff 抓取远程仓库所有分支更新并合并到本地,不要快进合并 git fetch origin 抓取远程仓库更新 git merge origin/master 将远程主分支合并到本地当前分支 git co --track origin/branch 跟踪某个远程分支创建相应的本地分支 git co -b <local_branch> origin/<remote_branch> 基于远程分支创建本地分支,功能同上 git push push所有分支 git push origin master将本地主分支推到远程主分支 git push -u origin master 将本地主分支推到远程(如无远程主分支则创建,用于初始化远程仓库) git push origin <local_branch>创建远程分支, origin是远程仓库名 git push origin <local_branch>:<remote_branch> 创建远程分支 git push origin :<remote_branch> 先删除本地分支(git br -d <branch>),然后再push删除远程分支 git pull git push git log --graph --pretty=oneline --abbrev-commit
标签
列出所有tag $ git tag 新建一个tag在当前commit $ git tag [tag] 新建一个tag在指定commit $ git tag [tag] [commit] 删除本地tag $ git tag -d [tag] 删除远程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] 敲命令git tag <name>就可以打一个新标签: $ git tag v1.0 可以用命令git tag查看所有标签: $ git tag v1.0 $ git tag v0.9 6224937
rebase
一、基本
git rebase用于把一个分支的修改合并到当前分支。
假设你现在基于远程分支"origin",创建一个叫"mywork"的分支。
$ git checkout -b mywork origin
假设远程分支"origin"已经有了2个提交,如图
现在我们在这个分支做一些修改,然后生成两个提交(commit).
$ vi file.txt
$ git commit
$ vi otherfile.txt
$ git commit
...
但是与此同时,有些人也在"origin"分支上做了一些修改并且做了提交了. 这就意味着"origin"和"mywork"这两个分支各自"前进"了,它们之间"分叉"了。
在这里,你可以用"pull"命令把"origin"分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的"合并的提交"(merge commit):
但是,如果你想让"mywork"分支历史看起来像没有经过任何合并一样,你也许可以用 git rebase:
$ git checkout mywork
$ git rebase origin
这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时
保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新
为最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。
当'mywork'分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除. (请查看 git gc)
二、解决冲突
在rebase的过程中,也许会出现冲突(conflict).
在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用"git-add"命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行:
$ git rebase --continue
这样git会继续应用(apply)余下的补丁。
在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。
$ git rebase --abort
三、git rebase和git merge的区别
现在我们可以看一下用合并(merge)和用rebase所产生的历史的区别:
当我们使用Git log来参看commit时,其commit的顺序也有所不同。
假设C3提交于9:00AM,C5提交于10:00AM,C4提交于11:00AM,C6提交于12:00AM,
对于使用git merge来合并所看到的commit的顺序(从新到旧)是:C7 ,C6,C4,C5,C3,C2,C1
对于使用git rebase来合并所看到的commit的顺序(从新到旧)是:C7 ,C6‘,C5',C4,C3,C2,C1
因为C6'提交只是C6提交的克隆,C5'提交只是C5提交的克隆,
从用户的角度看使用git rebase来合并后所看到的commit的顺序(从新到旧)是:C7 ,C6,C5,C4,C3,C2,C1
表示本地当前本地当前分支上。