Git 常用命令详解

—-写在前面:

自打成为社会人以来,接触Git也四年有余了吧,说它是工作必备工具真是毫不夸张呢。本篇将讲述Git的基础操作,掌握了它们开发者基本够用了。除非你志在软件配置管理SCM,那就要移步官网深入研究了。

一、Git的安装

下面以Ubuntu系统为例:

1
2
3
4
# 需先加入git软件源,再执行install操作
$ sudo add-apt-repository ppa:git-core/ppa
$ sudo apt update
$ sudo apt-get install git

Windows和OS X用户可直接从官网获取git安装包安装:

1
2
3
4
5
# Windows版下载地址:
https://www.git-scm.com/download/win

# OS X版下载地址:
https://www.git-scm.com/download/mac

二、Git的配置

2.1 用户名和邮箱

安装完Git第一步即需设置用户名和邮箱,因为每次git提交都需要包含这些信息,且不可更改。为减少每次提交都设置用户名/邮箱带来的麻烦,建议添加--global选项,即:

1
2
$ git config --global user.name "alex"
$ git config --global user.email "alex@gmail.com"

2.2 默认文本编辑器

Git默认会是使用系统默认的文本编辑器,若你有自己喜好的编辑器,推荐使用以下命令将其设为git默认编辑器。比如你可以设置为emacs,sublime,atom等等,下面以vim为例:

1
$ git config --global core.editor vim

2.3 Git指令别名

为方便个人使用,支持通过alias来设置git别名,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 将 git checkout 设置为 git co
$ git config --global alias.co checkout

# 将 git branch 设置为 git br
$ git config --global alias.br branch

# 将git commit 设置为 git ci
$ git config --global alias.ci commit

# 将 git status 设置为 git st
$ git config --global alias.st status

# 将 git reset HEAD -- 设置为 git unstage
$ git config --global alias.unstage 'reset HEAD --'

# 将 git log -l HEAD 设置为 git last
$ git config --global alias.last 'log -l HEAD'
...

2.4 检查Git配置

可以通过git config --list列出当前的配置项:

1
2
3
4
5
6
$ git config --list
user.name=alex
user.email=alex@gmail.com
color.status=auto
color.branch=auto
color.diff=auto

三、Git基础

3.1 初始化Git仓库

如想对文件目录进行跟踪管理,可进入该目录使用init指令初始化,操作完成后当前目录会生成.git目录:

1
2
$ git init
Initialized empty Git repository in git_learn/.git/

3.2 克隆Git仓库

若想获取现有仓库的副本,可通过clone指令,将其从服务器端复制到客户端:

1
$ git clone https://github.com/git_learn.git

3.3 查看Git仓库当前文件状态

可使用status指令查看当前目录是否有改动。若只需查看简洁的状态信息,可添加-s,--short选项:

1
2
3
4
5
6
$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
$ git status -s
$ git status --short

3.4 跟踪新文件

可使用add指令将新的文件添加到暂存区加以跟踪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md

$ git add README.md

$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md

借用git status可以很明显的看到,README.md文件从执行add指令之前的Untracked files…变为Chnages to be committed…

3.5 移除文件

若想从git仓库中移除某个文件,需用rm指令将其从以已跟踪文件列表中移除,再提交即可:

1
2
3
4
5
6
7
8
9
10
$ git rm README.md
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: README.md

3.6 移动文件

有时候你可能需要将某个文件重命名或更换目录,那mv指令可以帮你完成:

1
2
3
4
5
6
$ git mv README.md README
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README

你可以近视将mv操作视作,执行了下面3条指令:

1
2
3
$ mv README.md README
$ git rm README.mg
$ git add README

3.7 提交文件

执行完add只是将文件变更保存到了暂存区,若需上库,还需执行commit操作,将其加入提交的内容中去(此时将以之前设置的默认文本编辑器打开提交信息):

1
2
3
4
5
6
7
8
$ git commit
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Changes to be committed:
# renamed: README.md -> README
#

这里提供一种简单直接的方式,加入-m选项可直接键入提交信息:

1
2
3
4
$ git commit -m 'Add README.md for test'
[master (root-commit) e8365bd] Add README.md for test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md

若需修改提交信息,可添加--amend选项进入修改提交信息界面,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ git commit --amend

new file: README.md

$ git mv README.md README
$ git status .
On branch master
Add README.md for test

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sun Aug 26 23:20:13 2018 +0800
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
# new file: README
#
#比如此处将提交信息改为test:
[master da4604c] test
Date: Sun Aug 26 23:20:13 2018 +0800
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README

