前言
最近在查看源码的时候,大多数是在窗口中去使用git,这里记录下我在日常中经常使用的一些命令,方便以后查询。这篇文章分为三个部分:
- 第一个部分介绍Git的一些必备的基础概念。
- 第二个部分介绍一些常用的命令
- 第三个部分根据介绍的常用命令做一个实操学习
如果我们建议看的话,直接从实际操作来进行看就行,其他方面是为了做一些备忘。
1.Git基本概念
这章节主要是说一下Git必须了解的一些概念,便于在使用下面命令的时候不会迷路,文章的内容来源于《精通Git(第二版简体中文)》可以直接去我的资源中下载。
分布式版本控制系统
分布式版本控制系统(Distributed Version Control System,简称 DVCS)面世了。在这类系统中,像 Git、Mercurial、Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像 下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因 为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分 别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前 的集中式系统中是无法实现的。
特点
直接记录快照,而非差异比较
Git 和其它版本控制系统(包括 Subversion 和近似工具)的主要差别在于 Git 对待数据的方法。概念上来区分, 其它大部分系统以文件变更列表的方式存储信息。这类系统(CVS、Subversion、Perforce、Bazaar 等等)将 它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。

Git 不按照以上方式对待或保存数据。反之,Git 更像是把数据看作是对小型文件系统的一组快照。每次你提交 更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。为了高效, 如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。Git 对待数据更像是 一个 快照流。

这是 Git 与几乎所有其它版本控制系统的重要区别。因此 Git 重新考虑了以前每一代版本控制系统延续下来的诸 多方面。Git 更像是一个小型的文件系统,提供了许多以此为基础构建的超强工具,而不只是一个简单的 VCS。 稍后我们在Git 分支讨论 Git 分支管理时,将探究这种方式对待数据所能获得的益处。
文件的三种状态与Git的三种工作区域
Git 有三种状态,你的文件可能处 于其中之一:已提交(committed)、已修改(modified)和已暂存(staged)。
- 已提交(committed):已提交表示数据已经安全的 保存在本地数据库中。
- 已修改(modified):已修改表示修改了文件,但还没保存到数据库中。
- 已暂存(staged):已暂存表示对一个已修改文件的当前版 本做了标记,使之包含在下次提交的快照中。
三个工作区域的概念:Git 仓库、工作目录以及暂存区域。

- Git 仓库,是Git 用来保存项目的元数据和对象数据库的地方。这是 Git 中最重要的部分,从其它计算机克隆 仓库时,拷贝的就是这里的数据。
- 工作目录,是对项目的某个版本独立提取出来的内容。这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘 上供你使用或修改。
- 暂存区域,是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。有时候也被称作“索 引”,不过一般说法还是叫暂存区域。
Git工作流程
基本的 Git 工作流程如下:
- 在工作目录中修改文件。
- 暂存文件,将文件的快照放入暂存区域。
- 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。

如果 Git 目录中保存着的特定版本文件,就属于已提交状态。如果作了修改并已放入暂存区域,就属于已暂存状 态。如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。
2.Git命令
Git基础
初始化仓库
- 在现有目录中初始化仓库
$ git init
使用命令后会在当前文件夹中初始化一个.git文件。
- 克隆现有的仓库
git clone [url] <本地仓库名>
一般情况下不用自己定义“本地仓库名”,直接拉取url后就在本地生成未url中项目的仓库名称。
[url],常见的url可以使用三种协议:http协议,git协议,SSH协议。
如果项目的数据过大,因为Http协议有大小限制,可以直接选择ssh协议进行拉取和传输。
记录每次更新到仓库
git文件的生命周期:

