Fork me on GitHub

Git命令

需要学习的东西太多了,很多命令用到时却忘了,分享一个经典的Git 常用命清单,建议收藏,或者收进你的云笔记中,方便用到时查阅。

名词 翻译
workspace 工作区
Index/Stage 暂存区
Repository 仓库区(本地仓库)
Remote 远程仓库

新建代码库

在当前目录新建一个Git代码库

1
$ git init

新建一个目录,将其初始化为Git代码库

1
$ git init [project-name]

下载一个项目和它的整个代码历史

1
$ git clone [url]

添加或删除文件

添加指定文件到暂存区

1
$ git add [file1] [file2]......

添加指定目录到暂存区,包括子目录

1
$ git add [dir]

添加当前目录的所有文件到暂存区

1
$ git add .

添加每个变化前,都会要求确认。对于同一个文件的多处变化,可以实现分次提交

1
$ git add -p

删除工作区文件,并且将这次删除放入暂存区

1
$ git rm [file1] [file2]......

停止追踪指定文件,但该文件会保留在工作区

1
$ git rm --cached [file]

改名文件,并且将这个改名放入暂存区

1
$ git mv [file-original] [file-original]

代码提交到仓库

提交暂存区到仓库区

1
$ git commit -m [message]

提交暂存区的指定文件到仓库区

1
$ git commit [file1] [file2]... -m [message]

提交工作区自上次commit之后的变化,直接到仓库区

1
$ git commit -a

提交时显示所有diff信息

1
git commit -v

使用一次新的commit,替代上一次提交。如果代码没有任何变化,则用来改写上一次commit的提交信息。

1
$ git commit --amend -m [message]

重做上一次commit,并包括指定文件的新变化

1
$ git commit --amend [file1] [file2]...

分支管理

列出所有本地分支

1
$ git branch

列出所有远程分支

1
$ git branch -r

列出所有本地分支和远程分支

1
$ git branch -a

新建一个分支,但依然停留在当前分支

1
$ git branch [branch-name]

新建一个分支,并切换到该分支

1
$ git checkout -b [branch]

新建一个分支,指向指定commit

1
$ git branch [branch] [commit]

新建一个分支,与指定的远程分支建立追踪关系

1
$ git branch --track [branch] [remote-branch]

切换到指定分支,并更新工作区

1
$ git checkout [branch-name]

切换到上一个分支

1
$ git checkout -

建立追踪关系,在现有分支与指定的远程分支之间

1
$ git branch --set-upstream [branch] [remote-branch]

合并指定分支到当前分支

1
$ git merge [branch]

选择一个commit,合并进当前分支

1
$ git cherry-pick [commit]

删除分支

1
$ git branch -d [branch-name]

删除远程分支

1
2
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]

标签管理

列出所有tag

1
$ git tag

新建一个tag在当前commit

1
$ git tag [tag]

新建一个tag在指定commit

1
$ git tag [tag] [commit]

删除本地tag

1
$ git tag -d [tag]

删除远程tag

1
$ git push origin :refs/tags/[tagname]

查看tag信息

1
$ git show [tag]

提交指定tag

1
$ git push [remote] [tag]

提交所有tag

1
$ git push [remote] --tags

新建一个分支,指向某个tag

1
$ git checkout -b [branch] [tag]

查看历史或统计信息

显示有变更的文件

1
$ git status

显示当前分支的版本历史

1
$ git log

显示commit历史,以及每次commit发生变更的文件

1
$ git log --stat

搜索提交历史,根据关键词

1
$ git log -S [keyword]

显示某个commit之后的所有变动,每个commit占据一行

1
$ git log [tag] HEAD --pretty=format:%s

显示某个commit之后的所有变动,其”提交说明”必须符合搜索条件

1
$ git log [tag] HEAD --grep feature

显示某个文件的版本历史,包括文件改名

1
2
$ git log --follow [file]
$ git whatchanged [file]

显示指定文件相关的每一次diff

1
$ git log -p [file]

显示过去5次提交

1
$ git log -5 --pretty --oneline

显示所有提交过的用户,按提交次数排序

1
$ git shortlog -sn

显示指定文件式什么人在什么时间修改过

1
$ git blame [file]

显示暂存区和工作区的差异

1
$ git diff

显示暂存区和上一个commit的差异

1
$ git diff --cached [file]

显示工作区与当前分支最新commit之间的差异

1
$ git diff HEAD

显示两次提交之间的差异

1
$ git diff [first-branch]...[second-branch]

显示今天你写了多少行代码

1
$ git dirr --shortstat "@{0 day ago}"

显示某次提交的元数据和内容变化

1
$ git show [commit]

显示某次提交发生变化的文件

1
$ git show --name-only [commit]

显示某次提交时,某个文件的内容

1
$ git show [commit]:[filename]

代码远程同步

下载远程仓库的所有变动

1
$ git fetch [remote]

显示所有远程仓库

1
$ git remote -v

显示某个远程仓库的信息

1
$ git remote show [remote]

增加一个新的远程仓库,并命名

1
$ git remote add [shortname] [url]

取回远程仓库的变化,并与本地分支合并

1
$ git pull [remote] [branch]

git pull是将线上的新分支和本地的分支合并成一个新的分支,并产生一个新的merge节点。而git pull --rebase则不同:git pull --rebase会把线上的每一个节点和本地的节点进行比较然后逐个进行合并。如果出现冲突那么git会在本地创建一个游离节点,你必须要在这个节点上进行解决冲突操作,然后使用git add ., git rebase --continue 之后才可以进行下一个节点的merge。然后会重复这个过程直到所有节点完成merge。当然如果合并时冲突有点多,这个时候就要注意了是不是团队分工有问题,这时可以使git rebase --abort, 放弃合并,回退到没合并的状态。
在子库进行了提交,输入git status发现git提示子库有更改。代表了线上的子库有变动。需要git submodule update,再次输入git status时,发现工作区很干净。

