阅读 2872

Git 基本命令,你都学废了吗

概述

此篇博文意在让新手快速上手 Git,满足工作中的基本需求,而非梳理细节。后续会再开一个系列,来探讨 Git 细节问题。

一、Git 的安装

这部分网站上资料非常多,根据自己的系统版本查找资料并下载安装包安装即可。

二、初次使用 Git 之前的配置

1. 配置用户名和邮箱 

git config --global user.name "user_name" git config --global user.email "email_address" 
复制代码

2. 查看配置 

git config --list
复制代码

三、理论基础

1. 为什么要掌握 Git 命令

可能有很多小伙伴习惯了 Windows 的操作模式,对命令行相对抵触。而且市面上确实有诸如 TortoiseGit、SourceTree 等 Git 图形化工 具,使用体验也还尚可。但正所谓“Git 的设计让使用者觉得自己比想象中的笨”,Git 拥有太多强大的功能,而图形化工具中只封 装了其中的一部分,还是命令行的功能全面。其次,很多老鸟回望来路,都认为 Git 的学习确实需要自底向上的过程。掌握了命令 行,使用图形化工具如探囊取物。反之则不知其所以然,倘若后面遇到问题,就要抓瞎咯。

2. 这么多差异版本,是如何保存的

  • SVN 记录原理

SVN 记录的是每一次版本变动的内容。换句话说,SVN 只保存差异。

  • Git 记录原理

Git 记录的则是将每个版本独立保存。譬如说 File1 有 5 个版本,那就有 5 个对应的拷贝。这种方式看似更浪费空间,但在分支管理上带来了很多便利。

3. 工作区、暂存区和 Git 仓库

  • 工作区:就是我们存放代码的地方,看得见摸得着。
  • 暂存区:实际上是一个文件,其中保存我们的改动。
  • Git仓库:最终存放我们所有版本数据的位置。HEAD 指针指向的就是我们最新提交的版本。

4. Git 的工作流程

  • 在工作目录中增删、修改文件;

  • 将需要进行版本管理的文件放入暂存区;

  • 将暂存区的文件提交到 Git 仓库。

5. Git 管理的文件状态

  • 已修改(modified);

  • 已暂存(staged);

  • 已提交(committed)。

四、建仓、拉代码、添加到暂存区、提交

1. 建仓

  • 建立全新项目(空白目录)

在新建的空目录中执行以下命令,即可建仓:

git init
复制代码

建仓之后,可以看到在空白目录中新增了一个 .git 目录。这个目录就是用来跟踪版本迭代的。

  • 已有项目代码建仓

进入项目代码根目录后,执行 git init 即可。

2. 从服务器拉代码

  • 默认方式

     git clone 仓库地址
    复制代码
  • 拉取指定分支

    git clone -b branch_name 仓库地址
    复制代码

我们可以通过增加 -b branch_name 选项来指定 clone 的分支

  • 拉取所有分支

3. 将文件添加到暂存区

  • 新建一个 Readme.txt,内含部分描述信息(这是在工作区发生的)。然后将其添加到暂存区:

    git add Readme.txt
    复制代码
  • 如果我们修改了很多文件,逐一 add 过于繁琐。此时可以通过如下命令,把工作区的修改一并加入暂存区:

    git add -u
    复制代码

4. 将暂存区中的修改提交到 Git 仓库

  • 输入以下命令,将修改提交到 Git 仓库:

    git commit -m "log"
    复制代码
  • 我们还可以将略过添加暂存区的步骤,直接将文件提交到 Git 仓库:

    git commit -am "log"
    复制代码

五、查看工作状态和历史提交

1. 查看状态

我们可以使用以下命令来查看当前的状态:

git status
复制代码

2. 更新暂存区状态

某个文件已经加入暂存区,但我们又在工作区对其进行了修改,此时可以再次执行 git add,更新暂存区中的状态。

3. 还原工作区修改

如果我们在工作区修改了某个文件,但这些修改不想要了,那么可以执行以下命令,来还原工作区中的文件:

git checkout -- file_name
复制代码

这里要注意,如果暂存区中有此文件,则会用暂存区的版本来覆盖工作区。如果暂存区中没有此文件,则会以 Git 仓库中的版本来覆盖工作区中的版本。如果想还原成 Git 仓库的版本,则可以先用 :

git reset HEAD file_name
复制代码

 将其从暂存区中移出,然后再使用 :

git checkout -- file_name
复制代码

从而使工作区中的文件还原为 Git 仓库中的状态。