- 检查当前文件状态
$ git status
On branch master
nothing to commit, working directory clean
- 查看提交记录
git log 会按提交时间列出所有的更新,最近的更新排在最上面。
-2来仅显示最近两次提交。
git log -2
commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 16:40:33 2008 -0700
removed unnecessary test
commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 10:31:28 2008 -0700
first commit
回退操作
撤消操作
- 从仓库目录撤销到暂存区域
git reset --soft HEAD^
回退工作区
如果我们的文件已经存在在存储区后,如果放弃之前的更改,可以使用checkout命令。
git checkout --<file>
$ git st
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)
modified: app/src/main/java/WXApiService.java
no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout -- app/src/main/java/WXApiService.java
$ git st
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
这里我可以推荐一篇阮一峰的文章《常用 Git 命令清单》方便大家查看。
标签
- 检出标签
如果你想要工作目录与仓库中特定 的标签版本完全一样,可以使用 git checkout -b [branchname] [tagname] 在特定的标签上创建一个 新分支:
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'
Git别名
我们可以通过设置别名,叫很多命令进行组合使用
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
在设置别名时候,可以借鉴阮一峰的《配置别名》
Git工具
储藏工作
现在想要切换分支,但是还不想要提交之前的工作;所以储藏修改。将新的储藏推送到栈上,运行 git stash 或 git stash save:
$ git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
Git分支管理
新建分支
git branch develop
合并分支
merge
git merge master
将拉取master分支的提交历史合并到developer中,需要解决冲突。
rebase
如果当前在develop分支上,想要合并master分支
git rebase master
此时,会将developer的分支commit记录指向master分支的header指向的最后历史记录节点。如果想要master也指向developer节点,需要切换回master,然后执行merge命令
git checkout master
git merge develop
注意:总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。
补丁
Git 中的一些命令是以引入的变更即提交这样的概念为中心的,这样一系列的提交,就是一系列的补丁。这些命 令以这样的方式来管理你的分支。
获取在单个提交合并带本分支
git cherry-pick
从一个分支单独一个或者两个提交而不是合并整个分支的所有变更是非常有用的。下面3.4有示例。
3.实操
3.1 正向操作
工作区域——>暂存区域——>本地仓库目录
1.我创建了一个GitTest,并且初始化了仓库,使用命令git init初始化了一个Git仓库。
GitTest martin$ git init
Initialized empty Git repository in /Users/martin/Workspace/android/gitee/GitTest/.git/
2.我们在项目中添加一个README.md文件
martindembp:GitTest martin$ touch README.md
martindembp:GitTest martin$ git st
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
可以看见README.md文件此时处于工作区域是未被追踪的状态,前面说了当这个文件处于这个状态时,如果进行删除了,就不能找回来了。
3.我们将README.md文件添加到暂存区域(stage)
martindembp:GitTest martin$ git st
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
可以看见,进入这个区域的文件就可以根据提交命令,制作成一次提交了。
4.使用提交命令,提交到本地git 仓库。
martindembp:GitTest martin$ git commit --signoff
[master (root-commit) 137ef75] add README.md
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
martindembp:GitTest martin$ git log
commit 137ef75a241e026ae0ce57cf1b20eb53993e0ec0 (HEAD -> master)
Author: martin <martinmu2013@gmail.com>
Date: Thu Mar 28 21:59:08 2019 +0800
add README.md
Signed-off-by: martin <martinmu2013@gmail.com>
martindembp:GitTest martin$ git st
On branch master
nothing to commit, working tree clean
根据命令,我们可以得知几个点。
- git commit --signoff,将文件提交到了工作区域,
signoff是进入VIM区域编辑注释。 - git log,对这次提交做成了快照,索引值SHA1值为
137ef75a241e026ae0ce57cf1b20eb53993e0ec0 - git st,当前暂存区域和工作区域都已经清空。
3.2 逆向操作
工作区域<——暂存区域<——本地仓库目录
刚才我们进行了一个文件从创建到提交到本地仓库的过程,这次演示的是从本地仓库将文件变为未跟踪的状态。因为,我们第一次的提交不知道什么原因无法撤回,这里我又重新创建了一个Main.java文件按照上面的流程进行了一次提交。下面我们对这个Main.java文件进行撤销操作。
1.将仓库提交的Main.java快照退回为暂存区域。
martindembp:GitTest martin$ git reset --soft HEAD^
martindembp:GitTest martin$ git log
commit 08a733926a86e7191a7c4ad6290c52adc7cb390a (HEAD -> master)
Author: martin <martinmu2013@gmail.com>
Date: Thu Mar 28 21:59:08 2019 +0800
add README.md
Signed-off-by: martin <martinmu2013@gmail.com>
martindembp:GitTest martin$ git st
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: Main.java
撤销分为三种方式:软撤销,硬撤销,混合撤销。我们这里使用软撤销,使用软撤销,就是进行撤销后,这个commit的快照会回到暂存区域。
git reset --soft HEAD^命令HEAD^代表最近一次commit快照。这里代表撤销最近一次提交的内容,将提交的内容进入到暂存区域。
2.从暂存区域回退到工作区域。
martindembp:GitTest martin$ git reset HEAD Main.java
martindembp:GitTest martin$ git st
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
Main.java
nothing added to commit but untracked files present (use "git add" to track)
此时,我们看见Main.java文件已经退回到了工作区域已经无法进行追踪了。
3.3 在工作当中解决代码冲突
现在有这样一种场景,我们每天在下班之前都会提交代码,首先的步骤就是保存当前工作的代码,然后下拉服务端代码,解决冲突后合并代码上传。
保存本地——>下拉代码——>解决冲突
1.保存当前代码
在下拉代码之前,我们需要先保存我们现在手写的代码,就需要使用到下面的命令。
git stash
2.查看存储栈列表
当我们存储工作了以后,工作区间就会比较干净,这时就可以对分支进行切换。同时我们也可以查看存储的情况列表。
git stash list
martindembp:qmoorassistant martin$ git stash list
stash@{0}: WIP on master: dce3dc6 init mvp
2.下拉代码
在储藏我们当前的工作后,现在从服务器上下拉代码。
git pull
3.当我们合并冲突后,需要将的存储工作pop出来,这里的pop是最近的操作,当然也可以指定存储工作使用命令git stash apply.
git stash pop
- 日志
MartindeMacBook-Pro:qmoorassistant martin$ git stash pop
Auto-merging app/src/main/java/com/qmoor/qmoorassistant/presenter/WXApiPresenter.java
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: app/src/main/java/com/qmoor/qmoorassistant/bean/WXChatRoom.java
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)
modified: app/src/main/java/com/qmoor/qmoorassistant/activity/WXApiActivityTest.java
Dropped refs/stash@{0} (1602824b921619fb1323156aaaadf3ae18572823)
4.提交代码
在提交代码的时候加上--signoff,可以看见是谁提交的。
git commit --signoff
3.合并代码后,代码上传。
在合并的时候,会有很多冲突,我们需要手动的去解决文件冲突,然后再进行代码上传。
git push
MartindeMacBook-Pro:qmoorassistant martin$ git push
Enumerating objects: 123, done.
Counting objects: 100% (123/123), done.
Delta compression using up to 4 threads
Compressing objects: 100% (83/83), done.
Writing objects: 100% (93/93), 27.92 KiB | 1021.00 KiB/s, done.
Total 93 (delta 41), reused 0 (delta 0)
To git.7moor.com:wanghao/qmoorassistant.git
b222f91..dac7daa master -> master
3.4 cherry-pick:选择性的拉取某次提交合并分支
这节内容,我本来应该属于3.3节的内容,但是我选择重新起一节来编写,因为我觉得很实用。
在工作中,我们有这么一种需求,一个项目中开发一个分支叫分支A,现在公司接到一个需求,需要开一个分支B,但是在开发分支B中的业务逻辑和A分支的业务逻辑是完全相同的,那么在搭建好B分支的前期框架后,开发A分支业务逻辑的程序员也需要将代码拷贝到B分支上,每次粘贴复制肯定会出现问题,所以就有了次命令,来看下示意图:

如果你希望将提交 e43a6 拉取到 master 分支,你可以运行:
$ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf
Finished one cherry-pick.
[master]: created a0a41a9: “More friendly message when locking the index fails.”
3 files changed, 17 insertions(+), 3 deletions(-)
这样会拉取和 e43a6 相同的更改,但是因为应用的日期不同,你会得到一个新的提交 SHA-1 值。现在你的历史 会变成这样:

- log 日志
MartindeMacBook-Pro:qmoorassistant martin$ git st
On branch xiaomi-api-adjust
Your branch is up to date with 'origin/xiaomi-api-adjust'.
You are currently cherry-picking commit f96b6aa.
(all conflicts fixed: run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Changes to be committed:
modified: app/src/main/assets/litepal.xml
3.5 分支的合并与创建
大家在工作,公司肯定会分支制作一些分支管理方案。比如下图:

可以看见这样的分支是git变得更有魅力,就简单讲解下分支的创建和合并。假设你已经有一个仓库并且有一个分支master。
创建developer分支
MartindeMacBook-Pro:kotlin-studio martin$ git branch developer
MartindeMacBook-Pro:kotlin-studio martin$ git checkout developer
MartindeMacBook-Pro:kotlin-studio martin$ git branch
* develop
master
创建成功后,切换到了新分支,并且打印分支情况。如果我们在developer开发后,想要将developer分支的代码整合进入master分支,操作如下:
整合developer的代码到master分支
MartindeMacBook-Pro:kotlin-studio martin$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
MartindeMacBook-Pro:kotlin-studio martin$ git merge develop
这中间需要自行处理下合并文件的代码。
3.6 删除远程分支的文件
今天遇见这样一个场景,我从远程分支上拉下载项目代码后,发现打不开提示我说项目的结构的配置文件损坏了。所以,我将项目的结构文件的.idea文件夹下的文件全部删除了,然后同步服务器,最后打开了idea重新生成文件夹,参考了下面两篇文件。
3.8 给发布版本创建tag
工作中有这样一个场景,当我们的产品上线了以后,对应的产品肯定会有发布日期和版本号,在后续开发的过程中,我们不仅需要开发新产品的功能的同时,如果这次版本发布后,有用户反馈出的bug需要及时解决,那么我们就需要快速定位代码。这个时候我们就可以使用git tag命令去给这次发布做一个标签方便我们记录线上版本的时间节点。具体行为如下:
MartindeMacBook-Pro:workphoneassistant martin$ git tag -a v1.0.7.28 -m 'version name:1.0.7.28 ,version code:27 ,publish date:2019-7-28'
MartindeMacBook-Pro:workphoneassistant martin$ git tag
v1.0.7.28
MartindeMacBook-Pro:workphoneassistant martin$ git show v1.0.7.28
tag v1.0.7.28
Tagger: martin <martinmu2013@gmail.com>
Date: Mon Jul 29 10:28:04 2019 +0800
version name:1.0.7.28 ,version code:27 ,publish date:2019-7-28
MartindeMacBook-Pro:workphoneassistant martin$ git push origin --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 191 bytes | 191.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
* [new tag] v1.0.7.28 -> v1.0.7.28
参考文章:
3.9 给主线的多个commit打patch
在参与工作中,还有这样一个流程,我们在发布版本的时候,如果测试工作中发现了这次新功能中的出现了bug的话,可能会暂时不上这个新功能上去,我们需要恢复到某一个时间节点的分支,然后再从dev分支中选择一些commit提交打入到新分支中合成一个上线版本的临时分支情况,前面讲到的cherry-pick可以做到,现在介绍一个新的方法–打补丁(patch)。
4.0 自动补全的配置
5.0 对于代码中分支管理的探讨
在日常开发中,我们肯定遇见多功能开发的问题,可能现在的公司使用feature-branch的思想开发新分支,这里介绍一些新的持续交付的新概念feature-toggle:
文章
项目
工具篇
前面我们使用了命令去进行分支管理,日常中也可以使用git插件工具进行提交。下面我来说些常用场景。
场景1:当前分支a,合并分支b,并且分支b此时有更新代码。
普通使用命令,我们肯定是先切换到b分支, 拉最新代码,然后切换到a分支,最后进行合并操作。现在使用工具就没有这么麻烦了。
- 步骤1:弹出pull的操作弹框。

- 步骤2:选择合并分支

这样就完成了我们的操作。
场景2:查询某段代码提交的历史记录。
- 步骤1:框选代码片段,右键

- 查看历史记录

在这里我们就可以查看这段代码提交的历史记录,非常的实用。
小结
这篇文章主要是用来帮助我记录git的命令学习过程,后期我还会陆续对这篇文章进行更改,慢慢完善。
本文详述了Git的基本概念,如分布式版本控制系统、文件的三种状态与工作区域,以及Git的工作流程。接着介绍了Git常用命令,包括初始化仓库、记录更新、回退操作、分支管理和标签使用等,并提供了实操案例,如合并分支、解决代码冲突、使用cherry-pick选择性拉取提交、删除远程分支文件、创建和管理标签等。此外,还讨论了Git自动补全配置和分支管理策略。

被折叠的 条评论
为什么被折叠?



