git 命令
Git基础
安装 Git
sudo apt-get install git # for ubuntu
brew install git # for mac
# change os for windows
帮助命令
man git
git <verb> --help
git help <verb>
man git-<verb>
git help push
git 用户信息配置
git config --global user.name "username"
git config --global user.email "example@qq.com"
查看所有配置项
git config -l
用户的git配置文件
~/.gitconfig
本地创建ssh key
ssh-keygen # 默认情况一直回车
cat ~/.ssh/id_rsa.pub # 查看生成的公钥(需要把公钥添加到git仓库的服务端)
创建git仓库
mkdir demo
cd demo
git init # 初始化一个git仓库
初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。
如果当前目录下有几个文件想要纳入版本控制,需要先用 git add
命令告诉 Git 开始对这些文件进行跟踪,然后提交
touch README
git add README
git commit -m 'first commit'
git remote add origin git@github.com:qiangluis/qiangluis.github.io.git
git push -u origin master
添加已有仓库
cd existing_git_repo
git remote add origin git@github.com:qiangluis/qiangluis.github.io.git
git push -u origin master
从现有仓库克隆
git clone git://github.com/jquery/jquery.git
git clone --bare git://github.com/jquery/jquery.git # clone纯版本仓库
检查当前文件状态
git status # 检查当前文件状态
跟踪新文件 或 暂存修改
git add <path> # 添加新文件(开始跟踪一个新文件)
git add <exist_file> # 暂存已修改的文件
git add . # 添加当前目录所有文件
git add -A # 添加当前目录所有文件
git add -n <pathspec> # 同--dry-run,不会真正执行,只显示会被添加的文件列表
在 git add
后面可以指明要跟踪的文件或目录路径。如果是目录的话,就说明要递归跟踪该目录下的所有文件。(译注:其实 git add
的潜台词就是把目标文件快照放入暂存区域,也就是 add file into staged area,同时未曾跟踪过的文件标记为需要跟踪。这样就好理解后续 add 操作的实际意义了。)
位于.gitignore
中匹配的文件,在执行git add .
的命令时会自动忽略。
.gitignore 忽略某些文件
顶层工作目录中添加一个叫”.gitignore”的文件,用来忽略某些文件。
例子:
# 以'#' 开始的行,被视为注释.
# 忽略掉所有文件名是 foo.txt 的文件.
foo.txt
# 忽略所有生成的 html 文件,
*.html
# foo.html是手工维护的,所以例外.
!foo.html
# 忽略所有.o 和 .a文件.
*.[oa]
- gitignore 格式参考http://iissnan.com/progit/html/zh/ch2_2.html
- github gitignore https://github.com/github/gitignore
比较文件差异
git status
git diff # 显示还没有暂存起来的改动(工作目录与暂存区index的区别)
git diff <commit> <path> # 显示工作目录与指定commit的区别
git diff <commit> <commit> # 显示两次commit的区别
git diff <commit> <commit> <path># 显示两次commit中,某些路径(文件)的区别
git diff master dev # 显示两个分支的差异
git diff master # 显示工作目录与master分支的差异
git diff --cached # 显示暂存区index与上次commit时的差异(查看已经暂存起来的变化)
git diff --staged # 【同上】显示暂存区index与上次commit时的差异
git diff --cached <commit> # 显示暂存区index与commit的差异
git diff --cached <commit> <path> # 显示暂存区index与commit的差异
git diff <blob> <blob> # 比较两个blob的不同
patch 补丁
git diff > ../sync.patch # 生成补丁
git apply ../sync.patch # 打补丁
git apply --check ../sync.patch # 测试补丁能否成功
git diff HEAD~..HEAD > last.patch # 两个版本间的不同来生成patch
提交更新
git commit -m <'msg'> # 提交当前暂存区域的文件,msg 作为提交的注释
git commit -a # 提交所有修改的文件(跳过使用暂存区域)
git commit -am <'msg'> # 全部提交
给 git commit
加上 -a
选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过git add
步骤
删除或移动文件
git rm <file> # 移除文件(包括路径)
git rm -r -f <directory> # 遍历移除文件夹的所有内容
git rm --cached readme.txt # 把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。换句话说,仅是从跟踪清单中删除。
git rm log/\*.log # 使用 glob 模式。
git mv <source> <destination> # 移动或重命名文件
git mv <source> <destination directory>
查看提交历史
git show <object> # Shows one or more objects (blobs, trees, tags and commits).
git log —stat # 查看commit修改了哪些文件,显示简要的增改行数统计(alias glg)
git log --oneline --decorate --color --graph # 查看分支合并的情况(alias glog)
git log --abbrev-commit --pretty=oneline
git log -p # 查看上次修改了哪些内容;-p meas patch
git log -p <file> # 查看这个文件的历史修改
git log -p -2 # 我们常用 `-p` 选项展开显示每次提交的内容差异,用`-2` 则仅显示最近的两次更新
git blame <file> # 查看文件的每一行最后由谁修改
- git log 输出格式http://iissnan.com/progit/html/zh/ch2_3.html
撤销操作
修改最后一次提交
有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用 –amend 选项重新提交:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
git reset HEAD <file> # 取消暂存文件(工作目录中对文件的修改保留)
git reset --hard # 重置暂存区索引和工作目录,放弃上次commit后对已track文件的所有修改
git checkout <file> # 取消对文件的修改(从暂存区索引中恢复文件)
记住,任何已经提交到 Git 的都可以被恢复。即便在已经删除的分支中的提交,或者用--amend
重新改写的提交,都可以被恢复(关于数据恢复的内容见第九章)。所以,你可能失去的数据,仅限于没有提交过的,对 Git 来说它们就像从未存在过一样。
远程仓库的使用
git remote -v # 查看远程仓库
git remote add [shortname] [url] # 添加远程仓库
git remote add origin git@github.com:xxxx.git
git remote rm origin # 移除远程仓库
git remote set-url --push origin <new_url> # 修改远程仓库
git remote show origin # 查看远程仓库信息
git remote rename origin github # rename remote
git remote rm github # 删除remote
git pull origin master
# 处女座和强迫症患者请使用 git pull --rebase 命令
git pull --rebase origin master # 使用rebase不会在本地合并时,产生分支的结果,而使用patch的方式
git push origin master
git push -u origin --all # pushes up the repo and its refs for the first time
git push -u origin --tags # pushes up any tags
git push -f origin master # 强制把本地的仓库push到远程origin上(慎用!),用于rebase或恢复到某个版本后
git fetch [remote-name] # 从远程仓库抓取数据
git fetch origin/dev
git fetch origin
会抓取从你上次克隆以来别人上传到此远程仓库中的所有更新(或是上次 fetch 以来别人提交的更新)。
可以使用git pull
命令自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支。
打标签
git tag # 列出现在的所有tag
git tag <tagname> # 打tag
git tag -a <tagname> -m <'msg'> # 带注释的tag
git show <tagname> # 命令查看相应标签的版本信息,并连同显示打标签时的提交对象。
git push origin <tagname>
git push origin --tags
git pull origin --tags
git tag -d <tagname> # 删除本地的tag
git push origin :refs/tags/<tagname> # 删除远程的tag
git stash 储藏
你想切换分支,但是你还不想提交你正在进行中的工作;所以你储藏这些变更。为了往堆栈推送一个新的储藏,只要运行 git stash
:
git stash # 将当前修改文件保存到stash(必须是已经track的文件)
git stash save <'msg'> # 将文件保存到stash并添加注释
git stash list
git stash pop # 来重新应用stash,同时立刻将其从堆栈中移走。
git stash apply # 应用但不删除stash
git stash apply stash@{2}
git stash apply --index # 应用stash的内容,并更新暂存区index
git stash drop # 放弃stash
git stash drop stash@{2} # 放弃stash
git stash clear
git stash show -p stash@{0} | git apply -R # 取消之前所应用stash的修改(实现了stash unapply)
git stash show -p | git apply -R
git stash branch <new_branch> # 创建一个新的分支,检出stash 进行apply,如果成功,将会丢弃stash。
分支管理
git branch # 查看本地所有分支
git branch -a # 查看所有分支[包括remote]
git branch -r # 查看远程所有分支
git branch --no-merged # 查看未合并的分支
git branch feature1 master # 从主分支master创建分支feature1,但不会切换到feature1分支
git branch -m old_branch_name new_branch_new # 分支改名
我们用 (远程仓库名)/(分支名)
这样的形式表示远程分支。
git checkout <branch> # 切换到分支
git checkout -b <new_branch> <start_point> # 创建并切换到分支
git checkout -t <remote/branch> # 创建track远程分支的本地分支
git checkout -b <new_branch> <remote/branch> # 创建远程分支的命名的本地分支
git push origin <branch> # 将当前分支推送到远程origin
git pull origin <branch> # 拉取远程origin的分支
# 删除分支
git branch -d <branch> # 删除一个分支
git branch -D <branch> # 强制删除未合并的分支
git push origin :branch_remote_name # 删除远程分支
git branch -r -d branch_remote_name # 删除远程分支
分支合并(将dev分支合并到master)
git checkout master
git pull origin master
git merge dev # 将dev分支合并到当前分支HEAD(合并过程中可能需要解决冲突)
git push origin master # 将合并后的master分支push到远程
重写历史
git commit --amend # 修改最近一次提交
git rebase -i <commit> # 修改指定commit到当前HEAD的提交
git rebase -i HEAD~3 # 修改前3次commit(HEAD~3..HEAD)
重写历史 http://iissnan.com/progit/html/zh/ch6_4.html
git rebase -i 还可以重新排列commit的顺序。
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD # 在当前分支的所有历史版本中执行相应的操作进行重写
数据恢复
git log --diff-filter=D --summary # 列出版本库中所有已删除的文件
如果你想将其恢复,参照http://stackoverflow.com/questions/953481/restore-a-deleted-file-in-a-git-repo
# HEAD 指向当前版本
git revert <commit> # 还原某个版本的修改
git revert -n <commit> # 撤销操作的修改应用于 暂存区index 和 工作目录,但不产生一次新的commit
git revert HEAD # 撤销上一次commit所做的修改(逆操作),并做为一次新的commit.
git revert HEAD~3 # 撤销前4次commit, 并且以撤销所做的修改做为一次新的commit.
git revert b6d3da4..b0a940c # 撤销从 b6d3da4 到 b0a940c 的commit
git revert master~5..master~2 # 撤销master倒数第5次(包含)到master倒数第2次(包含)范围的commit
git reset # 重置HEAD到指定的状态
git reset <commit> <file> # 将某个文件恢复到指定版本
git reset HEAD <file> # 取消暂存某个文件
git reset <mode> <commit> # If <mode> is omitted, defaults to "--mixed".
--soft 暂存区index和工作目录保持不变,只修改HEAD到指定的commit。【不能用于单个文件】
--mixed 指定<commit>时,重置暂存区index, 但工作目录文件与commit进行合并,并修改HEAD到指定的commit
如果没有指定<commit>时,只修改暂存区index,工作目录保持不变,恢复到HEAD
--hard 重置暂存区index和工作目录保持,放弃对所有track文件的修改,并修改HEAD到指定的commit
--merge 重置暂存区index, 更新工作目录中与commit不同的文件,但保留本地未staged的文件修改。当工作目录文件与commit不同,并且暂存区index有未缓存的修改时,取消reset.
--keep 重置当前HEAD与commit不同的所有文件,但工作目录文件中有本地修改时,取消reset(会保留本地文件的修改)
git reset --hard origin/dev # 重置HEAD到origin/dev
git reset --hard HEAD~ # 回退到上一版本
git reset --hard <commit> # 回退到某次提交
git checkout -b <branch_name> <commit> # 签出某个提交版本的分支
# 查找历史版本
git log # 查看提交历史
git reset --hard <commit> # 回到之前的版本
git reflog # 查看HEAD ref指针变动的log
git log -g # 会输出 reflog 的正常日志,从而显示更多有用信息
git fsck --full # 该工具会检查仓库的数据完整性。如果指定 --full 选项,该命令显示所有未被其他对象引用 (指向) 的所有对象
git gc # 收集所有松散对象并将它们存入 packfile,合并这些 packfile 进一个大的 packfile,然后将不被任何 commit 引用并且已存在一段时间 (数月) 的对象删除。
git count-objects -v # 查看使用了多少空间
Git 会在你每次修改了 HEAD 时悄悄地将改动记录下来。当你提交或修改分支时,reflog
就会更新。git update-ref
命令也可以更新 reflog
git rebase
- 修改分支的历史,让mywork分支的历史看起来没有合并,而是从dev延伸来。
http://gitbook.liuhui998.com/4_2.html
git checkout mywork
git rebase dev
git rebase --continue
git rebase --abort
- 交互式rebase
这种方法通常用于在向别处推送提交之前对它们进行重写。交互式rebase提供了一个简单易用的途径让你在和别人分享提交之前对你的提交进行分割、合并或者重排序。在把从其他开发者处拉取的提交应用到本地时,你也可以使用交互式rebase对它们进行清理。 http://gitbook.liuhui998.com/4_3.html
git rebase -i <newbase> <upstream/branch>
git rebase -i <newbase> # 从newbase的commit开始进行交互式的合并,在vi中更改第一列并:w保存并退出
使用Git查找历史版本的问题
$ git bisect start # 启动bisect二分查找
$ git bisect bad # 标注当前HEAD为bad状态
$ git bisect good v1.0 # 标注从v1.0开如的分支为good状态
# 在多个版本中定位问题
git bisect good # 标注当前为good状态
git bisect bad # 标注当前为bad状态
git bisect reset # 重设你的HEAD到你开始前的地方
事实上,如果你有一个脚本会在工程正常时返回0,错误时返回非0的话,你可以完全自动地执行git bisect。首先你需要提供已知的错误和正确提交来告诉它二分查找的范围。你可以通过bisect start命令来列出它们,先列出已知的错误提交再列出已知的正确提交:
git bisect start HEAD v1.0
git bisect run test-error.sh
这样会自动地在每一个检出的提交里运行test-error.sh直到Git找出第一个破损的提交。你也可以运行像make或者make tests或者任何你所拥有的来为你执行自动化的测试。
子模块
git submodule add url path # 添加子模块
例如:git submodule add git://github.com/chneukirchen/rack.git rack
克隆一个带子模块的项目
git clone git://github.com/schacon/myproject.git
git submodule init # 来初始化你的本地配置文件
git submodule update # 来从那个项目拉取所有数据并检出你上层项目里所列的合适的提交
现在你的rack子目录就处于你先前提交的确切状态了。如果另外一个开发者变更了 rack 的代码并提交,你拉取那个引用然后归并之后,需要再次执行
git submodule update
git log -1 rack # 查看谁最后变更了子模块
子模块http://iissnan.com/progit/html/zh/ch6_6.html
others
git hash-object
该命令输出长度为 40 个字符的校验和。这是个 SHA-1 哈希值
$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4
git show <object> # Shows one or more objects (blobs, trees, tags and commits).
git cat-file -p master # 查看master的commit内容
git cat-file -p <object> # 根据哈希值或引用查看文件
git cat-file -t <object> # 查看文件类型
git cat-file -s <object> # 查看文件大小
git ls-tree <tree-ish> # 查看tree的文件列表
git ls-files # 查看暂存区index和工作目录的文件列表
git rev-parse dev # 某个分支指向哪个特定的SHA
git rev-list # 查看某次commit的内容
git rev-list --objects # 查看某次commit的内容