git
Git支持多种协议,包括https,默认的git://使用ssh,但也可以使用https等其他协议。但通过ssh支持的原生git协议速度最快。
远程库
$ git init --bare [repertory's name].git
分支
- master分支是主分支,因此要时刻与远程同步;
- dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch –set-upstream branch-name origin/branch-name。
配置
# 生成rsa
$ ssh-keygen -t rsa
$ git config --global user.name "xxx"
$ git config --global user.email "xxx@xx.com"
# 写配置
$ git config --global -e
# 查看
$ git config -l
# 配置msg编辑器
$ git config --global core.editor vim
# 获取当前.git 目录路径
$ git rev-parse --git-dir
# 设置短命令
$ git config --global alias.ci "commit -a -v"
submodule
$ git submodule add -b master --name test -- https://github.com/doudounannan/create-web-app.git src/submodules/test
好用工具
tig
命令
$ brew install tig
使用
$ tig
命令
# commit
# 查看diff提交
$ git commit -verbose
# 不需要git add 直接commit
$ git commit -a
# diff
# 工作区与本地库的区别
$ git diff <file>
# 暂存区与本地库的区别
$ git diff --cached
# 工作区与本地库的区别
$ git diff HEAD
# log
$ git log
# 查看第一次提交
$ git log --reverse
# log具体提交内容
$ git log -p
# log按照行显示
$ git log --oneline --graph --decorate
# 或者$ git log --pretty=oneline --graph --decorate
# 除了 git log 信息之外,包含哪些文件被更改了,以及每个文件相对的增删行数。
$ git log --stat
# 显示代表每个提交的一堆信息。显示每个提交全部的差异(diff),这也是项目历史中最详细的视图。
$ git log --author="<pattern>"
# 搜索特定作者的提交。<pattern> 可以是字符串或正则表达式。
$ git log --grep="<pattern>"
# clean: clean来删除没有track过的文件
# 提醒哪些文件会被删除
$ git clean -n
# 删除文件
$ git clean -f
# reflog
$ git reflog
# ======== 回滚 ========
# 本地仓库回滚,工作区和暂存区修改文件不存在
$ git reset --hard <commit>
# 本地仓库回滚,修改回到暂存区
$ git reset --soft <commit>
# 暂存区文件撤销,修改回到工作区
$ git reset HEAD <file>
# ----- 追加提交信息 ------
$ git commit --amend
# ----- 丢弃工作区修改 -----
# 丢弃工作区文件的修改,只能丢弃修改,不能删除新加文件
$ git checkout <file>
$ git checkout .
# ====== 删除文件后提交删除 ======
$ git rm <file>
# ====== codereview =====
$ git push origin HEAD:refs/for/master
# ====== 远程仓库 ======
# 查看远程仓库
$ git remote
# 查看远程仓库详细信息
$ git remote -v
# 添加远程库
$ git remote add origin git@github.com:xxx
# 把本地所有内容添加到远程(加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。)
$ git push -u origin master
# 查看某个远程仓库的详细信息
$ git remote show <remote>
# 修改某个远程仓库在本地的简称
$ git remote rename <oldshortname> <newshortname>
# 移除远程仓库
$ git remote rm <shortname>
# ====== 分支 ======
# 获取当前分支
$ git branch | sed -n '/\*/s///p
# 查看远程分支
$ git branch -a
# 复制分支
$ git clone -b <branch> <remote-repository>
# 创建新分支并立即切换到新分支
$ git checkout -b <branch>
# 切换分支
$ git checkout <branch>
# 新分支创建后不会自动切换为当前分支
$ git branch <branch>
# 修改分支名称
$ git branch -m <old-branch> <new-branch>
# 把dev分支的工作成果合并到master分支上
$ git merge <branch>
# 删除dev分支
$ git branch -d <branch>
# 把当前工作现场“储藏”起来,等以后恢复现场后继续工作
$ git stash
# 查看工作现场
$ git stash list
# 用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除
$ git stash apply
$ git stash drop
# 恢复的同时把stash内容也删了
$ git stash pop
# ====== 标签 ======
# 打标签
$ git tag <tag>
# 查看所有标签
$ git tag
# 给对应的commitId打标签
$ git tag <tag> 6224937
# 查看标签信息
$ git show <tag>
# 创建带有说明的标签,用-a指定标签名,-m指定说明文字
$ git tag -a <tag> -m "version 0.1 released" <commit>
# 通过-s用私钥签名一个标签
$ git tag -s <tag> -m "signed version 0.2 released" <commit>
# 删除标签
$ git tag -d <tag>
# 推送某个标签到远程
$ git push origin <tag>
# 一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags
# 如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除
$ git tag -d <tag>
$ git push origin :refs/tags/<tag>
线性提交
$ git rebase -i HEAD~n
# 按照自己的需求选择模式p/e/s/p等
# 注意需要设置默认编辑器,否则跳转编辑器失败,设置默认git编辑器命令如下:
$ git config --global core.editor /usr/bin/vim
二分法查找bug
# 开始 bisect
$ git bisect start
# 录入正确的 commit
$ git bisect good xxxxxx
# 录入出错的 commit
$ git bisect bad xxxxxx
# 然后 git 开始在出错的 commit 与正确的 commit 之间开始二分查找,这个过程中你需要不断的验证你的应用是否正常
$ git bisect bad
$ git bisect good
$ git bisect good
...
# 直到定位到出错的 commit,退出 bisect
$ git bisect reset
cherry-pick commit
# 使用场景:在master上有过commit,发现需要切分支搞,可是你又不想把刚才在master上的修改复制粘贴到新分支的文件中,那么就可以在新分支下使用cherry-pick 捡回刚才的那条commit
$ git cherry-pick [commit-id]
update
fetch操作的本质是更新repo所指定远程分支的头指针(server->refs/remotes/xxx/)
merge操作的本质是合并当前分支和指定的头指针(refs/remotes/xxx->refs/heads)
pull操作的本质是fetch + merge
commit
commit的本质是修改了当前分支的头指针(refs/heads)
push操作本质是提交当前分支头指针到server,顺便也修改了本地存储的server头指针(refs/remotes/xxx)
checkout
复制本地分支的本质是拷贝了refs/heads/下的一个头指针
push本地分支到server的本质是把这个头指针上传服务器,顺便拷贝了本地存储的server头指针(refs/remotes/xxx)
tracking远程分支的本质是把refs/remotes/下的指针拷贝到了refs/heads下
GUI tool
- beyond compare
- meld
- source tree
注意
- 慎用git revert,版本回退尽量用git reset –hard
git revert 撤销 某次操作,此次操作之前和之后的commit和history都会保留,并且把这次撤销作为一次最新的提交,版本会递增,不影响之前提交的内容。git reset是直接删除指定的commit
git revert 和 git reset的区别
- 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的内容。
问题
Q: git refusing to merge unrelated histories
A: $ git pull origin master –allow-unrelated-histories