3.8 查看文件修改详细信息

可能你并不满足于staus呈现的信息,还想知道修改的具体内容,那么diff指令可以为你圆梦:

1
2
3
4
5
6
7
8
# 在README文件中添加一句话:Test for diff cmd.
$ git diff
diff --git a/README b/README
index e69de29..5b24ac5 100644
--- a/README
+++ b/README
@@ -0,0 +1,2 @@
+Test for diff cmd.

若希望知道哪些已暂存的内容将会进入下一次提交,可添加--staged选项(同义词--cached)查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ git diff .
diff --git a/README b/README
index dc774c9..69920be 100644
--- a/README
+++ b/README
@@ -1 +1,2 @@
Test for staged before.
+Test for staged after.

$ git diff --staged
diff --git a/README b/README
index e69de29..dc774c9 100644
--- a/README
+++ b/README
@@ -0,0 +1 @@
+Test for staged before.

3.9 查看提交记录

如果你想查看之前的提交记录,可通过log操作实现:

1
2
3
4
5
6
7
8
9
$ git log
commit 6f79f932eea30c32b92d9ee525219f9fb9e65689 (HEAD -> master)
Author: alex <alx@gmail.com>
Date: Sun Aug 26 21:46:09 2018 +0800
staged
commit da4604c147f34ecf029b42975a323a8fc6ae26e8
Author: alex <alx@gmail.com>
Date: Sun Aug 26 21:20:13 2018 +0800
test

-p选项: 按补丁格式显示每次提交引入的更改

1
2
3
4
5
6
7
8
9
10
11
$ git log -p -1
commit 6f79f932eea30c32b92d9ee525219f9fb9e65689 (HEAD -> master)
Author: alex <alex@gmail.com>
Date: Sun Aug 26 21:46:09 2018 +0800
staged
diff --git a/README b/README
index e69de29..dc774c9 100644
--- a/README
+++ b/README
@@ -0,0 +1 @@
+Test for staged before.

--stat选项: 显示每次提交中被更改的文件的统计信息

1
2
3
4
5
6
7
$ git log --stat
commit 6f79f932eea30c32b92d9ee525219f9fb9e65689 (HEAD -> master)
Author: alex <alex@gmail.com>
Date: Sun Aug 26 21:46:09 2018 +0800
staged
README | 1 +
1 file changed, 1 insertion(+)

--pretty选项: 可选格式显示提交。可跟oneline, short, full, format

1
2
3
4
5
6
7
$ git log --pretty=oneline
6f79f932eea30c32b92d9ee525219f9fb9e65689 (HEAD -> master) staged
da4604c147f34ecf029b42975a323a8fc6ae26e8 test

$ git log --pretty=format:"%h - %an, %ar : %s"
6f79f93 - alex, 8 minutes ago : staged
da4604c - alex, 34 minutes ago : test

--graph选项: 提交历史旁显示ASCII图表,标示分支及合并信息

1
2
3
4
5
$ git log --graph
* commit 6f79f932eea30c32b92d9ee525219f9fb9e65689 (HEAD -> master)
| Author: alex <alex@gmail.com>
| Date: Sun Aug 26 21:46:09 2018 +0800
| staged

更多扩展选项可通过git log --help来查阅。

四、Git基础续

4.1 撤销已暂存文件

有时候你可能并不想将某个文件提交,但是你又不小心输入了git add *.,导致这个文件被添加到了暂存区。
别担心,强大Git支持撤销操作,只需使用git reset HEAD <file>即可:

1
2
3
4
5
6
7
8
9
10
$ git reset HEAD README
Unstaged changes after reset:
M README
$ git status
On branch 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)
modified: README
no changes added to commit (use "git add" and/or "git commit -a")

4.2 撤销文件的修改

除了上述的reset指令,你还可以使用checkout实现,轻松撤销之前对文件得修改,使其恢复至上次提交的状态:

1
2
3
4
5
$ git checkout -- README
$ git status .
On branch master
nothing to commit, working tree clean
注:鉴于该条指令比较危险,所有对文件得修改都会丢失,建议执行前先备份好。

4.3 还原提交

可能你想还原之前得一笔提交,又不想reset完再commit,怎么办?请拿起revert一键操作吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ git revert 6f79f932eea30c32b92d9ee525219f9fb9e65689
[master 4077c72] Revert "staged"
1 file changed, 1 deletion(-)

