Git可以说是目前最优秀的分布式版本控制系统,并且使用Git还能提升逼格,何乐而不为啊。所以记录下来学习git的过程,以方便以后查阅。
# 本机环境
# 基础知识普及
Git系统中一共有三个区域:
创建仓库主要分两种:
1. 对本地文件夹进行git管理
2. 克隆远程仓库
初始化本地文件夹为git仓库(在e:/gitest/first目录下创建)
$ git init
Initialized empty Git repository in e:/gitest/first/.git/
把文件修改添加到暂存区
$ git add hello.txt
查看当前工作状态
$ git status
克隆远程仓库(第一个参数为远程仓库地址,
https
或ssh
地址都可以。第二个参数为本地目录,不填则默认为当前目录)
$ git clone https://github.com/lyszZi/remote.git /e/gitest/remote
commit用来提交修改到仓库中。每次commit后,暂存区的内容都会被清空。这个命令中的参数
-a
意味着提交工作区中所有修改过的文件以及删除的文件(但不包括新添加的文件),不使用-a
则默认只提交暂存区中的内容。此外,还可以使用-m
给commit添加注释,提高可读性。
$ git commit -a -m "add hello.txt"
多个分支的概念实际上是基于某次提交(commit)创建的两个不同的记录,每个分支上的提交都是基于该分支的最后一次提交。
创建分支可以是基于某个已有的分支,也可以是基于某次提交(commit)。
创建一个新分支development,这种创建分支方法是基于当前分支的最新提交来创建的。
$ git branch development
基于某个特定的提交节点创建分支,首先我们需要知道该节点的标识(随后会介绍,这里只需要知道每个commit都有一个40位的唯一的标识)。
$ git branch another 86f756645
切换当前工作区为某个分支。第二个命令为创建一个新的分支并切换工作区为该分区,其效果可以等价于连续执行
branch
和checkout
指令。
$ git checkout 分支名称
$ git checkout -b 分支名称
等价于:
$ git branch 分支名称
$ git checkout 分支名称
查看当前仓库中有哪些分支。
$ git branch
$ git branch --list
删除分支。这里的删除分支只是删除分支名字而已(即使用
git branch
无法再查看到该分支名称)。但是这个分支中所有已提交的内容都不会被删除,接下来会介绍如何恢复这些“无引用”的分支。
$ git branch -d 分支名称
merge的语义即为 merge from,意味着将指定的分支合并到当前分支。
先用checkout切换到要合并的分支。然后执行
git merge
指令把目标分支合并到当前分支。
$ git checkout master
$ git merge development
以上的指令把分支development合并到了分支master中,如果合并过程发生冲突(两个文本文件内容不一致),系统会以特殊的格式插入到文本中,一般的冲突格式如下:
<<<<<<< HEAD
third
=======
add dev third
>>>>>>> development
PS:解决冲突的方式只能是手工修改冲突内容,然后再重新提交文件.如果合并的文件没有发生冲突,则会自动将合并的内容提交
git merge指令还有以下常见的参数选项:
* --commit
:即merge后自动进行commit。系统默认为该选项。
* --no-commit
:即merge后只合并工作区中的内容,不进行commit操作。
* -m
:merge后自动提交时添加的注释。
rebase意为改变当前分支的基点。
$ git checkout development
$ git rebase master
以上的指令意为,更改当前分支development将以最新的master分支最为基点。也就是说最新的master中的内容会合并到development中。如果合并的过程中发生了冲突,将会和
merge
操作一样处理冲突问题。
cherry-pick意为寻找最好的樱桃。即在众多的对象中挑选最优的一个。
把标识为02a7e2edc的提交合并到当前分支中。
$ git cherry-pick 02a7e2edc
PS: Git中存储的提交都是以快照(snapshot)的形式,而不是svn的增量(delta)形式,所以Git不需要进行额外的增量运算就可以直接合并或恢复文件,这极大加快了合并速度。
reset将当前分支的头(HEAD)恢复到之前某个提交节点。换种说法就是忽略或者丢弃最近的某些提交操作。
reset有两种模式,分别为软复位和硬复位。
软复位到HEAD的前两个提交节点。
$ git reset --soft HEAD~2
软复位到某个特定提交节点。需要获得该提交节点的标识。
$ git reset --soft 02a7e2edc
# 软复位后一般都伴随一次commit操作来完成操作。
硬复位。硬复位意味着丢弃之前的修改,软复位意味着合并之前的修改。
$ git reset --hard HEAD``
#复位操作不仅能往前复位提交节点,还能向后复位,只要知道提交节点的标识即可。
恢复“无引用”提交的方法主要有三种,分别是针对于三种不同原因导致的无引用情况后的处理情况。但是无论是哪一种方式,首先都要先找出“无引用”提交节点的标识!!接下来只要在基于该提交节点新建一个分支就可以了。
git log
: 在reset前调用过git log
查看记录,reset之后可以根据之前的log记录恢复到某个之前的节点。 git reflog
: 列出HEAD的变化历史。系统中只有一个HEAD。这个方式适合同一个分支中由于reset而引起的“无引用”情况。只要通过git reflog找到该“无引用”提交节点的标识,在创建分支即可。git fsck -full
: 列出所有未被引用的提交。适合于删除某个branch并手动删除.git/logs/
目录而引起的“无引用”情况。PS:手动删除.git/logs/
目录有风险,不推荐!要慎重!
remote用于和远程仓库进行交互。本地远程仓库有两个分支
在本地建立一个远程仓库的引用。该命令只是在本地建立一个引用,本地还没有任何别的远程仓库的内容。
$ git remote add name git_url
PS:如果是没有关联远程仓库的本地仓库,则需要使用该命令来与远程仓库建立连接;如果本地仓库为clone远程仓库的,则会默认有一个对远程仓库master分支的引用origin。
查看本地仓库有哪些远程仓库引用。
$ git remote
$ git remote -v
查看远程仓库(origin)中的分支。
$ git remote show origin
将本地内容push到远程仓库中。src代表本地分支名称,des是远程分支名称。不写des则默认src与des相同。
$ git push origin src:des
删除一个远程分支,把一个空的内容push到远程分支,就意味着删除该分支。
$ git push origin :des
克隆远程仓库。更多可查询fetch,pull。
$ git clone [email protected]:lysongzi/remote.git
创建一个远程仓库分支的本地跟踪分支。
$ git checkout -b dev origin/development
//自动创建一个名为name的本地分支,作为origin/name的跟踪分支。
$ git checkout --track origin/name
接下来介绍两个应用场景。一个为将本地仓库同步到一个新建的远程仓库,另一个为从远程仓库同步内容并创建本地仓库。可以参考此远程多人协作模式(传送门-多人协作模式)。
场景1.(需要ssh连接—传送门-配置ssh密钥)
//创建一个远程仓库的引用
$ git remote add origin [email protected]:lysongzi/remote.git
//将本地的某个分支push到远程仓库中
$ git push origin master
$ git push origin development
//从现在开始,只要本地做了提交commit,就可以通过push命令把分支的最新修改推送到远程仓库中。
情景2.
//使用clone克隆远程仓库到本地。
$ git clone https://github.com/lysongzi/remote.git
//此时本地将只有远程仓库的master分支,我们再创建对development分支的引用。
//origin为系统创建的对远程仓库的master分支的本地跟踪分支。
$ git checkout -b dev origin/development
//然后我们就可以在本地上对各个分支进行修改,提交,最后选择性把分支的修改push到远程仓库对应分支即可。
然后再实际多人协作过程中,别人也会向远程仓库的某个分支中提交他们的修改。有时候,我们的修改和别人的修改就会产生冲突。
$ git push origin dev
To [email protected]:lysongzi/remote.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to '[email protected]:lysongzi/remote.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
就是说别人更新了修改,和我们的修改产生了冲突。根据Git提示,我们需要先pull一些最新的修改,如果有冲突,则按冲突解决方法解决冲突,然后重新提交。
$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:lysongzi/remote
fc38031..291bea8 development -> origin/development
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 <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=<remote>/<branch> development
然而这时候还是出现了报错,根据提示原因是没有指定本地dev分支与远程origin/dev分支的链接。
$ git branch --set-upstream-to=origin/development development
再次执行pull操作。
$git pull
git pull
指令会同步本地仓库和远程仓库的内容,并把有冲突的地方标识出来。然后解决了冲突后,提交,再push则没有问题了。
#多人协作模式总结
首先,可以试图用 git push origin branch
推送自己的修改;
如果推送失败,则说明远程分支比你的本地更新,需要先用 git pull
试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用 git push origin branch
推送就能成功!
如果 git pull
提示 “no tracking information”
,则说明本地分支和远程分支的链接关系没有创建,用命令 git branch --set-upstream-to=<remote>/<branch> 本地branch
来创建。
git的配置主要有两种方式,一种是通过命令行来配置,还有一种则是修改配置文件。更多参考 传送门—Git配置
且系统中主要有三种配置文件。这三种文件优先级为 3>2>1
。
/etc/gitconfig
: 全局配置。~/.gitconfig
: 适用于当前用户。.git/config
: 适用于当前工作仓库。命令行分别为:
$ git config --system name value
$ git config --global name value
$ git config --local name value
配置基本信息(提交者名称,邮箱)。
$ git config user.name 'xxxx'
$ git config user.email '[email protected]'
查看当前配置,查看某个属性的值。
$ git config -l或--list
$ git config prop_name
查看各个命令的完整用法。
$ git help command-name
限制记录输出。
$ git log -l -5
每条Log只显示一行。
$ git log --pretty=oneline
查看两个提及节点间的Log,since和untill为提交节点对应的标识。
$ git log since...untill
查看两个分支的不同。
$ git diff 分支1 分支2
查看后者(dev)与前者(master)共同父节点之间的差异。
$ git diff master...dev
比较当前工作区内容与上一个提交之间的差异。
$ git diff HEAD
比较当前分支的暂存区和上一个提交之间的差别。如果当前修改没有被添加到暂存区,输出为空。
$ git diff --cached HEAD
该指令作用与git add
相反。
移除文件或目录。-r递归删除,-f强制删除。
$ git rm -rf 文件/目录
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的
查看所有tag。还可以使用通配符查询标签。
$ git tag
$ git tag -l 'v1.*'
首先,切换到需要打标签的分支上。然后创建标签即可。
$ git tag v1.0
对某个提交打标签。
$ git tag v1.1 6224937
标签不是按时间顺序列出,而是按字母排序的。可以用git show 查看标签信息。
$ git show v1.0
指定标签信息。
$ git tag -a v1.0 -m "注释"
删除标签。
$ git tag -d v1.0
1.《Android内核剖析》第四章
2.廖雪峰个人网站-git教程