基本用法

生成ssh key

1
2
3
4
5
# 使用该命令生成key
ssh-keygen -t rsa -C "your_email@youremail.com"
# 生成后将.pub里的内容复制到GitHub的key中。之后使用以下命令进行验证是否添加ok。
ssh -T git@github.com
# 如果出现`You've successfully authenticated, but GitHub does not provide shell access `,表示连接成功。

使用http连接的方式

如果使用http连接,而不是ssh,那么每次拉取提交都需要输入用户名和密码,非常麻烦,可通过下面的命令来存储用户名密码,避免每次输入。

1
git config --global credential.helper store

上面命令输入后,在.gitconfig文件中会多出下面的信息。

1
2
[credential]
helper = store

在输入上面的命令后,再次拉取更新时输入账号密码,之后账号密码就会存储下来,之后就不用再输入账号密码了。

进行基本配置

1
2
3
4
5
6
7
# 设置用户名和相应的邮箱,分支提交信息中将会展示这些信息进行区分
git config --global user.name ""
git config --global user.email ""

# git在提交代码时会自动把CRLF转换为LF,在拉取代码时会自动将LF转换为CRLF。在Windows开发时,就设置该选项core.autocrlf为真,这样拉取代码时,就会自动进行转换
# 更详细的可以参见 progit的 core.autocrlf 部分说明
git config --global core.autocrlf true

设置命令别名

1
2
3
4
5
6
7
# 设置git status 别名为 git st
git config --global alias.st status
# 一些常见的别名设置
# 设置 git status 为 git st
git config --global alias.st status
# 设置 git log ... 为 git lg
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

创建仓库

1
2
# 假设仓库名为pot
git init pot

克隆仓库

1
2
3
4
5
# 本地仓库
git clone /path/to/repository

# 网络仓库
git clone sername@host:/path/to/repository

添加和提交

1
2
3
4
5
6
7
# 添加到暂存区
git add <filename>
# 添加所有文件到暂存区
git add *   

# 提交到仓库
git commit -m "代码提交信息"

修改文件或文件夹名称

1
2
3
4
5
6
# 该命令用来改名
$ git mv file_from file_to
# 上面这个命令相当于下面三个命令
$ mv README.md README
$ git rm README.md
$ git add README

删除文件

1
2
3
4
# 删除文件
git rm <filename>
# 之后进行commit
git commit

该命令从版本库中删除某个文件,如果误删的话,可以使用撤回命令(下方有说明)将操作撤回。

比较差异

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 比较工作区和暂存区的差异
git diff
# 比较工作区与仓库文件之间的差异
git diff <filename>
# 比较工作区和本地仓库指定版本的差异,HEAD~1表示当前版本,HEAD~2表示上一个版本
git diff HEAD~n
# 也可以用commit id,commit-id可以通过git log查看
git diff <commit-id>
# 比较两次提交之间的差异
git diff <commit-id1> <commit-id2>
# 比较两次提交之间某个文件的差异
git diff <commit-id1> <commit-id2> <filename>

分支基本操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 列出本地所有分支
git branch 
# 列出远程所有分支
git branch -r 
# 列出本地和远程的所有分支
git branch -a
# 创建一个叫"feature_x"的分支,并切换过去
git checkout -b feature_x
# 从远程拉取dev分支到本地
git checkout -b dev origin/dev
# 从某个commit id上创建分支
git checkout -b dev <commit-id>
# 切换回主分支
git checkout master
# 将新建的分支删除掉
git branch -d feature_x
# 删除远程的分支
git branch -r feature_x
# 重命名分支
git branch -m <oldname> <newname>
# 将本地分支推送到远程,如果不推送,别人也看不到
git push origin <branch>

更新与合并分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 更新远程分支到本地
git pull
# 这里需要注意的是,git pull等同于以下两个命令
git fetch
git merge
# 由于merge有时候会自动生成一些额外的不需要的信息,因此可尝试使用下面两个命令
git fetch
git rebase
# 合并branch分支到当前分支
git merge <branch>
# 在发生冲突时,需要手动修复,修复后add修复后的文件并提交
git add <filename>
git commit -m ""

关于rebase的用途,这里可参考两篇文章:

  1. Rebase 代替合并
  2. 彻底搞懂 Git-Rebase

推送到远程仓库

1
2
3
4
5
# origin 是远程仓库名(默认的),master是本地分支名
git push origin master

# 将本地仓库与远程仓库相关联
git remote add origin http://192.168.10.222:8888/test/test.git

打标签

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 给id为1b2e91d的提交id打tag,其中id可通过`git log`查看
git  tag 1.0.0 1b2e91d
# 本地删除某个标签
git tag -d 1.0.0
# 推送某个标签到远程
git push origin 1.0.0
# 或者推送所有的标签到远程
git push origin --tags
# 删除远程的tag
git tag -d 1.0.0 # 先删除本地的标签
git push origin :refs/tags/1.0.0 # 推送删除远程的标签

log

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查看log
git log
# 查看某一个人的log
git log --author=bob
# 将log精简到1行
git log --pretty=oneline
# 展示所有分支的名字和标签
git log --graph --oneline --decorate --all
# 查看哪些文件改变了
git log --name-status

撤销修改

1
2
# 撤销工作区的修改
git checkout -- <filename>

这里的撤销只针对工作区(注意区分工作区、暂存区、版本库概念间的区别),针对工作区的撤销实际上也要分两种情况。

  1. 一种是工作区修改后还没有被放进暂存区,那么执行该命令后,工作区将会于跟版本库中的一摸一样。
  2. 一种是工作区之前已经添加到了暂存区,之后又做了新的修改,那么执行该命令后,将会回到跟暂存区中一样的状态。
1
2
# 撤销暂存区中的修改
git reset HEAD <filename>

