Git常用命令

2019-06-28  本文已影响0人  d8893ea8ba05

配置及帮助相关

设置配置:git config --global user.name "John Doe"
查看配置及出处:git config --show-origin rerere.autoUpdate
查看帮助:git help <verb>

基本命令

将目录初始化为git目录:git init
克隆已有的项目:git clone https://github.com/libgit2/libgit2 mylibgit
查看文件状态:git status -s
移除文件:git rm (-f参数强制移除被修改的文件,如果文件被修改了,默认是不会被移除的)
取消文件跟踪:git rm --cached
移动文件:git mv file_from file_to
查看历史:git log (-p:显示差异;-2:最近两次记录;--stat:文件状态)
自定义格式历史记录及合并路径:git log --pretty=format:"%h - %an, %ar : %s" --graph
从标记中回退:git reset HEAD <file>
退回到上次提交的版本:git checkout -- <file>
查看远端:git remote -v
添加远端:git remote add <shortname> <url>
拉取数据:git fetch/git pull
推送数据:git push <remote> <branch>
查看本地与远端分支对应情况:git remote show origin
重命名/删除远端:git remote rename pb paul / git remote remove paul
查看/查找tag:git tag/git tag -l "v1.8.5*"
创建匿名tag:git tag -a v1.4 -m "my version 1.4"
补打tag:git tag -a v1.2 9fceb02
推送tag:git push origin v1.5/git push origin --tags
删除本地/远端tag:git tag -d <tagname>/git push origin --delete <tagname>
牵出tag:git checkout 2.0.0
基于tag创建分支:git checkout -b version2 v2.0.0

分支

git commit记录与blob.png

创建分支:git branch testing
切换分支:git checkout testing
创建并切换分支:git checkout -b <newbranchname>
合并分支:git merge hotfix
删除分支:git branch -d hotfix
查看分支:git branch (-v:显示最后commit,--merged/--no-merged:过滤已经合并/未合并到当前分支的分支,git branch --no-merged master:是否合并到master的分支)
同步到远程分支:git push <remote> <branch> (git push origin serverfix 等效于 git push origin refs/heads/serverfix:refs/heads/serverfix)
创建本地分支并跟踪对应的远程分支:git checkout -b <branch> <remote>/<branch> / git checkout --track origin/serverfix / git checkout <branch>
设置本地分支的跟踪远程分支:git branch -u origin/serverfix
显示本地分支与远程分支的对应情况:git branch -vv
更新本地git数据:git fetch --all
更新本地git数据并合并当前分支:git pull
删除远端分支:git push origin --delete <branch>
变基:git rebase <branch>
取出client分支,找出处于client(client是基于server开出的分支)分支和server分支的共同祖先之后的修改,然后把她们在master分支上重新放一遍: git rebase --onto master server client
变基远端:git pull --rebase

Git服务器

克隆裸仓库:git clone --bare my_project my_project.git
将裸仓库放置到服务器上:scp -r my_project.git user@git.example.com:/srv/git
通过git将仓库目录的组权限设置为可写:git init --bare --shared
SSH Key目录:cd ~/.ssh
创建sshkey:ssh-keygen -o
打印sshkey公钥:cat ~/.ssh/id_rsa.pub
创建git用户和对应的.ssh目录

  $ sudo adduser git
  $ su git
  $ cd
  $ mkdir .ssh && chmod 700 .ssh
  $ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys

添加用户公钥:cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
创建并初始化git:

  $ cd /srv/git
  $ mkdir project.git
  $ cd project.git
  $ git init --bare

已经设置了git用户和git仓库的服务器,快速添加新项目:

  $ cd myproject
  $ git init
  $ git add .
  $ git commit -m 'initial commit'
  $ git remote add origin git@gitserver:/srv/git/project.git
  $ git push origin master

限制git用户活动在与git相关范围内:

  $ cat /etc/shells   # see if `git-shell` is already in there.  If not...
  $ which git-shell   # make sure git-shell is installed on your system.
  $ sudo -e /etc/shells  # and add the path to git-shell from last command
  $ sudo chsh git -s $(which git-shell)

