配置命令
ssh-keygen -t rsa -C "youremail@example.com"
可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,将id_rsa.pub内容提交到github或gitee
git config [--global]
git config --global user.name "Your Name"
git config --global user.email "email@example.com"
git config --global credential.helper store
基本命令
项目开始
git clone [https://url/repo_name](https://url/repo_name)
从远程仓库clone到本地,对于新项目的常用方法——先在github或gitee新建仓库再拉到本地工作,也可用下面的git init
git init
初始化目录为git仓库, 然后可关联远程仓库,git remote add origin git@github.com:your_account/your_project.git
远程库一般取名origin,关联后加-u参数推送一次,即可关联本地与远程同名分支,git push -u origin master
git remote rm origin
,可解除本地与远程库关联,但不影响本地库与远程库的内容。
版本控制
git add
向staged区加入文件
git commit -m<message></message>
将staged区的文件提交到本地版本库
git commit -a -m<message></message>
跳过add直接将工作区修改提交
git rm
删除版本库中一个文件
git push
- 无参数,将本地版本库当前分支推到远程库对应分支(一般同名),查看远程状态参考远程管理与协作部分
- origin,同上,远程默认为origin
- origin master,将本地master分支推到远程库对应分支(一般同名)
- origin master : refs/for/master,将本地master分支推到远程库master分支
- origin : refs/for/master,将空分支推到远程库master分支,等于是删除远程库master分支
- --all origin,将本地所有分支推到远程库
git status
查看本地库状态,staged,已commit的等信息
git diff
查看文件差异
git log [--pretty=oneline] [--graph]
查看日志
git reflog
查看命令历史
版本游历
git checkout --
丢弃工作区的修改
- 如add过,从staged区取回文件覆盖工作区文件
- 如未add过,用提交过的最后文件覆盖工作区文件
git reset [--hard/soft/mixed]
【git reset的本质是:移动HEAD以及它所指向的branch,所以<commit_id>影响的是下一次commit的位置,hard/soft/mixed参数影响工作区与staged区的内容】</commit_id>
将HEAD指针移到某次提交,<commit_id>可以用log, reflog查看,也可用 HEAD代表最后一次提交,HEAD代表再上一次提交,HEAD^代表上上次提交,HEAD~10代表向前回溯10个提交,</commit_id>
- --hard: 恢复后staged区清空,工作区版本恢复到指定<commit_id>的内容</commit_id>
- --soft : 工作区保持不变(可以再次add),staged区不变(可以再次commit,但是提交后的版本接在<commit-id>后)</commit-id>
- --mixed 或缺省: 工作区保持不变(可以再次add),staged区清空
注意回退到历史版本后,如再次提交,将导致那个历史版本以后的历史提交都失效,相当于从那个起点重新开始。如将reset改为revert命令,则将要回退的历史版本生成一个一样的最新版本,并将HEAD指向它。因此尽量不要回退,或回退查看历史文件后要回到当前版本,再继续工作。常用HEAD,即取消最近的工作回到最后的提交。
git reset HEAD
默认mixed,即将staged区该文件删除,相当于取消add该文件,工作区文件未变,staged区该文件消失,版本库保持最后commit的状态,要取消工作区修改,再次使用git checkout -- <file>将其恢复为最后提交版本</file>
分支管理
git branch
查看分支
git branch<name></name>
创建分支
git checkout <name>
或者git switch <name></name></name>
切换分支,建议用switch,避免checkout命令的歧义
git checkout -b <name>
或者git switch -c <name></name></name>
创建+切换分支,建议用switch,避免checkout命令的歧义
git merge<name></name>
合并某分支到当前分支 , --no-ff参数保留历史分支
git cherry-pick
从某分支上的提交合并到当前分支,如某个小bug修复
git branch -d<name></name>
删除分支,大写-D强制删除未合并的分支
git rebase
把本地未push的分叉提交历史整理成直线
首先通过简单的提交节点图解感受一下rebase在干什么
构造两个分支master和feature,其中feature是在提交点B处从master上拉出的分支
master上有一个新提交M,feature上有两个新提交C和D
此时我们切换到feature分支上,执行rebase命令,相当于是想要把master分支合并到feature分支(这一步的场景就可以类比为我们在自己的分支feature上开发了一段时间了,准备从主干master上拉一下最新改动。模拟了git pull --rebase的情形)
这两条命令等价于
git rebase master feature git checkout feature git rebase master
下图为变基后的提交节点图,解释一下其工作原理:
feature:待变基分支、当前分支
master:基分支、目标分支
官方原文解释(如果觉得看不懂可以直接看下一段):当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。
结合例子解释:当在feature分支上执行git rebase master时,git会从master和featuer的共同祖先B开始提取feature分支上的修改,也就是C和D两个提交,先提取到。然后将feature分支指向master分支的最新提交上,也就是M。最后把提取的C和D接到M后面,注意这里的接法,官方没说清楚,实际是会依次拿M和C、D内容分别比较,处理冲突后生成新的C’和D’。一定注意,这里新C’、D’和之前的C、D已经不一样了,是我们处理冲突后的新内容,feature指针自然最后也是指向D’
通俗解释(重要!!):rebase,变基,可以直接理解为改变基底。feature分支是基于master分支的B拉出来的分支,feature的基底是B。而master在B之后有新的提交,就相当于此时要用master上新的提交来作为feature分支的新基底。实际操作为把B之后feature的提交先暂存下来,然后删掉原来这些提交,再找到master的最新提交位置,把存下来的提交再接上去(接上去是逐个和新基底处理冲突的过程),如此feature分支的基底就相当于变成了M而不是原来的B了。(注意,如果master上在B以后没有新提交,那么就还是用原来的B作为基,rebase操作相当于无效,此时和git merge就基本没区别了,差异只在于git merge会多一条记录Merge操作的提交记录)
上面的例子可抽象为如下实际工作场景:远程库上有一个master分支目前开发到B了,张三从B拉了代码到本地的feature分支进行开发,目前提交了两次,开发到D了;李四也从B拉到本地的master分支,他提交到了M,然后合到远程库的master上了。此时张三想从远程库master拉下最新代码,于是他在feature分支上执行了git pull origin master:feature,即把远程库master分支给rebase下来,由于李四更早开发完,此时远程master上是李四的最新内容,rebase后再看张三的历史提交记录,就相当于是张三是基于李四的最新提交M进行的开发了。(但实际上张三更早拉代码下来,李四拉的晚但提交早)
远程管理与协作
【本地分支与远程分支独立管理,本地新建的分支如果不推送到远程,对其他人就是不可见的】
- 查看远程库信息,使用
git remote -v
- 从本地推送分支,使用
git push origin branch-name
,如果推送失败,先用git pull抓取远程的新提交 - 要从远程拉取并创建本地分支,可使用
git checkout --track origin/branch-name
- 要在本地创建不同的名字和远程分支对应,可使用
git checkout -b branch-name origin/branch-name
,不推荐,本地和远程分支的名称最好一致 - 建立本地分支和远程分支的关联,使用
git branch --set-upstream branch-name origin/branch-name
- 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
- 增加远程仓库为当前仓库的模块:在某个子目录下执行
git submodule add 远程url
,对于有子模块的项目,clone时要加上--recursive 参数迭代下载,或者执行
git submodule sync git submodule update --init --recursive
TAG
-
git tag <tagname>
用于新建一个标签,默认为HEAD,也可以指定一个commit id;</tagname> -
git tag -a <tagname>-m "blablabla..."
可以指定标签信息;</tagname> -
git tag
可以查看所有标签。 -
git push origin <tagname>
可以推送一个本地标签;</tagname> -
git push origin --tags
可以推送全部未推送过的本地标签; -
git tag -d <tagname>
可以删除一个本地标签;</tagname> -
git push origin :refs/tags/<tagname>
可以删除一个远程标签。</tagname>
保留现场
git stash
git stash list
git stash drop
git stash [apply|pop] [stash@{0}]
pop = apply + drop