# 常用 Git 命令简介及使用

#### &#x20;博客作者：联系请[点击](https://hezhiqiang.gitbook.io/about-the-author/lian-xi-zuo-zhe)，搬运不易，希望请作者喝咖啡，可以点击[联系博客作者](https://hezhiqiang.gitbook.io/about-the-author/lian-xi-zuo-zhe)

## 一、Git背景

&#x20;[**Git**](http://book.git-scm.com/) 是一个分布式版本控制工具，它的作者 [Linus Torvalds](http://en.wikipedia.org/wiki/Linus_Torvalds) 是这样给我们介绍 [Git](http://en.wikipedia.org/wiki/Git_\(software\))  —— The stupid content tracker（傻瓜式的内容跟踪器）

Git 最初由Linus Torvalds编写，用于 Linux 内核开发的版本控制工具。

Git 与常用的版本控制工具 CVS、Subversion 等不同，它采用了分布式版本库的方式，不必服务器端软件支持，使源代码的发布和交流极其方便。

## 二、Git的诞生

很多人都知道，Linus在1991年创建了开源的Linux，从此，Linux系统不断发展，已经成为最大的服务器系统软件了。

Linus虽然创建了Linux，但Linux的壮大是靠全世界热心的志愿者参与的，这么多人在世界各地为Linux编写代码，那Linux的代码是如何管理的呢？

事实是，在2002年以前，世界各地的志愿者把源代码文件通过diff的方式发给Linus，然后由Linus本人通过手工方式合并代码！

你也许会想，为什么Linus不把Linux代码放到版本控制系统里呢？不是有CVS、SVN这些免费的版本控制系统吗？因为Linus坚定地反对CVS和SVN，这些集中式的版本控制系统不但速度慢，而且必须联网才能使用。有一些商用的版本控制系统，虽然比CVS、SVN好用，但那是付费的，和Linux的开源精神不符。

不过，到了2002年，Linux系统已经发展了十年了，代码库之大让Linus很难继续通过手工方式管理了，社区的弟兄们也对这种方式表达了强烈不满，于是Linus选择了一个商业的版本控制系统BitKeeper，BitKeeper的东家BitMover公司出于人道主义精神，授权Linux社区免费使用这个版本控制系统。

安定团结的大好局面在2005年就被打破了，原因是Linux社区牛人聚集，不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议（这么干的其实也不只他一个），被BitMover公司发现了（监控工作做得不错！），于是BitMover公司怒了，要收回Linux社区的免费使用权。

Linus可以向BitMover公司道个歉，保证以后严格管教弟兄们，嗯，这是不可能的。实际情况是这样的：

Linus花了两周时间自己用C写了一个分布式版本控制系统，这就是Git！一个月之内，Linux系统的源码已经由Git管理了！牛是怎么定义的呢？大家可以体会一下。

Git迅速成为最流行的分布式版本控制系统，尤其是2008年，GitHub网站上线了，它为开源项目免费提供Git存储，无数开源项目开始迁移至GitHub，包括jQuery，PHP，Ruby等等。

历史就是这么偶然，如果不是当年BitMover公司威胁Linux社区，可能现在我们就没有免费而超级好用的Git了。

## 三、优点&#x20;

1\.   分布式开发时，可以git clone克隆一个本地版本，然后在本地进行操作提交，本地可以完成一个完整的版本控 制。在发布的时候，使用git push来推送到远程即可。&#x20;

2\.   git分支的本质是一个指向提交快照的指针，速度快、灵活，分支之间可以任意切换。都可以在本地进行操作可 以不同步到远程。&#x20;

3\.   冲突解决，多人开发很容易就会出现冲突，可以先pull远程到本地，然后在本地合并一下分支，解决好冲突，在 push到远程即可。&#x20;

4\.    离线工作，如果git服务器出现问题，也可以在本地进行切换分支的操作，等联网后再提交、合并等操作。&#x20;

## 四、缺点&#x20;

1\.    Git没有严格的权限控制，一般是通过系统设置文件的读写权限来做权限控制。&#x20;

2\.    工作目录只能是整个目录，而svn可以单独checkout某个有权限的目录。&#x20;

3\.     Git上手可能没有svn那边顺手，需要经过学习一下。

{% hint style="info" %}
**总结 :**

#### 如果对访问控制、权限分配和代码安全性等要求比较高的，建议使用svn。&#x20;