4. 查看历史提交

我们可以使用 git log 来查看历史提交。commit ID 是根据 sha1 算出来的。为什么不像 SVN 那样,从 1 开始排序?因为 Git 是分布式的,这样会引发冲突。

5. git log 的常用选项

  •  --decorate:显示每个commit的引用(如:分支、tag等);

  •  --oneline:单行显示(简化版 log)

  •  --graph:以图形化方式查看 commit

  •  --all:查看所有分支的 commit

六、回到过去

1. reset 命令——用 Git 仓库中的版本覆盖暂存区

  • 用 Git 仓库中 HEAD 所指版本覆盖暂存区(指定文件)

    git reset HEAD file_name
    复制代码
  • 用 Git 仓库中 HEAD 所指版本覆盖暂存区(所有文件)

    git reset HEAD
    复制代码

如何使用 Git 仓库中的其他版本覆盖暂存区

首先,假设我们在工作区的所有修改都 add 并且 commit 了,可以用下图来表示当前状态:

接下来,使用 reset 命令来回滚快照:

git reset HEAD~ 
复制代码

 ~ 表示HEAD所指版本的前一个版本,~~ 等以此类推。如果 ~ 太多不便表示,可以在 ~ 后加数字来指定

回滚之后的状态如下:

注意,reset 命令实际包含了两个动作:

  • 移动 HEAD 的指向,可以将其指向之前的快照(HEAD 指针的位置发生了改变,所以看 log 时,看不到最后一次提交的信息。要用 git reflog 才能看到所有 log)。
  • 用 HEAD 移动后指向的快照覆盖暂存区。

2. reset 命令的选项

  •  --mixed

    git reset --mixed HEAD~ 
    复制代码

--mixed 是默认选项,不写也会自动加上

移动 HEAD 的指向,可以将其指向之前的快照。并用 HEAD 移动后指向的快照覆盖暂存区。

  •  --soft

    git reset --soft HEAD~
    复制代码

使用 --soft 选项,只移动 HEAD 的指向,使其指向之前的快照,但并不覆盖暂存区中的内容。

这种用法通常用于撤销错误的 commit。

  • --hard

    git reset --hard HEAD~6
    复制代码

移动 HEAD 的指向,使其指向之前的快照。并用 HEAD 移动后指向的快照来覆盖暂存区中的内容。此外,还会将暂存区中的文件还原到工作区(也是 HEAD 所指的 Git 仓库版本的状态)。

3. 使用commit ID 来执行 reset

git reset  commit_ID 
复制代码

数 HEAD 毕竟麻烦,我们也可以使用commit ID 来指定 reset 到哪个版本(不用全部 ID,足够识别就行了)。

4. 回滚个别文件

git reset commit_ID file_name
复制代码

回滚个别文件时,HEAD 指针就不移动了。

5. reset 还可以往前滚

git reset commit_ID
复制代码

 视情况使用 --hard

七、版本对比

1. 比较工作区和暂存区的差异

git diff
复制代码

2. 比较两个历史commit

git diff commit_ID1 commit_ID2
复制代码

3. 比较工作区和 Git 仓库中的commit

git diff commit_ID 
复制代码

 commit ID 用 HEAD 这种方式也可以

4. 比较暂存区和 Git 仓库快照

git diff --cached/--staged [commit ID]
复制代码

 #如果不指定快照ID,则默认和仓库中最新commit比较

5. diff 功能概览图

八、常用的小技巧

1. 修改最后一次提交

  • 情景一:代码已经 commit 到仓库,突然想起还有两个文件没有 add。

  • 情景二:代码已经 commit 到仓库,突然想起 log 写得不全面。

执行带 --amend 选项的 commit 命令,Git 就会“更正”最近的一次提交。

git commit --amend   在接下来的界面中可修改 log

git commit --amend -m "new log"    直接提交新 log

2. 删除文件

git rm file_name
复制代码

此命令删除的只是工作区和暂存区的文件,也就是取消跟踪,下次提交时,不纳入版本控制。已经提交到 Git 仓库的文件是不会删除的,需要移动 HEAD 指针来切掉。

如果误删除,可以使用以下命令来恢复:

 git checkout -- file_name
复制代码
  • 工作区和暂存区有差异

如果某个文件在工作区和暂存区的内容不一致,git rm 执行时会报错。我们可以用:

git rm -f file_name
复制代码

这会同时把工作区和暂存区的文件删除。

如果需要只删除暂存区的文件,保存工作区的文件,则可以执行 :