这条命令执行后,暂存区的修改就会被撤销掉,同时将暂存区的修改放回到工作区,之后再使用git checkout -- <filename>命令将工作区的内容给撤销掉。

1
2
3
4
5
6
7
8
# 回退至版本库的上一个版本
git reset --hard HEAD^
# 回退至版本库的上上个版本
git reset --hard HEAD^^
# 回退至版本库的前100个版本
git reset --hard HEAD~100
# 回退至某一个确定的版本 1094a(commit id)
git reset --hard 1094a

这里需要注意的是,在回退至较老的版本后,再使用git log命令查看日志就不会再看到最新的提交日志了,如果想再回到最新的提交该咋办?使用git reflog命令可以查看自己执行的每个命令情况,通过该命令可以再找回之前更新的提交以及对应的commit id,之后就又可以回来了。

1
2
3
# 放弃本地的所有提交,获取服务器上最新的版本
git fetch origin
git reset --hard origin/master

还没有使用过,暂时并不清楚哟。

注意,以上修改都仅限于本地回退,如果错误的提交已经到了远程仓库,那么回退的方式就不一样了。

常规来说,回退远程仓库有两种方式。

方法1

首先在本地使用git reset --hard 方式进行回退,回退完之后,通过git push --force命令强制推送本地分支到远程分支。但这种方式有个弊端,即如果有其他人已经在远程分支提交了新的代码,而你的代码又落后于他的代码,在你回退之后,已经把他人的提交给“删除”了,这样强制推送到远程后,也会将别人的提交给删除掉。因此这种方式比较适合自己独立开发的情况。

方法2

可以使用git revert命令回退某次提交,其用法参考这篇文章:远程仓库版本回退方法

1
2
3
git revert HEAD                     //撤销最近一次提交
git revert HEAD~1                 //撤销最近两次的提交
git revert 0ffaacc                  //撤销0ffaacc这次提交

git revertgit reset命令不同,git revert命令不会删除某次的提交,而是仅仅回退某次的代码,然后需要你重新提交,这样就会产生一个新的提交。如果是回退最早前的一次提交,再次提交时就会产生冲突,这样在解决冲突后重新提交就行了。这样不会影响到其他人。

从svn使用过来的话,会感觉到git revert的方式更加亲切熟悉,svn的每次回退都是需要进行一次的新的提交,确保每次操作都有记录,也方便回溯定位。

总的来说,还是更加推荐这种方式进行版本回退,不影响他人,从svn使用过来的话也会更加熟悉这种方式。

储藏功能

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 临时将工作区的内容给放到另外一个临时空间
git stash
# 查看当前存储的临时空间现场
git stash list
# 从stash恢复临时存储的内容
git stash apply  # 恢复,并不删除stash中的内容
git stash drop   # 删除stash中的内容
# 从stash中弹出之前保存的内容,与上面两条命令执行结果相同
git stash pop   # 恢复,并删除
# 恢复指定的一次隐藏
git stash appley stash@{0}

子模块功能

一个工程添加新的子模块:

1
2
# 添加<remote_path>作为该工程的子模块
git submodule add <remote_path>

上述命令执行完毕后,会自动将对应的仓库的最新版本拉取下来,这个时候子模块仅仅是在本地,通过git status可以看到有未提交的更新,这个时候主仓库还需要进行提交才能够将子模块的引用信息给存储控制起来。

在拉取一个包含子模块的仓库时,需要使用下面的命令:

1
2
3
4
5
6
# 拉取包含子模块的仓库
git clone <remote_path> --recursive
# 或者使用下面3条命令
git clone <remote_path>
git submodule init
git submodule update 

若子模块有更新,在主仓库中想使用最新版本的子模块,需要执行命令进行更新。

1
2
3
4
5
# 在主仓库中执行
git submodule update --remote
# 或是在子模块目录中执行
git fetch 
git merge origin/master

在更新完毕后,记得在主仓库中进行提交更新,否则的话子模块的更新仅在本地,并不会被保留在版本库中。

如果想回退子模块版本到某个指定的版本,那么直接在子模块目录中使用git reset --hard <commmit_id>命令切换到某个版本即可。之后在主目录中提交更新子模块对应的版本即可。

在回退回某个版本并更新后,如果有别人在使用另外一个仓库,他在pull更新主仓库后,通过status会发现子模块的版本与远程的不匹配,这个时候可以在主仓库中使用命令git submodule update --checkout或是命令git submodule update更新子模块版本到对应的版本。

如果在主仓库中想进入子模块直接修改子模块的代码并提交,这里需要注意的是,子模块中的分支是游离的分支,没有被版本控制,因此在修改前需要先切换到对应的分支上来。

如果要修改子模块的路径,那么直接修改.gitmodules文件中的url路径,之后使用命令git submodule sync来更新.git/config目录下的文件,之后执行git submodule –remote命令更新子模块就好了,如果有冲突,就把之前的子模块文件夹删了再拉。

忽略特殊文件

在git工作的根目录下创建.gitignore文件,然后将忽略的文件名填进去,git就会自动忽略这些文件。

自己一般不需要重头写.gitignore文件,github已经提供了各种情况下的配置,可以在https://github.com/github/gitignore进行下载。

将文件添加到忽略文件中后,再手动add被忽略的文件就会被提示,这个时候可以使用git add -f <filename>来强制添加。或者是发现.gitignore写的有问题,因此可以使用命令git check-ignore -v <filename>来查看是哪条策略导致文件被忽略的。

Linux升级最新Git

使用源码编译,文档参考:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git/

参考链接

  1. git - 简明指南
  2. Git客户端使用
  3. 《git小书》
  4. 《pro git 2》
  5. 解决每次git pull需要输入用户名密码的问题