$ git log .
commit 4077c7238374397b311a77f6892a0b4a80e3d29e (HEAD -> master)
Author: alex<alex@gmail.com>
Date: Tue Aug 28 21:31:39 2018 +0800
Revert "staged"
This reverts commit 6f79f932eea30c32b92d9ee525219f9fb9e65689.
commit 6f79f932eea30c32b92d9ee525219f9fb9e65689
Author: alex<alex@gmail.com>
Date: Sun Aug 26 21:46:09 2018 +0800
staged

4.4 远程仓库

1.显示远程仓库

如果你相查看克隆的代码在远程服务器设置了哪些远程仓库,你可以使用remote指令列出远程仓库短名称。
你也可以加上-v选项,以查看远程仓库对应得URL

1
2
3
4
5
6
$ cd battery-historian/
$ git remote
origin
$ git remote -v
origin https://github.com/google/battery-historian.git (fetch)
origin https://github.com/google/battery-historian.git (push)

2.显示远程仓库更多信息

show跟上对应分支,可显示该分支信息:

1
2
3
4
5
6
7
8
9
10
11
$ git remote show origin
* remote origin
Fetch URL: https://github.com/google/battery-historian.git
Push URL: https://github.com/google/battery-historian.git
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)

4.5 拉取数据

进入项目组时,你可能需要从服务器拉取项目代码,fetch可以帮你实现。
但是记住,它只会帮你把数据拉到本地仓库,而不会自动合并到本地项目中,如需修改请自行手动操作。

1
2
3
$git fetch https://github.com/google/battery-historian.git
From https://github.com/google/battery-historian
* branch HEAD -> FETCH_HEAD

你还可以使用clone指令克隆代码到本地并自动设置master分支,设置分支后你后续就可以使用pull指令同步代码了。

4.6 推送数据

当你完成一个feature时,你可能需要将相关代码提交上库。这时候push指令就派上用场用场了。

1
2
3
4
5
6
7
8
9
10
#将本地master分支推送到远程origin服务器。
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 747 bytes | 747.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/google/battery-historian.git
ac592e3..d0fa54e master -> master

push除了可以后跟分支branch,还可以跟上--tags达到推送标签到服务器的目的(可以将tag理解为branch)

4.7 标签tag

同其它版本控制系统一样,git也可以给特定版本添加标记,简单粗暴使用tag指令即可:

1
2
3
4
5
$ git tag
v0.9.2
v1.0.0
v1.1.0
...

-l选项还可以显示指定系列得标记版本:

1
2
3
4
5
6
7
Alex-Mac:apktool xiezeyang$ git tag -l "v2.0*"
v2.0.0
v2.0.0-RC2
v2.0.0-RC3
v2.0.0-RC4
v2.0.1
...

-a选项可以创建tag:

1
2
3
4
5
6
7
8
# -m: 用于添加标记信息
$ git tag -a v6.66 -m 'add tag for test'
# show: 显示指定版本/提交/标记信息
$ git show v6.66
tag v6.66
Tagger: alex <alex@gmail.com>
Date: Tue Aug 28 21:28:32 2018 +0800
add tag for test

4.8 分支branch

何为分支,即一个指向某次提交得轻量级得可移动的指针。(若不理解可前Google查阅Git介绍)
如果你拥有一个可移动得新指针使用,那你就需要学会使用branch指令创建分支。

1
2
3
4
5
6
7
# -l: 列举分支
$ git branch -l
* master
$ git branch test
$ git branch -l
* master
test

创建分支后可以使用checkout指令切换到新分支上:

1
2
3
4
5
$ git checkout testing
Switched to branch 'testing'
$ git branch -l
master
* test

如果你想偷懒也不是不可以,使用checkout后接-b可直接创建并切换至新分支:

1
2
3
4
5
6
$ git checkout -b test2
Switched to a new branch 'test2'
$ git branch -l
master
* test2
test

如果某个分支你不想用了,你可以加上-d选项删除它:

1
2
3
4
5
6
7
#不支持删除当前分支哦,你需要先切到其它分支上,不然就会出现下方提示
$ git branch -d test2
error: Cannot delete branch 'test2' checked out at '/gitlearn'
$ git checkout testing
Switched to branch 'testing'
$ git branch -d test2
Deleted branch test2 (was 21fbe525).

鉴于merge,rebase等操作存在一定危险性,建议新手慎玩。可移步官网了解branch前世今生先。