分布式Git

生成patch:git format-patch -M origin/master
应用patch:git am 0001-limit-log-function.patch
查看不在master上的commit:git log contrib --not master
查看当前分支与目标分支自从公共基点后的commit:git diff master...contrib
查看共同父commit:git merge-base contrib master
展示修改:git diff
只合并特定节点:git cherry-pick e43a6
准备发布:git archive master --prefix='project/' | gzip > git describe master.tar.gz / git archive master --prefix='project/' --format=zip > git describe master.zip
查看远端所有分支,包括pull request:git ls-remote https://github.com/schacon/blink

Git工具

查看单个提交:

  $ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
  $ git show 1c002dd4b536e7479f
  $ git show 1c002d

选择父节点:HEAD^
experiment上有但master上没有的提交:git log master..experiment
refA或refB上有但是refC上没有的提交:git log refA refB ^refC / git log refA refB --not refC
显示master或者experiment中包含但不是两者共有的提交:git log --left-right master...experiment
交互式暂存:git add -i
暂存工作:git stash / git stash push -m
删除暂存:git stash drop
应用并删除暂存:git stash pop
查看所有暂存:git stash list
暂存并不重置工作区:git stash --keep-index
同时暂存未跟踪的文件:git stash -u
清理工作目录:git clean -f -d
查找某个常量何时引入:git log -S ZLIB_BUF_MAX --oneline
查找zlib.c文件中git_deflate_bound in the函数的每一次变更:git log -L :git_deflate_bound:zlib.c
修改最后一次提交:git commit --amend
修改前三个父节点的提交:git rebase -i HEAD~3
仅移动HEAD:git reset --soft
移动HEAD及索引:git reset --mixed (默认)
移动HEAD并更新目录:git reset --hard
squash提交

git reset --soft HEAD~2
git commit

回退记录:git revert -m 1 HEAD
假合并:git merge -s ours mundo
查找bug引入源:git blame -L 69,82 Makefile
查看代码原来在哪里:git blame -C -L 141,153 GITPackUpload.m
二分查找:

  $ git bisect start
  $ git bisect bad
  $ git bisect good v1.0

打包分支:git bundle create repo.bundle HEAD master
克隆打包:git clone repo.bundle repo
打包commit:git bundle create commits.bundle master ^9a466c5
验证包:git bundle verify ../commits.bundle
查看包分支:git bundle list-heads ../commits.bundle
导入包内容:git fetch ../commits.bundle master:other-master

自定义Git

查看git支持的选项列表:man git-config

Git内部远离

.git目录下的核心内容:HEAD 文件、(尚待创建的)index 文件,和 objects 目录、refs 目录。objects 目录存储所有数据内容;refs 目录存储指向数据(分支)的提交对象的指针;HEAD 文件指示目前被检出的分支;index 文件保存暂存区信息

数据对象

Git的数据对象有四种:blob文件对象、tree树对象、commit提交对象和tag标签对象

文件对象

创建新文件并存储入数据内容数据库:

$ echo 'version 1' > test.txt
$ git hash-object -w test.txt

接着,向文件里写入新内容,并再次将其存入数据库:

$ echo 'version 2' > test.txt
$ git hash-object -w test.txt
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a

可以查看到不同的版本内容被记录下来:

$ find .git/objects -type f
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30

现在可以把文件内容恢复到某个版本:

$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt
$ cat test.txt
version 1
$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt
$ cat test.txt
version 2

树对象

一个树对象包含了一条或多条树对象记录(tree entry),每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息:

$ git cat-file -p master^{tree}
100644 blob a906cb2a4a904a152e80877d4088654daad0c859      README
100644 blob 8f94139338f9404f26296befa88755fc2598c289      Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      lib
$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b      simplegit.rb

为创建一个树对象,首先需要通过暂存一些文件来创建一个暂存区

git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt

将暂存取写入树对象

$ git write-tree
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
100644 blob 83baae61804e65cc73a7201a7252750c76066a30      test.txt

提交对象