git rm --cached file_name
复制代码

3. 重命名文件

git mv old_name new_name
复制代码

九、分支与分支管

1. 什么是分支?为什么要有分支?

2. 创建分支

git branch branch_name
复制代码

创建 branch_name 分支

git checkout -b branch_name
复制代码

 创建 branch_name 分支,并切换到此分支

3. 切换分支

git checkout branch_name
复制代码

4. 查看分支

  • 查看本地分支

    git branch -v
    复制代码
  • 查看远程分支

    git branch -r
    复制代码
  • 查看本地分支和远程分支

    git branch -a
    复制代码

5. 合并分支

git merge branch_name
复制代码

将 branch_name 分支合并到当前分支。

如果 merge 时提示 conflict,则需要手动解决冲突。Git 会在冲突的文件中加入一些提示。

6. 删除分支

git branch -d branch_name
复制代码

删除分支后再查看 log,会发现虽然这些分支没有了,但在这些分支上提交的Commit ID依然存在。

7. 匿名分支

git checkout commit_ID
复制代码

此时是分离头指针状态。由于我们使用了 checkout 命令,但并未创建新的分支,所以 Git 创建了一个匿名分支。既然是匿名分支,如果我们切换到其他分支,匿名分支中的所有操作都会被丢弃。所以我们可以用匿名分支来做些实验,反正没有什么影响。如果想保留匿名分支的操作,可以根据 Git 提示来操作,为其新建一个正式的分支。

8.本地分支与远程分支关联

git branch --set-upstream-to=origin/<remote_branch> local_branch
复制代码

使用git在本地新建一个分支后,需要做远程分支关联。如果没有关联,git会在下面的操作中提示你显示的添加关联。

关联目的是在执行git pull, git push操作时就不需要指定对应的远程分支,你只要没有显示指定,git pull的时候,就会提示你。

十、将本地修改推到服务器端

前面说过,Git 是分布式的 VCS 工具。我们本地有自己的仓库,服务器端有服务器端的仓库。为了确保其他人 clone 的代码中能包含我们的修改,就要把我们本地的修改推到服务器端。

我们通过 git push 命令,将本地修改推送到服务器端:

git push <远程主机名> <本地分支名>:<远程分支名>
复制代码

通常用 origin 来表示远程主机名。

1. 省略远程分支名

表示将本地分支推送到与之存在追踪关系的远程分支(通常同名)。如果该远程分支不存在,则会新建。

  • origin: 远程主机名

  • master: 本地分支名

    git push origin master
    复制代码

2. 省略本地分支名

表示删除远程分支。这一操作等同于推送一个空的本地分支到远程分支。

  •  origin : 远程主机名

  •  refs/for/master: 远程分支名

    git push origin :dev
    复制代码

3. 同时省略本地分支名和远程分支名

如果当前分支与远程分支存在追踪关系,则本地分支和远程分支都可以省略,将当前分支推送到origin主机的对应分支。

git push origin
复制代码

4. 同时省略远程主机名、本地分支名和远程分支名

如果当前分支只有一个远程分支,那么主机名都可以省略:

git push
复制代码

5. push提示reject的处理方式

如果我们本地的代码不是服务器上最新版本,push 代码时会被拒绝。此时我们要先更新本地代码,再push到服务器。

git reset --hard
复制代码

将本地代码恢复到最新commit状态

git pull --rebase
复制代码

 将服务器更新合并到本地

十一、更新本地代码

前文说到,Git 是分布式的 VCS,很多人都会向服务器端 push 修改。接下来看看,我们如何将服务器上的更新同步到本地。

1. 本地只有 master 分支,且未做修改

此时的本地代码处于 clean 状态,所以可以直接使用 git pull 来更新。

2. 本地只有 master 分支,且有修改

  • 修改需要保留

此时要先将修改 push 到服务器端,然后再使用 git pull 来更新。

  • 修改无需保留

由于修改无需保留,我们可以使用 git reset --hard 将代码恢复到 clean 状态,然后再使用

 git pull 来更新。

3. 本地在自有分支上修改

由于我们在自己的分支(假定分支名为 mybranch)上修改,master 处于 clean 状态。此时要分四步处理:

  • 切换到 master 分支:

    git checkout master
    复制代码
  •  更新 master 分支:

    git pull
    复制代码
  •  切换到 mybranch 分支:

    git checkout mybranch
    复制代码
  •  把 master 分支合并到 mybranch 分支:

    git merge master
    复制代码
文章分类
开发工具
文章标签