#### 如果是分布式，多人开发，版本迭代比较快的项目，建议使用Git。

{% endhint %}

## **五. 安装Git**

### 一、Linux – 打开终端，然后通过包管理安装

```bash
yum -y install git
# or: dnf -y install git
```

#### 在Ubuntu上命令是：

```bash
sudo apt-get install git
```

### 二、Windows – 推荐使用[git for windows](https://gitforwindows.org)，它包括了图形工具以及命令行模拟器

{% embed url="<https://gitforwindows.org/>" %}

### 三、OS X – 最简单的方式是使用[homebrew](https://brew.sh)安装，命令行执行brew install git

{% embed url="<https://brew.sh/>" %}

{% hint style="success" %}

#### 如果你是新手，推荐使用图形工具[Github desktop](https://desktop.github.com/)和[Sourcetree](https://www.atlassian.com/zh/software/sourcetree)。不过即使使用图形界面的应用，知道一些基本的 git命令依然很重要。接下来的内容我们集中在命令行控制上。

{% endhint %}

{% embed url="<https://www.atlassian.com/zh/software/sourcetree>" %}

{% embed url="<https://desktop.github.com>" %}

**如果你习惯使用了SVN的Windows桌面图形工具当然也可以下载小乌龟**

{% hint style="danger" %}

#### 注意：下载中文汉化包需要与下载的**Git**客户端相对应版本，安装好汉化包需要重启电脑才能生效。

{% endhint %}

{% embed url="<https://tortoisegit.org/download/>" %}

### **四、Git官网各种发行版下载：**

{% embed url="<https://git-scm.com/downloads>" %}

{% hint style="info" %}
Git是分布式的，这意味着它并不依赖于中心服务器来保存你文件的旧版本。

任何一台机器都可以有一个本地版本的 控制系统，其实就是一个硬盘上的文件，我们称之为仓库（repository）。如果是多人协作的话，你还需要一个线上 仓库，用来同步代码等信息。