4.9 储藏stash

这里说的储藏,是指能够获取当前目录得中间状态,即修改过得被跟踪的文件、暂存的得变更,并将该中间状态保存在一个包含未完成变更得栈中,随后可再次恢复这些状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ git status .
On branch 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)
modified: README
Untracked files:
(use "git add <file>..." to include in what will be committed)
diff.patch
no changes added to commit (use "git add" and/or "git commit -a")

$ git stash
Saved working directory and index state WIP on master: 6f79f93 staged

$ git status .
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
diff.patch
nothing added to commit but untracked files present (use "git add" to track)

--list选项可以列出所有储藏:

1
2
$ git stash list
stash@{0}: WIP on master: 6f79f93 staged

apply选项可以重新应用储藏,若不指定默认会应用最近得储藏:

1
2
3
4
5
6
7
8
9
10
$ git stash apply stash@{0}
On branch 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)
modified: README
Untracked files:
(use "git add <file>..." to include in what will be committed)
diff.patch
no changes added to commit (use "git add" and/or "git commit -a")

4.10 清理clean

对于工作目录中某些文件,可能是编译生成得,总之你并不想储藏,更无需提交,那clean指令可以帮你弄走它们。

1
2
3
# -f: 即force强制删除
$ git clean -d -f
Removing README.orig

如果想知道clean会整走哪些文件,你可以使用-n选项来个演习操作:

1
2
$ git clean -d -n
Would remove README.orig

如果你想更安全的移除文件,你可以-i走起,保证你爽歪歪:

1
2
3
4
5
6
7
8
$ git clean -x -i
Would remove the following item:
README.orig
*** Commands ***
1: clean 2: filter by pattern 3: select by numbers
4: ask each 5: quit 6: help
What now> 1
Removing README.orig

4.11 补丁Patch

前面介绍过diff指令,你可以通过git diff生成diff.patch。然后通过apply指令来应用该patch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ git diff > diff.patch
$ cat diff.patch
diff --git a/README b/README
index dc774c9..a059de0 100644
--- a/README
+++ b/README
@@ -1 +1,2 @@
Test for staged before.
+Test for diff patch.

$ git checkout .
$ git apply ../diff.patch
$ git status .
On branch 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)
modified: README
no changes added to commit (use "git add" and/or "git commit -a")

如果你想检查该补丁是否能顺利应用,请加上--check指令,若检查失败则有所提示:

1
2
3
$ git apply --check ../diff.patch
error: patch failed: README:1
error: README: patch does not apply

当然了,你还可以使用patch p1来打补丁:

1
2
3
4
5
6
7
8
9
$ patch -p1 < diff.patch
patching file README
$ git status .
On branch 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)
modified: README
no changes added to commit (use "git add" and/or "git commit -a")

如果你只是想将某一笔提交合入当前分支,你还可以选用cherry-pick指令,它同revert恰恰相反,此处就演示了。

4.12 SSH公密钥

默认情况下,用户SSH密钥保存在~/.ssh目录下:

1
2
3
4
5
$ cd ~/.ssh
$ ls
id_rsa id_rsa.pub known_hosts
$cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EBBBBDAQABAAABAQC/cbztX6Jweu3wevxPYIjwgJS4EeodL8/LN5QpRBXaioiZmWqu/Jj0AbQTxhkHpAg2rTDqOz6yAsVVsk+PQCv3hZFX6rSLUu0gS9nrjaj8oJF+ftTQYMdiZ8HZEaPyaHkabcde8NXtRYASAbW6gzIa1CLs1vOvdeeq1jXUilHDFBRxdTRlJ4ikACHgdV4h+AyKiqklzaZkfHfU6NCUHvdRvJ8SS3eLsYnmC6/pJ2mj7WTJ5TAAWpgfiFSmnyQKF7y+Ywm9tO7smHEOzk1shSZQnwvILH5lqI4N06nWAb7nEJ+Y1efVBLV1zIqw761/NzdV/2sL0E6/QpE91UIyTUDz alex@ubuntu.local

若无该目录,你可以通过sss-keygen指令来创建它们,为方便起见,你可以一路回车。
再打开~/.ssh/id_rsa.pub文件将其发送给git服务器管理员,或拷贝到git/gerrit服务上publickey配置处。
(可参阅GitHub官网帮助介绍:http://github.com/guides/providing-your-ssh-key)

如有不当之处,欢迎指出,谢谢!