上传本地指定分支到远程仓库

1
$ git push [remote] [branch]

强行推送当前分支到远程仓库,即使有冲突

1
$ git push [remote] --force

推送所有分支到远程仓库

1
$ git push [remote] --all

撤销恢复

恢复暂存区的指定文件到工作区

1
$ git checkout [file]

恢复某个commit的指定文件到暂存区和工作区

1
$ git checkout [commit] [file]

恢复暂存区的所有文件到工作区

1
$ git checkout .

重置暂存区的指定文件,与上一次commit保持一致,但工作区不变

1
$ git reset [file]

重置暂存区与工作区,与上一次commit保持一致

1
$ git reset --hard

重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变

1
$ git reset [commit]

重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致

1
$ git reset --hard [commit]

重置当前HEAD为指定commit,但保持暂存区和工作区不变

1
$ git reset --keep [commit]

新建一个commit,用来撤销指定commit。后者的所有变化都将被前者抵消,并且应用到当前分支

1
$ git revert [commit]

暂时将未提交的变化移除,稍后再植入

1
2
$ git stash
$ git stash pop

多人工作模式

多人协作的工作模式通常是这样的:
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=origin/<branch-name> <branch-name>
这就是多人协作的工作模式,一旦熟悉了,就非常简单。

查看远程库信息,使用git remote -v;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name, 如果推送失败,先用git pull抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name, 本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用git branch --set-upstream-to=origin/branch-name branch-name;
从远程抓取分支,使用git pull, 如果有冲突,要先处理冲突。

配置别名

我们需要敲一行命令,告诉Git,以后st就表示status
git config --global alias.st status
还有别的命令可以简写,很多人用co表示checkout, ci表示commit, br表示branch;

1
2
3
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch

--global参数是全局参数,也就是这些命令在这台电脑的所有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"

Git .gitignore使用

有些时候我们不希望把一些编译的东西提交到git中,gitignore可以方便管理我们不需要提交的文件,自动过滤设置的文件。
Git提供了一种可配性很强的机制来允许用户将指定的文件或目录排除在版本控制之外,它会检查代码仓库的根目录下是否存在一个名为.gitignore的文件,如果存在的话就去一行行读取这个文件中的内容,并把每一行指定的文件或目录排除在版本控制之外。注意.gitignore中指定的文件或目录是可以用*通配符的。

这里以一个项目为例。
第一步,创建代码库
首先进入当前的项目根目录
执行git init
这时项目根目录下会有.git文件夹
第二步,创建.gitignore文件
执行如下命令:
touch .gitignore
也可以新建一个文件,重命名为.gitignore.,注意后面有一个.
第三步,编辑.gitignore文件
vim .gitignore
然后在里面加入build/
表示我们不希望将build文件夹提交到git中,然后退出。
第四步,提交
git add .
将所有文件提交到git,会过滤掉bulid文件夹
git commit -m "过滤掉build文件夹"
执行提交
检查提交是否成功
git status
提示没有东西需要提交,说明提交成功。

添加子仓库

Git Submodule允许一个git仓库,作为另一个git仓库的子目录,并且保持父项目和子项目相互独立。

1
git submodule add <仓库地址><本地路径>

新建一个父仓库main, 一个子仓库sub。将父仓库克隆到本地。

1
git clone https://github.com/sunstady/main.git

进入父仓库,并添加子仓库。

1
2
cd main/
git submodule add https://github.com/sunstady/sub.git sub

1-1
添加成功后,在父仓库根目录增加了.gitmodule文件。

1
2
3
[submodule "sub"]
path = sub
url = https://github.com/sunstady/sub.git

并且在父仓库的git配置文件中加入了submodule段。

1
2
3
4
5
6
cat .git/config
//加入了submodule段
[submodule "sub"]
url = https://github.com/sunstady/sub.git
active = true

1-2
注意:添加子仓库之后,主仓库的对应目录下(这里为sub),并不是sub仓库的文件,而是对应的commit id

检出

克隆一个包含子仓库的仓库目录,并不会clone下子仓库的文件,只是会克隆下.gitmodule描述文件,需要进一步克隆子仓库文件。

1
2
3
4
5
//初始化本地配置文件
git submodule init
//检出父仓库列出的commit
git submodule update

1-3
或者使用组合指令。

1
git submodule update --init --recursive

此时子目录在一个未命名分支,此时子仓库有改动并没有检测到。

1
2
3
git branch
* (HEAD detached at 46a27af)
master

1-4
查看子仓库信息

1
git diff --cached --submodule

1-5
在子仓库,切换到master分支,并git pull最新代码之后,回到主仓库目录,会显示子仓库的修改,需要在主仓库提交修改,即修改指定的commit id

更新

如果在本地修改子仓库,在主仓库git status会显示子仓库有修改。

1
2
3
4
5
6
7
8
9
10
11
git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
modified: lib (modified content)
no changes added to commit (use "git add" and/or "git commit -a")

需要先在子仓库提交,然后再到主仓库提交代码。

删除子仓库

  • 删除.gitsubmodule里相关部分。
  • 删除.git/config 文件里相关字段。
  • 删除子仓库目录。
1
git rm --cached <本地路径>

1-6

如果未按照上述步骤删除,可能残留在.git/modules文件夹内。

Your support will encourage me to continue to create!