提交对象包含了一个顶层树对象,代表当前项目快照:

$ echo 'first commit' | git commit-tree d8329f
fdf4fc3344e67ab068f836878b6c4951e3b15f3d
$ git cat-file -p fdf4fc3
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author Scott Chacon <schacon@gmail.com> 1243040974 -0700
committer Scott Chacon <schacon@gmail.com> 1243040974 -0700

first commit

创建另外两个提交对象,格子饮用上一个提交:

$ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
cac0cab538b970a37ea1e769cbbde608743bc96d
$ echo 'third commit'  | git commit-tree 3c4e9c -p cac0cab
1a410efbd13591db07496601ebc7a059dd55cfe9

这就是每次我们运行 git add 和 git commit 命令时, Git 所做的实质工作——将被改写的文件保存为数据对象,更新暂存区,记录树对象,最后创建一个指明了顶层树对象和父提交的提交对象。 这三种主要的 Git 对象——数据对象、树对象、提交对象——最初均以单独文件的形式保存在 .git/objects 目录下

标签对象

标签对象通常指向一个提交对象,而不是一个树对象。 它像是一个永不移动的分支引用——永远指向同一个提交对象,只不过给这个提交对象加上一个更友好的名字罢了。可以像这样创建一个轻量标签:

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d

若要创建一个附注标签,Git 会创建一个标签对象,并记录一个引用来指向该标签对象,而不是直接指向提交对象。 可以通过创建一个附注标签来验证这个过程(-a 选项指定了要创建的是一个附注标签):

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700

test tag

refs引用

引用是一个文件来保存 SHA-1 值,并给文件起一个简单的名字,然后用这个名字指针来替代原始的 SHA-1 值。

git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9

这基本就是Git分支的本质,一个指向某一系列提交之首的指针或引用:

git update-ref refs/heads/test cac0ca

HEAD

HEAD 文件是一个符号引用(symbolic reference),指向目前所在的分支。 所谓符号引用,意味着它并不像普通引用那样包含一个 SHA-1 值——它是一个指向其他引用的指针。当我们执行 git commit 时,该命令会创建一个提交对象,并用 HEAD 文件中那个引用所指向的 SHA-1 值设置其父提交字段

$ cat .git/HEAD
ref: refs/heads/master
$ git symbolic-ref HEAD
refs/heads/master
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test

Git包文件

Git 最初向磁盘中存储对象时所使用的格式被称为“松散(loose)”对象格式。 但是,Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。Git 打包对象时,会查找命名及大小相近的文件,并只保存文件不同版本之间的差异内容。 你可以查看包文件,观察它是如何节省空间的。 git verify-pack 这个底层命令可以让你查看已打包的内容。

引用规格

引用规格的格式由一个可选的 + 号和紧随其后的 <src>:<dst> 组成,其中 <src> 是一个模式(pattern),代表远程版本库中的引用;<dst> 是那些远程引用在本地所对应的位置。 + 号告诉 Git 即使在不能快进的情况下也要(强制)更新引用。可在.git/config文件中配置:

[remote "origin"]
url = https://github.com/schacon/simplegit-progit
fetch = +refs/heads/*:refs/remotes/origin/* 
push = refs/heads/master:refs/heads/qa/master

数据恢复

reset后找回丢失的commit,并基于丢失的提交创建分支

git reflog
git branch recover-branch ab1afef

找回丢失的分支

git fsck --full

git库删除大的文件记录

//查找最大的文件
git verify-pack -v .git/objects/pack/pack-29…69.idx \
  | sort -k 3 -n \
  | tail -3
//显示blob对应的文件
$ git rev-list --objects --all | grep 82c99a3
82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz
//查找包含这个blob的commit
git log --oneline --branches -- git.tgz
//重写commit,从某个提交之后的所有commit中删除对应的blob
git filter-branch --index-filter \
  'git rm --ignore-unmatch --cached git.tgz' -- --all
rm -Rf .git/refs/original
rm -Rf .git/logs/
git gc
//移除不可引用的blob
git prune
上一篇下一篇

猜你喜欢

热点阅读