Git 常用命令介绍

配图源自 Freepik

版本控制工具有很多,比如 CVS、SVNGit 等,但目前用得最广泛的应该就是 Git 了。

下面介绍一些常用的 Git 命令。

一、全局、本地必要配置

挺有必要的,会更清晰的跟踪提交者的信息。

# 全局配置
$ git config --global user.name "your_name"
$ git config --global user.email "your_email"

# 本地配置
git config user.name "your_name"
git config user.email "your_email"

二、初始化仓库

# 初始化
$ git init

# 与远程仓库建立连接
$ git remote add origin <repo_addr>

# 修改远程仓库地址(一)
$ git remote set-url origin <repo_addr>

# 修改远程仓库地址(二)
$ git remote rm origin
$ git remote add origin <repo_addr>

# 修改远程仓库地址(三)直接修改配置文件
$ vim .git/config

三、关于克隆仓库

$ git clone <repo_addr>

# 使用 dir_name 作为克隆仓库的目录名称
$ git clone <repo_addr> <dir_name>

以上方式仅会克隆仓库的「默认分支」,通过 git branch --list 能看到本地只有一个分支。

自 2020 年 10 月起,在 GitHub 平台新创建的仓库,其默认分支名称正式调整为 main详见)。如果本地通过 git init 创建的仓库,其默认分支仍是 master 的话,可通过命令调整默认分支:

git config --global init.defaultBranch main

如果再通过新建分支再拉取指定分支,甚至可能还需要解决冲突,太繁琐了。

那么,如何快速有效的直接克隆远程指定分支?

$ git clone -b <指定分支名> <远程仓库地址>

# 指定目录名称
$ git clone -b <指定分支名> <远程仓库地址> <dir_name>

比如,我远程有 masterdevelop 两个分支,通过 git clone -b develop git@github.com:toFrankie/git_dev_demo.git 会克隆 develop 分支到本地,而且本地只有 develop 一个分支。

*部分内容源自 Git 克隆远程仓库的指定分支

四、分支操作

4.1 列出所有分支
# 列出所有本地分支
$ git branch

# 列出所有远程分支
$ git branch -r

# 列出所有本地分支和远程分支
$ git branch -a

# 如果分支太多,可以使用模糊查找
$ git branch | grep 'branch-name'
4.2 新建分支

若分支已存在,以下命令都会失败。

# 新建分支,但不会切换至新分支
$ git branch <branch-name>

# 新建分支,并切换至该分支。
$ git checkout -b <branch-name>

# 根据已有分支创建新的分支
$ git checkout -b <branch-name> origin/<远程分支名称>
# 例如,创建一个远程 develop 分支的本地分支
# git checkout -b develop origin/develop

# 重命名本地分支名称
$ git branch -m <old-branch-name> <new-branch-name>

有时候,你可能需要取出某个历史版本,可以理解为基于某个 Commit 来创建一个新的分支,就能看到历史版本了。可以使用以下命令:

# 基于 <SHA1> 新建一个新分支
$ git checkout -b <branch-name> <SHA1>

# 若不打算修改,只是想 checkout 的话
$ git checkout <SHA1>

举个例子,我们有以下 Commit Log,我需要基于 1b90fceff0f3e4f16b1b850019573d3103b69a96 的历史版本,新创建一个分支:

4.3 合并分支
# 合并指定分支到当前分支
$ git merge <branch-name>

# 工作中,特性分支合并至主干分支,通常会使用以下这个
$ git merge --no-ff <branch-name>

--no-ff(not fast forward)的作用是:要求 git merge 即使在 fast forward 条件下也要产生一个新的 Merge Commit。采用 --no-ff 的方式进行分支合并目的在于:希望保持原有「特性分支」整个提交链的完整性。

关于分支合并,有使用 git merge 的,也有使用 git rebase 的,而且不同派别还很容易争吵起来。就像缩进是采用 Tab 好还是 Space 好的争论一样,那么实际中如何权衡,根据团队而定吧。

4.4 删除分支
# 删除本地指定分支
$ git branch -d <branch-name>

# 删除远程分支
git push origin --detele <branch-name>

# 删除远程分支(方法二:向远程分支推送一个空分支)
$ git push origin :<远程分支名>
4.5 重命名远程分支

要重命名远程分支名称,其实就是先删除远程分支,然后重命名本地分支,再重新推送一个远程分支的过程。

例如,将远程分支 dev 重命名为 develop,可以这样操作:

