本文借鉴廖雪峰老师博客而整理的git相关总结,以方便自己查阅使用。

1.Git用户设定及其配置

1.Git配置

Git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量。这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:

  • /etc/gitconfig 文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
  • ~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
  • 当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。
2.用户信息
1
2
$ git config --global user.name "runoob"
$ git config --global user.email test@runoob.com
  • 如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。
  • 如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。
3.查看配置信息
1
git config --list

2.版本库的创建

1
2
3
4
git init # 初始化一个仓库
git add <file1> <file2> ... <filen> # 添加文件,并将文件修改添加到暂存区
git commit -m <message> # 添加文件到Git仓库,提交修改,将暂存区的所有内容提交到当前分支
git commit -am "committed message" # 一次提交所有在暂存区中改动的文件到版本库

3.查看历史

1
2
git log # 显示从最近到最远的提交日志 -- 显示最近的3次提交
git log --pretty =oneline # 简略输出

4.版本回退

gitHEAD代表的是当前版本,可以将HEAD理解为一个指针(指向版本)。上一个版本是HEAD^,上上版本为HEAD^^…,若向上100个版本则为HEAD^100.

1
2
3
git reset --hard HEAD^ # 返回至上一个版本
git reset --hard 版本号 # 达到指定版本
git reflog # 记录着每一次的命令(查看历史命令)

5.工作区与暂存区

  • 工作区:包含整个项目的文件夹(.git隐藏文件夹不包含在工作区内)。

  • 版本库:工作区中的隐藏目录.git,不算工作区,而是Git的版本库。

    Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。具体结构分析参考廖雪峰此节。

    其中在创建Git版本库时,Git自动为我们创建了唯一一个master分支。

  • 暂存区:英文叫stage, 或index。一般存放在 “.git目录下” 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。

1
git status # 查看工作区的状态

Git版本控制下的文件状态的三种状态:

  • 已提交(committed):该文件已经被安全地保存在本地数据库中了。
  • 已修改(modified):修改了某个文件,但还没有提交保存。
  • 已暂存(staged):把已修改的文件放在下次提交时要保存的清单中。

6.修改操作

注意:Git跟踪管理的是修改而非文件。每次需要将工作区的修改添加入到暂存区中,然后再进行commit,将暂存区中跟踪的修改的进行全部的提交。

其中:

1
2
3
4
git diff HEAD -- <file> # 可以查看工作区和版本库里面最新版本的区别
git diff ANode BNode 用于比较项目中任意两个版本(分支)的差异,即A B两个节点之间的差异
同理,可以比较两个分支之间的差异
git diff --cached # 比较当前索引和上次提交间的差异 以及在--name--status,只看文件列表

几种撤销修改方式:

  1. 未添加到暂存区

    1
    git checkout -- <file> # 让这个文件回到最近一次git commit或git add时的状态
  2. 添加到暂存区未commit到分支

    1
    2
    git reset HEAD <file> # 将暂存区的修改撤销(unstage) -- 即回到场景1(这里HEAD表示最新的版本)
    git checkout -- <file> # 同场景1,丢弃工作区的修改
  3. 添加到分支中,未推送至远端

    1. 版本回退
    2. 进行情况2中的两步

7.文件删除

git add后,即添加到版本库之后。见以下操作:

1
2
3
# 以test.txt文件为例
git add test.txt # 提交到版本库
rm test.txt # 删除工作区的文件