这就是[GitHub](https://github.com/)、[BitBucket](https://bitbucket.org)等网站做的工作。
{% endhint %}

{% embed url="<https://github.com/>" %}

{% embed url="<https://bitbucket.org/product/>" %}

## 六. **Git 常用命令**

{% hint style="success" %}

### Git学习网站：

{% endhint %}

{% embed url="<https://learngitbranching.js.org/>" %}

### 常用 Git 命令清单。几个专用名词的译名如下。

```bash
Workspace：       #工作区
Index / Stage：   #暂存区
Repository：      #仓库区（或本地仓库）
Remote：          #远程仓库
```

### 一、新建代码库

> ```
> # 在当前目录新建一个Git代码库
> git init
>
> # 新建一个目录，将其初始化为Git代码库
> git init [project-name]
>
> # 下载一个项目和它的整个代码历史
> git clone [url]
> ```

### 二、配置

Git的设置文件为`.gitconfig`，它可以在用户主目录下（全局配置），也可以在项目目录下（项目配置）。

> ```
> # 显示当前的Git配置
> git config --list
>
> # 编辑Git配置文件
> git config -e [--global]
>
> # 设置提交代码时的用户信息
> git config [--global] user.name "[name]"
> git config [--global] user.email "[email address]"
> ```

### 三、增加/删除文件

> ```
> # 添加指定文件到暂存区
> git add [file1] [file2] ...
>
> # 添加指定目录到暂存区，包括子目录
> git add [dir]
>
> # 添加当前目录的所有文件到暂存区
> git add .
>
> # 添加每个变化前，都会要求确认
> # 对于同一个文件的多处变化，可以实现分次提交
> git add -p
>
> # 删除工作区文件，并且将这次删除放入暂存区
> git rm [file1] [file2] ...
>
> # 停止追踪指定文件，但该文件会保留在工作区
> git rm --cached [file]
>
> # 改名文件，并且将这个改名放入暂存区
> git mv [file-original] [file-renamed]
> ```

### 四、代码提交

> ```
> # 提交暂存区到仓库区
> git commit -m [message]
>
> # 提交暂存区的指定文件到仓库区
> git commit [file1] [file2] ... -m [message]
>
> # 提交工作区自上次commit之后的变化，直接到仓库区
> git commit -a
>
> # 提交时显示所有diff信息
> git commit -v
>
> # 使用一次新的commit，替代上一次提交
> # 如果代码没有任何新变化，则用来改写上一次commit的提交信息
> git commit --amend -m [message]
>
> # 重做上一次commit，并包括指定文件的新变化
> git commit --amend [file1] [file2] ...
> ```

### 五、分支

> ```
> # 列出所有本地分支
> git branch
>
> # 列出所有远程分支
> git branch -r
>
> # 列出所有本地分支和远程分支
> git branch -a
>
> # 新建一个分支，但依然停留在当前分支
> git branch [branch-name]
>
> # 新建一个分支，并切换到该分支
> git checkout -b [branch]
>
> # 新建一个分支，指向指定commit
> git branch [branch] [commit]
>
> # 新建一个分支，与指定的远程分支建立追踪关系
> git branch --track [branch] [remote-branch]
>
> # 切换到指定分支，并更新工作区
> git checkout [branch-name]
>
> # 切换到上一个分支
> git checkout -
>
> # 建立追踪关系，在现有分支与指定的远程分支之间
> git branch --set-upstream [branch] [remote-branch]
>
> # 合并指定分支到当前分支
> git merge [branch]
>
> # 选择一个commit，合并进当前分支
> git cherry-pick [commit]
>
> # 删除分支
> git branch -d [branch-name]
>
> # 删除远程分支
> git push origin --delete [branch-name]
> git branch -dr [remote/branch]
> ```

### 六、标签

> ```
> # 列出所有tag
> git tag
>
> # 新建一个tag在当前commit
> git tag [tag]
>
> # 新建一个tag在指定commit
> git tag [tag] [commit]
>
> # 删除本地tag
> git tag -d [tag]
>
> # 删除远程tag
> git push origin :refs/tags/[tagName]
>
> # 查看tag信息
> git show [tag]
>
> # 提交指定tag
> git push [remote] [tag]
>
> # 提交所有tag
> git push [remote] --tags
>
> # 新建一个分支，指向某个tag
> git checkout -b [branch] [tag]
> ```

### 七、查看信息

> ```
> # 显示有变更的文件
> git status
>
> # 显示当前分支的版本历史
> git log
>
> # 显示commit历史，以及每次commit发生变更的文件
> git log --stat
>
> # 搜索提交历史，根据关键词
> git log -S [keyword]
>
> # 显示某个commit之后的所有变动，每个commit占据一行
> git log [tag] HEAD --pretty=format:%s
>
> # 显示某个commit之后的所有变动，其"提交说明"必须符合搜索条件
> git log [tag] HEAD --grep feature
>
> # 显示某个文件的版本历史，包括文件改名
> git log --follow [file]
> git whatchanged [file]
>
> # 显示指定文件相关的每一次diff
> git log -p [file]
>
> # 显示过去5次提交
> git log -5 --pretty --oneline
>
> # 显示所有提交过的用户，按提交次数排序
> git shortlog -sn
>
> # 显示指定文件是什么人在什么时间修改过
> git blame [file]
>
> # 显示暂存区和工作区的差异
> git diff
>
> # 显示暂存区和上一个commit的差异
> git diff --cached [file]
>
> # 显示工作区与当前分支最新commit之间的差异
> git diff HEAD
>
> # 显示两次提交之间的差异
> git diff [first-branch]...[second-branch]
>
> # 显示今天你写了多少行代码
> git diff --shortstat "@{0 day ago}"
>
> # 显示某次提交的元数据和内容变化
> git show [commit]
>
> # 显示某次提交发生变化的文件
> git show --name-only [commit]
>
> # 显示某次提交时，某个文件的内容
> git show [commit]:[filename]
>
> # 显示当前分支的最近几次提交
> git reflog
> ```

### 八、远程同步

> ```
> # 下载远程仓库的所有变动
> git fetch [remote]
>
> # 显示所有远程仓库
> git remote -v
>
> # 显示某个远程仓库的信息
> git remote show [remote]
>
> # 增加一个新的远程仓库，并命名
> git remote add [shortname] [url]
>
> # 取回远程仓库的变化，并与本地分支合并
> git pull [remote] [branch]
>
> # 上传本地指定分支到远程仓库
> git push [remote] [branch]
>
> # 强行推送当前分支到远程仓库，即使有冲突
> git push [remote] --force
>
> # 推送所有分支到远程仓库
> git push [remote] --all
> ```

### 九、撤销

> ```
> # 恢复暂存区的指定文件到工作区
> git checkout [file]
>
> # 恢复某个commit的指定文件到暂存区和工作区
> git checkout [commit] [file]
>
> # 恢复暂存区的所有文件到工作区
> git checkout .
>
> # 重置暂存区的指定文件，与上一次commit保持一致，但工作区不变
> git reset [file]
>
> # 重置暂存区与工作区，与上一次commit保持一致
> git reset --hard
>
> # 重置当前分支的指针为指定commit，同时重置暂存区，但工作区不变
> git reset [commit]
>
> # 重置当前分支的HEAD为指定commit，同时重置暂存区和工作区，与指定commit一致
> git reset --hard [commit]
>
> # 重置当前HEAD为指定commit，但保持暂存区和工作区不变
> git reset --keep [commit]
>
> # 新建一个commit，用来撤销指定commit
> # 后者的所有变化都将被前者抵消，并且应用到当前分支
> git revert [commit]
>
> # 暂时将未提交的变化移除，稍后再移入
> git stash
> git stash pop
> ```

## 六. 其他Git命令

> ```
> # 生成一个可供发布的压缩包
> git archive
> ```

### 一、撤销提交

一种常见的场景是，提交代码以后，你突然意识到这个提交有问题，应该撤销掉，这时执行下面的命令就可以了。

> ```
> git revert HEAD
> ```

上面命令的原理是，在当前提交后面，新增一次提交，抵消掉上一次提交导致的所有变化。它不会改变过去的历史，所以是首选方式，没有任何丢失代码的风险。

`git revert` 命令只能抵消上一个提交，如果想抵消多个提交，必须在命令行依次指定这些提交。比如，抵消前两个提交，要像下面这样写。

> ```
> git revert [倒数第一个提交] [倒数第二个提交]
> ```

`git revert`命令还有两个参数。

> * `--no-edit`：执行时不打开默认编辑器，直接使用 Git 自动生成的提交信息。
> * `--no-commit`：只抵消暂存区和工作区的文件变化，不产生新的提交。

### 二、丢弃提交

如果希望以前的提交在历史中彻底消失，而不是被抵消掉，可以使用`git reset`命令，丢弃掉某个提交之后的所有提交。

> ```
> git reset [last good SHA]
> ```

`git reset`的原理是，让最新提交的指针回到以前某个时点，该时点之后的提交都从历史中消失。

默认情况下，`git reset`不改变工作区的文件（但会改变暂存区），`--hard`参数可以让工作区里面的文件也回到以前的状态。

> ```
> git reset --hard [last good SHA]
> ```

执行`git reset`命令之后，如果想找回那些丢弃掉的提交，可以使用`git reflog`命令，具体做法参考[这里](https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local)。不过，这种做法有时效性，时间长了可能找不回来。

### 三、替换上一次提交

提交以后，发现提交信息写错了，这时可以使用`git commit`命令的`--amend`参数，可以修改上一次的提交信息。

> ```
> git commit --amend -m "Fixes bug #42"
> ```

它的原理是产生一个新的提交对象，替换掉上一次提交产生的提交对象。

这时如果暂存区有发生变化的文件，会一起提交到仓库。所以，`--amend`不仅可以修改提交信息，还可以整个把上一次提交替换掉。

### 四、撤销工作区的文件修改

如果工作区的某个文件被改乱了，但还没有提交，可以用`git checkout`命令找回本次修改之前的文件。

> ```
> git checkout -- [filename]
> ```

它的原理是先找暂存区，如果该文件有暂存的版本，则恢复该版本，否则恢复上一次提交的版本。

注意，工作区的文件变化一旦被撤销，就无法找回了。

### 五、从暂存区撤销文件

如果不小心把一个文件添加到暂存区，可以用下面的命令撤销。

> ```
> git rm --cached [filename]
> ```

上面的命令不影响已经提交的内容。

### 六、撤销当前分支的变化

你在当前分支上做了几次提交，突然发现放错了分支，这几个提交本应该放到另一个分支。

> ```
> # 新建一个 feature 分支，指向当前最新的提交
> # 注意，这时依然停留在当前分支
> git branch feature
>
> # 切换到这几次提交之前的状态
> git reset --hard [当前分支此前的最后一次提交]
>
> # 切换到 feature 分支
> git checkout feature
> ```

上面的操作等于是撤销当前分支的变化，将这些变化放到一个新建的分支。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hezhiqiang.gitbook.io/about-the-author/yun-wei-gong-ju-shi-yong/untitled.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