# 1. 删除远程分支 dev
$ git push origin --delete dev

# 2. 重命名本地分支 dev 为 develop
$ git branch -m dev develop

# 3. 推送本地分支 develop
$ git push origin develop

五、暂存提交推送

5.1 暂存更改

关于 git add 命令,需要注意一下 1.x 版本与之有些不同,最后有标注。

# 提交新文件(new file)、被修改(modified)文件以及被删除(deleted)文件。
$ git add .

# 提交新文件(new file)、被修改(modified)文件以及被删除(deleted)文件。
$ git add -A

# 提交被修改(modified)和被删除(deleted)文件,不包括新文件(new file)
$ git add -u

# 提交新文件(new file)和被修改(modified),不包括被删除(deleted)文件
$ git add --ignore-removal .

# 获取帮助
$ git add -h

# 以上为 2.x 版本的标准。
# 以下为 1.x 版本的区别之处:
# 1.x 的 `git add .` 不包括被删除文件(deleted)
# 1.x 不存在 `git add --ignore-removal .` 命令,但其作用等同于 1.x 版本 `git add .`
5.2 提交暂存
# 提交已暂存文件
$ git commit -m 'commit message'

# 提交已暂存文件,以及跟踪过但未被添加到暂存的文件
# 注意:git commit -am 可以写成 git commit -a -m,但不能写成 git commit -m -a
$ git commit -am 'commit message'

# 修改最后一次的提交说明(但 commitId 会改变哦,因为它是一次全新的提交)
$ git commit --amend

注意一下,git commit --amend 命令,只能修改最新一次的提交说明 ,执行命令进入 vim 模式(具体如何插入编辑,保存退出不展开赘述了,你们都会的)。亦可通过 git commit --amend -m 'Commit Message' 直接覆盖不用进入 vim 编辑器。

需要注意的是,该命令会导致 commitId(快照唯一标识)发生改变。可通过 git log(查看历史提交记录)前后对比发现。其实呢,修改过的提交实际上是全新的提交,而先前的提交将不再位于您当前的分支上。

该命令其实还有很多选项,还能更改提交文件等,想了解请看这里

5.3 推送至远程分支

主要用于将本地更新推送到远程主机,但不同简化形式、命令参数产生延申效果。

一般地,远程主机名 remote 都为 origin

# 不省略本地分支名和远程分支名情况下,冒号(:)前后是没有空格的
$ git push <远程主机名> <本地分支名>:<远程分支名>
# git push origin master:master

还有几种简化形式的写法:

  • 省略远程分支(多分支情况下,本人常用这种形式)
# 将本地分支推送到远程主机上的同名分支。如果远程分支不存在,则会自动创建一个远程分支。
$ git push <远程主机名> <本地分支名>
# git push origin master
  • (慎用)省略本地分支(相当于删除远程分支)
# 将一个“空的本地分支”推送至远程分支,即表示删除指定的远程分支。
$ git push <远程主机名> :<远程分支名>
# git push origin :master

# 等同于
$ git push origin --delete <远程分支名>
  • (不推荐)省略本地分支、远程分支
# 将当前分支推送至远程主机上的对应分支
$ git push <远程主机名>
# git push origin

这种形式要求当前本地分支和远程分支之间存在追踪关系。

怎么理解?

首先我不推荐,而且平常也不用这种形式的进行推送的。假如有存在 masterdevelop 两个分支,当与远程分支建立追踪关系的是 master 分支,那么处于 develop 分支时,使用 git push origin 形式推送至远程主机时就会提示:The current branch test has no upstream branch.,然后再执行 git push --set-upstream origin develop 即可使用这种形式的推送。

  • 省略远程主机、本地分支、远程分支
# 将当前分支推送至远程主机对应分支
$ git push

这种形式,除了要求当前本地分支和远程分支之间存在追踪关系之外,还要求当前当前分支只有一个追踪分支。

  • 省略远程分支,添加参数 -u
# 将本地分支推送到远程主机上的同名分支。如果远程分支不存在,则会自动创建一个远程分支。
$ git push -u <远程主机名> <本地分支名>
# git push -u origin master

这种形式适用于当前分支与多个主机存在追踪关系,可以利用 -u 指定一个默认的主机,这样后面就可以不加任何参数适用 git push 推送对应的分支了。

以上指令执行之后,在 .git/config 配置文件下会有分支的对应:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = git@github.com:toFrankie/git_dev_demo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "develop"]
    remote = origin
    merge = refs/heads/develop