此时就会出现工作区和版本库不一致的情况。通过git status命令查看工作区的状态。此时有两种选择:

  1. git rm test.txt 
    git commit -m "remove test.txt" # 提交至分支中
    
    1
    2
    3
    4
    5

    此时,文件就从版本库中被删除。

    2. ```bash
    git checkout -- test.txt
    误删。但是版本库中存在,可以通过以上命令将其恢复到最新版本。 `git checkout`是用版本库里的版本替换工作区的版本,故无论工作区是修改还是删除,都可以进行还原。

注意:从来没有被添加到版本库就被删除的文件,是无法恢复的。同时恢复文件只能恢复到最新版本(commit的最新一次),会丢失最近一次提交后修改的内容。

8.远程库添加的两种方式

前置工作

在本地创建密匙,添加到GitHub上,这样便可以将本地与自己的GitHub账号关联起来。

git-ssh
1
ssh-keygen -t rsa -C [邮箱]

其中的邮箱对应的是Git设置的邮箱。

【解释】:ssh-agent 是一种控制用来保存公钥身份验证所使用的私钥的程序,其实 ssh-agent 就是一个密钥管理器,运行 ssh-agent 以后,使用 ssh-add 将私钥交给 ssh-agent 保管,其他程序需要身份验证的时候可以将验证申请交给 ssh-agent 来完成整个认证过程,即进行公钥和秘钥的匹配。

1
eval "$(ssh-agent -s)"

添加生成的SSH keyssh-agent:

1
ssh-add ~/.ssh/id_rsa

最后登录GitHub,添加ssh,将id_rsa.pub(这里注意是添加公钥,不要添加成了秘钥)添加入GitHub设置中的SSH中。至此,本地和GitHub的关联完成。

  1. 将本地创建的Git仓库同步至GitHub上。

    1
    git remote add origin git <ssh路径> # 添加成功后远程库的名字就是origin(默认)
    1
    git push -u origin master # 将本地库所有内容推送到远程库上

    注意:git push命令实际将当前分支master推送到远程;由于远程库是空的,在第一次推送master分支时,加上-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时刻简化命令。即:

    1
    git push origin master
  2. 直接clone远程库,将 文件添加至到本地,再将本地库推送至远端。

    1
    2
    3
    4
    5
    git clone <ssh地址> # 带具体仓库
    /-------------修改完文件以后-----------/
    git add <file>
    git commit -m <message>
    git push origin master

9.分支管理

具体的理解与解释,可以参考廖雪峰分支管理一节,这里只做命令的汇总。

9.1创建dev分支,再切换到dev分支
1
2
3
4
5
6
git checkout -b <分支名> # -b参数代表创建并切换
/----等价于以下两句----/
git branch dev
git checkout dev
# 或者
git switch -c <name>
9.2 查看分支
1
2
3
git branch # 查看本地工程所有分支
git branch -r # 远端服务器分支
git branch -a # 远端服务器和本地服务器分支

会列出所有分支,当前分支前面会标有*号。

9.3分支切换
1
2
3
git checkout [分支] # 分支1切换分支2
# 或者
git switch <name>
9.4合并分支
1
2
# 用于合并指定分支到当前分支。
git merge <指定分支>
9.5删除分支
1
2
git branch -d <分支名>
git branch -d -r branch_name # 删除服务端分支 -> 推送该分支到远端服务器 git push origin:branch_name

HEAD指向的就是当前分支,每一次提交,master分支都会向前移动一步。

9.6 switch命令(用于切换分支)
1
2
git switch -c <分支名> # 创建并切换到新的dev分支上
git switch <分支名> # 直接切换到已有的分支上

10.解决冲突

1
2
3
4
5
6
7
8
9
10
11
12
13
*   51af5f6 (HEAD -> master) conflict fixed2
|\
| * 30a56f8 conflict feature1
* | 5e4ae6e conflict add fixed
* | d4fa5fc conflict fixed
|\|
| * a4c77c0 feature11
* | cb7d18b & feature11
|/
* 44e1c04 feature1
* bee796d (origin/master, origin/HEAD) 分支练习
* ba3dee6 测试提交
* 0caf900 Initial commit

Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。

查看分支合并图:

1
2
git log --graph --pretty=oneline --abbrev-commit # 详细版
git log --graph # 简略版

11.分支管理

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit。这样,从分支历史上就可以看出分支信息。

1
2
3
4
5
6
git merge --no-ff -m "message" branch
# 例子
sh-3.2# git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
test.txt | 1 +
1 file changed, 1 insertion(+)

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

目的:为了协同开发,保证我们自己一直能够使用自己的分支,不像之前那样合并完后就删除了。需要在哪个分支上创建分支,就先切换到该分支上,创建分支。

保存工作现场:

1
git stash

查看工作现场:

1
git stash list

回复工作现场:

1
2
3
4
5
# 1.恢复工作现场 2.删除stash内容
git stash apply
git stash drop
# 2.恢复的同时,删除stash内容
git stash pop

复制一个特定的提交到当前分支(bug修复复制):

1
git cherry-pick <commit>

12.Feature分支

用于新功能的分开,开发一个新模块,最好创建一个feature分支,在此上面开发,完成后,合并,最后删除该feature分支。

强制删除:

1
git branch -D feature-vulcan

13. 协作开发

查看远程库信息

1
2
3
git remote
#
git remote -v

推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:

1
2
git push origin master # 主分支
git push origin dev # dev分支

抓取分支

1
2
3
git clone git@github.com:ssh
git branch # 查看分支
git checkout -b dev origin/dev # 创建远程orgin的dev分支到本地(为了和远程的dev分支对应),创建本地dev分支

经修改commit后推送:

1
git push origin dev

如果产生冲突(最新提交和你试图推送的提交有冲突),先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:

1
2
3
4
5
6
7
8
9
10
11
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 <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

git branch --set-upstream-to=origin/<branch> dev

如果,git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置devorigin/dev的链接:

1
2
3
git branch --set-upstream-to=origin/dev dev

Branch 'dev' set up to track remote branch 'dev' from 'origin'.

如果出现冲突,就解决冲突(更新文件)即可。

多人协作工作模式:

  1. 首先,可以试图用git push origin <branch-name>推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

1
2
git pull origin remote_branch:local_branch # 将远端分支拉取到本地,并和本地分支合并,如果远端和本地分支名相同,可省略本地分支名部分
git fetch origin remote_branch:local_branch # 相比较git pull,没有将更新同本地合并,而是获取远端的更新

14.标签操作

用于新建一个标签,默认为HEAD,也可以指定一个commit id

1
git tag <tagname>

指定标签信息

1
git tag -a <tagname> -m "blablabla..."

查看所有标签

1
git tag

查看标签信息:

1
git show <tagname>

删除标签:

1
2
git tag -d <tagname>
git tag -D <tagname>

标签推送远端:

1
2
git push origin <tagname>
git push origin --tags # 一次性推送全部

删除远程标签,先删除本地,再推送远端

1
git push origin :refs/tags/<tagname>

15.其他

修改最新commit提交的信息:

1
git commit --amend

修改多次的信息:

1
2
3
4
git rebase -i commit_id ## 只能修改commit_id 之前的log message
git rebase -i --root ## 修改第一次及之前的log message
git rebase -i HEAD~2 ## 修改倒数第二次及之前的log message
git rebase -i HEAD~1 ## 修改最后一次提交的log message

未完待续…


Comment