基本命令格式:
usage: git []
一、开始一个工作区(参见:git help tutorial)
clone 克隆一个仓库到一个新的目录中。
init 创建一个空的Git仓库,或者重新初始化一个存在的仓库。
二、对当前的变化进行处理(参见:git help everyday)
add 把文件的内容加入到索引区(index)
mv 移动或重命名一个文件、目录或链接
restore 恢复工作的文件树
rm 从工作目录树和索引区中删除文件
sparse-checkout 初始化和修改稀疏checkout
三、检查历史和状态(参见:git help revisions)
bisect 使用二进制搜索查找引入错误的提交
diff 显示commits之间,或commit与工作目录区等的改变内容
grep 打印匹配模式的行
log 显示提交(commit)的日志
show 显示对象的不同类型
status 显示工作目录区的状态
四、增长、标记和微调通用的历史
branch 列出、创建或删除分支
commit 把变化的内容记录到仓库中
merge 把两个或者更多的开发历史加在一起
rebase 在另一个基层的顶部重新应用提交
reset 重置当前的HEAD到指定的状态
tag 创建、列出、删除或验证带GPG标记的tag对象
五、协作(参见: git help workflows)
fetch 从另一个仓库中下载对象和引用
pull 从另一个仓库中或者当地分支fetch和整合
push 跟相关的对象一起更新远程的引用
git help -a 和 git help -g 列出可用的子命令和一些概念指导。
参见 git help 或 git help 阅读指定的子命令或概念。
git help git 可以查看该系统的概况。
初始化一个仓库
git init 初始化
git status 查看状态
git add [filename|.] 把工作区的文件或所有文件添加到索引区。
git commit -m 'some msg' 提交到本地仓库中。把索引区的内容提交到本地仓库,如果两个文件的内容完全相同,
在索引区只会创建一个blob对象。
git gc 把blob对象进行压缩和垃圾对象进行清理
git branch xxx 创建分支
git checkout xxx 切换到xxx分支
git checkout b xxx 创建并切换到xxx分支
git checkout -- file 可以丢弃工作区的修改。git checkout -- file命令中的 -- 很重要,
没有 --,就变成了“切换到另一个分支”的命令
git reset HEAD 可以把暂存区的修改撤销掉(unstage),重新放回工作区;
git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。
当我们用HEAD时,表示最新的版本。
$ git rm 从版本库中删除该文件.小提示:先手动删除文件,然后使用git rm
和git add效果是一样的。
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
$ git checkout -- test.txt
git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!
$ cat .git/HEAD
ref: refs/heads/master HEAD目前指向的是master分支。
$ cat .git/refs/heads/master d0bde7..... 说明master指向的是一个commit对象。
而commit指向的是一个tree,tree指向的是文件对象。
如果在工作区中创建文件夹,并使用以下命令:
git add folder1/
只会创建其中的文件,文件夹的信息没有包含其中,但会出现在objects/文件中,例如
folder1/file3.txt
可以使用 git ls-files -s 结果中查询的
但是在执行 git commit -m 'xxx' 后,会创建一个tree对象,对应于这个文件夹。
Git中的文件状态,一共有四种:
Untracked
Modified
Staged
Unmodified 'both modified'
查看提交log
git log
可以查看commit提交的历史,以及可以看到HEAD所指向的commit
可以加选项: --pretty=oneline ,这样输入比较简洁。
Branches
分支就是指向commit的命令指针。
Master branch and HEAD
Master是一个分支,默认是规范的主线分支。
HEAD是一个特殊的指针,与当前活动的分支相关联,永远指向最新的commit。
$ git branch: 列出已经有的分支
$ git branch : 创建一个名为branch_name的分支,如果已经存在,会出现一个错误。
$ git branch -d 可以删除已经merge后的分支
$ git branch -D 可以删除还没有merge后的分支
$ git checkout dev: 切换到dev分支
$ git checkout -b dev: 创建并切换到新的div分支
$ git switch -c dev 创建并切换到新的dev分支
$ git switch master 直接切换到已有的master分支
使用新的git switch命令,比git checkout要更容易理解。
$ cat .git/HEAD
ref: refs/heads/dev
小结:
Git鼓励大量使用分支:
查看分支: git branch
创建分支: git branch
切换分支: git checkout 或者git switch
创建+切换分支: git checkout -b 或者git switch -c
合并某分支到当前分支: git merge
删除分支: git branch -d
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交:
$ git status 有些内容还没有提交,也不想提交。
Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge
现在,用git status
查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git checkout -b issue-101
Switched to a new branch 'issue-101'
现在修复bug,然后提交:
$ git add readme.txt
$ git commit -m "fix bug 101"
修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:
$ git switch master
...
$ git merge --no-ff -m "merged bug fix 101" issue-101
...
现在,是时候接着回到dev分支干活了!
$ git switch dev
Switched to branch 'dev'
$ git status
On branch dev
nothing to commit, working tree clean
工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了:
$ git stash pop
再用git stash list查看,就看不到任何stash内容了:
$ git stash list
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
在master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。
同样的bug,要在dev上修复,我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个master分支merge过来。
为了方便操作,Git专门提供了一个cherry-pick命令,让我们能复制一个特定的提交到当前分支:
$ git branch
* dev
master
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 101
1 file changed, 1 insertion(+), 1 deletion(-)
Git自动给dev分支做了一次提交,注意这次提交的commit是1d4b803,它并不同于master的4c805e2,因为这两个commit只是改动相同,但确实是两个不同的commit。用git cherry-pick
,我们就不需要在dev分支上手动再把修bug的过程重复一遍。
有些聪明的童鞋会想了,既然可以在master分支上修复bug后,在dev分支上可以“重放”这个修复过程,那么直接在dev分支上修复bug,然后在master分支上“重放”行不行?当然可以,不过你仍然需要git stash
命令保存现场,才能从dev分支切换到master分支。
小结
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场;
在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick 命令,把bug提交的修改“复制”到当前分支,避免重复劳动。
当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote:
$ git remote
origin
或者,用git remote -v显示更详细的信息:
$ git remote -v
...
...
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
如果要推送其他分支,比如dev,就改成:
$ git push origin dev
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!
抓取分支
多人协作时,大家都会往master和dev分支上推送各自的修改。
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@github.com:michaelliao/learngit.git
......
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:
$ git add env.txt
$ git commit -m "add env"
...
$ git push origin dev
...
你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:
$ cat env.txt
env
$ git add env.txt
$ git commit -m "add new env"
...
$ git push origin dev
To github.com:michaelliao/learngit.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:
$ git pull
There 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
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/ dev
git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
再pull:
$ git pull
...
这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:
$ git commit -m "fix env conflict"
[dev 57c53ab] fix env conflict
$ git push origin dev
因此,多人协作的工作模式通常是这样:
首先,可以试图用git push origin 推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to origin/。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
小结
查看远程库信息,使用git remote -v;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,
本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
不能删除当前分支,必须切换到其他分支才行
$ git checkout master
$ git branch -D dev: 这个命令不会提示是否已经merge,不建议使用,使用-d较好。
但是如果使用-D dev后,分支是被删除了,其他的commit、tree对象不会被同时删除。
我们也可以切换到某个commit上,这样HEAD就直接指向了这个commit,而不是有名称的分支
$ git checkout 2e4624
这时打印出来的内容很多,提示在'detached HEAD'状态,可以使用
git switch -c
或者撤销这个操作
git switch -
$ git log
此时可以看到的commit日志就会少许多
此时由于没有分支名称,我们也可以使用较新的git switch,也可以使用
$ git checkout -b
来创建一个分支,并切换到该分支上。
如果我们要找到比当前master分支前面的无分支名的commit,可以使用:
$ git reflog
就会打印出所有HEAD的切换的日志,就可以找到无名的commit,然后
$ git checkout
$ git branch -b dev
可以对比工作区和索引区中文件不同之处,
$ git diff --cached
可以对比索引区和本地仓库之间的文件不同。
当然如果使用vscode显示更为明显。
```
$ git diff HEAD --
查看工作区和版本库里面最新版本的区别
```
配置git全局变量:
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
先在github上创建一个新的仓库,会提示三种不同的后续操作,分别为:创建新的仓库,从现存的仓库推送,从其他仓库中导入。
SSH:
git remote add origin git@github.com:xxx/yyy.git
HTTPS:
git remote add origin https://github.com/xxx/yyy.git
远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,
但是origin这个名字一看就知道是远程库。
执行该命令后,会在.git/config文件中增加:
[remote "origin"]
url = https:/github.com/xxx/yyy.git
fetch = +refs/heads/*:refs/remotes/origin/*
git push -u origin master
就会把本地仓库代码的送到远程origin master分支的仓库中。第一次推送master分支时,加上了-u参数,
Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和
远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
以后使用这个命令可以推送master到远程库中:
$ git push origin master
删除远程库
如果添加的时候地址写错了,或者就是想删除远程库,可以用git remote rm 命令。
使用前,建议先用git remote -v查看远程库信息:
$ git remote -v
origin git@github.com:/.git (fetch)
origin git@github.com:/.git (push)
然后,根据名字删除,比如删除origin:
$ git remote rm origin
此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。
要真正删除远程库,需要登录到GitHub,在后台页面找到删除按钮再删除。
用于压缩 .git/objects/ 的对象
所有的对象都会把压缩到 .git/objects/pack 中
git help gc
git gc: 清除不需要的文件和优化本地仓库
ls -lh .git/objects/pack
显示两个文件:
.idx 和 .pack 文件
所有的objects对象都被压缩到.pack文件中, .idx文件中记录相关信息,才能在
一个.pack中查询到所有被压缩的文件信息。
可以使用
git verify-pack -v .git/objects/pack/pack-2e....3.idx
会显示出来所有的commit、tree和blob对象的信息
git-verify-pack: 验证压缩的Git归档文件。
可以使用
git unpack-objects < path to .pack
注意,manual中可以看出,如果压缩文件在原来的目录中,使用该命令不会解压。
1、产生垃圾对象的原因之一是,在commit之前对同一个文件进行多次修改,并且都添加到索引区,
那么,前面几次的对象没有被引用,就是垃圾对象。
此时可以使用:
git gc
有用的对象都会被压缩到 .git/objects/pack/ 中
没有被引用的对象任然会留在 .git/objects/ 目录中。
可以使用:
git prune: 从对象数据库中修剪掉所有不能达到的对象。注意,大多情况下,用户应该运行git gc,
会调用git prune命令。
git fsck: 打印出dangling blob对象(就是没有引用的垃圾对象)
git prune -n: 其作用于git fsck相似。
2、删除分支而产生的垃圾对象
git checkout -b tmp
创建并切换到tmp分支,然后新建文件,git add . , git commit -m '1st commit from tmp'
git checkout master
此时会产生三个对象,分别是:blob, tree, commit 对象。
git branch -D tmp: 强行删除tmp分支
这时,该三个对象不会受到影响,就是使用 git prune命令也不能删除它们。
如果运行 git gc 也会把这三个对象压缩到 .pack 文件中,说明不认为是垃圾对象
如果我们一定要删除这三个对象:参考该网页:
https://stackoverflow.com/questions/3797907/how-to-remove-unused-objects-from-a-git-repository
git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
-c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
-c gc.pruneExpire=now gc "$@"
这样就可以删除这些对象!
场景:
在当前master上产生一个分支,例如
git checkout -b bugfix
然后新建文件,git add , git commit 后,进行合并操作,前提是要切换到master分支
git checkout master
git merge bugfix
这样,就是把master指针从原来的位置指向bugfix指向的commit。
此时,.git/HEAD指向master分支,.git/ORIG_HEAD指向前一次master分支。有利于回滚操作。
git reset ORIG_HEAD
此时会把最新的commit对象予以删除,新建的文件也处于 Untracked 状态。
合并分支时,加上--no-ff
(Fast forward)参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
场景:
两个分支并行进行前进,都有了commit后进行merge操作。
git merge bugfix
会出现一个界面需要进行处理,即git需要生成一个commit,这个界面就是要输入一个msg。
git log
可以看到master已经指向最新的commit
git cat-file -p 32299
可以看到有两个parent,及两个父commit。即一个是.git/refs/heads/bugfix, 另一个是
.git/refs/heads/ORIG_HEAD
这种关系从
git log
上看不出来,需要其他工具进行。例如:sourcetree
如果出现同时修改同一个文件test.txt时,需要手工解决冲突
git merge bugfix
会提示合并失败,需要手动解决冲突,然后提交。
git status
会提示一些信息,并有一行提示
both Modified: test.txt
说明两个分支都修改了这个文件。
nvim test.txt
可以看到有
\<<<<<<< HEAD
\...
\=======
...
\>>>>>>> bugfix
git ls-files -s
100644 9dae... 1 test.txt
100644 2534... 2 test.txt
100644 4c53... 3 test.txt
其中文件名前面的数字是版本号。
如果把冲突解决好后(可以使用vscode较方便),然后git add test.txt
git ls-files -s
100644 b176... 0 test.tx如果把冲突解决好后(可以使用vscode较方便),然后git add test.txt
git ls-files -s
100644 b176... 0 test.txtt
git commit
打开编辑器界面,修改commit的msg信息,保存后就会提交
用带参数的git log也可以看到分支的合并图:
$ git log --graph --pretty=oneline --abbrev-commit
git rebase:如果其他分支有master最新的数据,就可以实现fast farword
而git rebase master 就是实现让其他要进行合并的分支有最新的数据。
当然在这个操作时,也会有可能出现冲突的,也需要进行手动解决。
但是如果该分支其他人也在使用,不推荐使用。
在上一节我们看到了,多人在同一个分支上协作时,很容易出现冲突。即使没有冲突,后push的童鞋不得不先pull,在本地合并,然后才能push成功。
每次合并再push后,分支变成了这样:
$ git log --graph --pretty=oneline --abbrev-commit
* d1be385 (HEAD -> master, origin/master) init hello
* e5e69f1 Merge branch 'dev'
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
| |/
* | 12a631b merged bug fix 101
|\ \
| * | 4c805e2 fix bug 101
|/ /
* | e1e9c68 merge with no-ff
|\ \
| |/
| * f52c633 add merge
|/
* cf810e4 conflict fixed
总之看上去很乱,有强迫症的童鞋会问:为什么Git的提交历史不能是一条干净的直线?其实是可以做到的!
Git有一种称为rebase的操作,有人把它翻译成“变基”。
先不要随意展开想象。我们还是从实际问题出发,看看怎么把分叉的提交变成直线。
在和远程分支同步后,我们对hello.py这个文件做了两次提交。用git log命令看看:
$ git log --graph --pretty=oneline --abbrev-commit
* 582d922 (HEAD -> master) add author
* 8875536 add comment
* d1be385 (origin/master) init hello
* e5e69f1 Merge branch 'dev'
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
…
注意到Git用(HEAD -> master)和(origin/master)标识出当前分支的HEAD和远程origin的位置分别是582d922 add author和d1be385 init hello,本地分支比远程分支快两个提交。
现在我们尝试推送本地分支:
$ git push origin master
To github.com:michaelliao/learngit.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
很不幸,失败了,这说明有人先于我们推送了远程分支。按照经验,先pull一下:
$ git pull
...
再用git status看看状态:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
加上刚才合并的提交,现在我们本地分支比远程分支超前3个提交。
用git log看看:
$ git log --graph --pretty=oneline --abbrev-commit
* e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit
|\
| * f005ed4 (origin/master) set exit=1
* | 582d922 add author
* | 8875536 add comment
|/
* d1be385 init hello
...
对强迫症童鞋来说,现在事情有点不对头,提交历史分叉了。如果现在把本地分支push到远程,有没有问题?
有!
这个时候,rebase就派上了用场。我们输入命令git rebase试试:
$ git rebase
First, rewinding head to replay your work on top of it...
Applying: add comment
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
Applying: add author
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
输出了一大堆操作,到底是啥效果?再用git log看看:
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master) add author
* 3611cfe add comment
* f005ed4 (origin/master) set exit=1
* d1be385 init hello
...
原本分叉的提交现在变成一条直线了!这种神奇的操作是怎么实现的?其实原理非常简单。我们注意观察,发现Git把我们本地的提交“挪动”了位置,放到了f005ed4 (origin/master) set exit=1之后,这样,整个提交历史就成了一条直线。rebase操作前后,最终的提交内容是一致的,但是,我们本地的commit修改内容已经变化了,它们的修改不再基于d1be385 init hello,而是基于f005ed4 (origin/master) set exit=1,但最后的提交7e61ed4内容是一致的。
这就是rebase操作的特点:把分叉的提交历史“整理”成一条直线,看上去更直观。缺点是本地的分叉提交已经被修改过了。
最后,通过push操作把本地分支推送到远程:
Mac:~/learngit michael$ git push origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 576 bytes | 576.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To github.com:michaelliao/learngit.git
f005ed4..7e61ed4 master -> master
再用git log看看效果:
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master, origin/master) add author
* 3611cfe add comment
* f005ed4 set exit=1
* d1be385 init hello
…
远程分支的提交历史也是一条直线。
小结
rebase操作可以把本地未push的分叉提交历史整理成直线;
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
-a, --annotate
生成一个无符号的带注释的标签对象
-s, --sign
使用默认电子邮件地址的密钥创建一个GPG签名的标记。
-d, --delete
删除标签
git tag 生成轻量化的tag: 只会在/.git/refs/tags/下生成一个文件。
git tag v1.0
git tag -a -m :这种tag会包含meta-data数据(email 作者 时间 时区etc.)
还会生成一个tag对象。
git tag -a v1.0 -m "version 1.0"
git tag -a : 为旧的commit创建带标签的tag
git tag -a v1.0 236e1e......
git cat-files -p : 查询到具体的信息,与commit类似。
此时,运行
git tag -d v1.0
只会删除tags/下的文件,不会删除那个tag对象。
如果远程仓库进行了一些commit,而本地仓库没有变化,这是远程的master超前本地一次提交
git fetch:就会把远程的最新提交同步到本地,而此时本地的master没有变化
git merge origin/master:合并同步过来的commit
git pull: 相当于以上两步
如果出现"3 way merge"就与前面所得一样,可能有冲突,也可能没有,处理后,进行一个新的commit,会比远程仓库的commit提前了2步。
git branch -vv
可以显示超前于origin/master: ahead 2等信息。
git push origin master: 就可以同步远程的仓库。
git remote show origin
显示远程的信息、分支等和一些提示
git fetch: 会在本地多出了文件 .git/FETCH_HEAD
cat .git/FETCH_HEAD
显示远程仓库最新的分支信息
如果远程仓库有几个分支,在git fetch时,本地的.git/FETCH_HEAD内的显示顺序与
在哪个本地分支进行git fetch有关。如果直接运行 git pull就会只merge该分支,其他分支不会merge。
git reset --hard ORIG_HEAD
可以回滚到前面的版本
上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100
。
$ git reset --hard HEAD^
如果想要回到未来的版本,可以使用get reflog
(记录你的每一次命令)找到这个commit id,然后再 git reset --hard commit_id
。
git branch -vv: 可以查看本地与远程的分支是否同步。
如果远程仓库中删除了分支dev,使用:
$ git fetch
不能删除本地已经存在的dev,
$ git fetch --prune
$ git remote prune
以上两个命令都可以实现删除本次的dev
如果本地有新的分支,而远程没有直接使用
git push 不能成功,提示使用 git push --set-upstream origin feature-1
这是因为本地分支与远程分支没有关联。也可以使用
git push origin feature-1
也行。其中--set-upstream(-u)用于本地与远程进行关联。此时
git branch -vv
可以看到 feature-1与远程仓库的feaure-1没有关联。
git push origin -d feature-1
可以通过命令行删除远程仓库中的feature-1分支。
git push -u origin feature-1
此时使用
git branch -vv
可以看到feature-1与远程origin的feature-1相关联,关联之后,
以后再次push时,就可以简单的使用
git push
就可以。
hook中文意思是钩子,我的理解是关卡,就是在操作过程中,在前面或后面进行一些检查。
例如,使用python编程,没有符合相关的编程格式,如果使用了pre-commit钩子,提交不能成功。
当然,需要按照不同语言进行设置和配置一些文件。
对仓库中的对象提供内容或类型和大小的信息
git cat-file [options]