六、标签操作

# 列出所有 tag
$ git tag

# 查看 tag 信息
$ git show <tag-name>

# 轻量标签
$ git tag <tag-name>

# 附注标签
$ git tag -a <tag-name> -m <message>
# 例如,打一个 v1.0.0 的标签
# git tag -a v1.0.0 -m 'v1.0.0 release'

# 后期打标签
$ git tag -a <tag-name> <version>

# 提交指定 tag
$ git push origin <tag-name>

# 提交所有 tag
$ git push origin --tags

# 删除本地 tag
$ git tag -d <tag-name>

# 删除远程 tag
$ git push origin --detele tag <tag-name>

# 还可以向远程推送一个“空标签”,等同于删除远程标签
$ git push origin :refs/tags/<tag-name>

# 将本地所有不在远程仓库服务器上的标签推送至服务器
git push origin –tags

七、拉取

这里主要有两条命令 git fetchgit pull,区别如下:

  • git fetch:将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到「本地分支」中。
  • git pull:将远程主机的最新内容拉下来后直接合并,相当于:git fetch + git merge FETCH_HEAD

git fetch origin branch-name 虽说会将远程的更新拉取到本地,它会更新至本地的 origin/branch-name 的分支下,换句话说:此时 origin/branch-name 与远程的 branch-name 分支是一致的,都是最新的(请注意,本地的 origin/branch-namebranch-name 是两个独立的分支)。

如果你 Fetch 完成之后,不进行 Merge 或 Rebase 等合并操作,它是不会更新 branch-name 分支内容的。在合并之前,可以利用 git diff branch-name origin/branch-name 去对比两个分支的内容,最终决定是否要将远程的更新合并至本地的 branch-name 分支中。

7.1 git fetch

# 将 git remote 中所有关联的远程仓库包含的所有分支的更新拉取到本地
$ git fetch

# 将远程所有分支的更新拉取至本地
$ git fetch <远程主机名>

# 将远程特定分支的更新拉取至本地
$ git fetch <远程主机名> <分支名>
# git fetch origin main

当拉取成功后,会返回一个 FETCH_HEAD,指的是某个分支在服务器上的最新状态。通过以下方式可以查看刚拉取回来的更新信息:

$ git log -p FETCH_HEAD

我们来试一下,如下图:

图中可以看到一些文件更新信息,包括文件名、更新作者、更新时间、更新代码等,并通过这些信息来判断是否产生冲突。

接着,可以通过 git merge 来将这些拉取下来的最新内容合并到当前分支中:

$ git merge FETCH_HEAD

# 或者使用以下这个,其中 <branch-name> 表示要合并的分支名称,例如 origin/main
$ git merge origin/<branch-name>

7.2 git pull

# 拉取远程某分支的更新,并与本地指定分支合并
$ git pull <远程主机名> <远程分支名>:<本地分支名>
# git pull origin

# 如果远程分支与当前本地分支进行合并,则冒号及后面部分可以省略
$ git pull <远程主机名> <远程分支名>
# git pull origin <branch-name>

因此

$ git pull origin main

# 相当于
$ git fetch origin main
$ git merge FETCH_HEAD

7.3 (建议)少用 Push,多用 Fetch 和 Merge

将拉取和合并独立开来是一个较好的方法,即少用 Push,多用 Fetch 和 Merge。

git pull 的问题是它把过程的细节都隐藏了起来,以至于你不用去了解 Git 中各种类型分支的区别和使用方法。当然,多数时候这是没问题的,但一旦代码有问题,你很难找到出错的地方。看起来 git pull 的用法会使你吃惊,简单看一下 Git 的使用文档应该就能说服你。

将下载(Fetch)和合并(Merge)放到一个命令里的另外一个弊端是,你的本地工作目录在未经确认的情况下就会被远程分支更新。当然,除非你关闭所有的安全选项,否则 git pull 在你本地工作目录还不至于造成不可挽回的损失,但很多时候我们宁愿做的慢一些,也不愿意返工重来。

尤其在多人协作的时候,可能是一个复杂的合并操作,我们可以这样(以 main 分支为例):

# 1. 拉取
$ git fetch origin main

# 2. 比较
$ git diff main origin/main

# 3. 合并
$ git merge origin/main

况且,有些团队的合并操作要求使用 git rebase,而不是 git merge。当然了也有 git pull --rebase 可使用啦。

可参考文章:

未完待续...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容