Git图解

Git图解#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文基础上演绎的文章。原作者 Mark Lodato,译者 wych。原文采用创用 CC 姓名标示-非商业性-相同方式分享 3.0 美国授权条款授权。

此页图解 git 中的最常用命令。如果你稍微理解 git 的工作原理,这篇文章能够让你理解的更透彻。

基本用法#

enter image description here

上面的四条命令在工作目录、stage 缓存(也叫做索引)和 commit 历史之间复制文件。

  • git add files 把工作目录中的文件加入 stage 缓存
  • git commit 把 stage 缓存生成一次 commit,并加入 commit 历史
  • git reset -- files 撤销最后一次 git add files,你也可以用 git reset 撤销所有 stage 缓存文件
  • git checkout -- files 把文件从 stage 缓存复制到工作目录,用来丢弃本地修改

你可以用 git reset -pgit checkout -pgit add -p 进入交互模式,也可以跳过 stage 缓存直接从 commit历史取出文件或者直接提交代码。

Git代码合并选Merge还是Rebase

Git代码合并选Merge还是Rebase#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

git rebase 这个命令经常被人认为是一种 Git 巫术,初学者应该避而远之。但如果使用得当的话,它能给你的团队开发省去太多烦恼。在这篇文章中,我们会比较 git rebase 和类似的 git merge 命令,找到 Git 工作流中 rebase 的所有用法。

概述#

你要知道的第一件事是,git rebasegit merge 做的事其实是一样的。它们都被设计来将一个分支的更改并入另一个分支,只不过方式有些不同。

想象一下,你刚创建了一个专门的分支开发新功能,然后团队中另一个成员在 master 分支上添加了新的提交。这就会造成提交历史被 fork 一份,用 Git 来协作的开发者应该都很清楚。

enter image description here

现在,如果 master 中新的提交和你的工作是相关的。为了将新的提交并入你的分支,你有两个选择:merge 或 rebase。

Merge#

将 master 分支合并到 feature 分支最简单的办法就是用下面这些命令:

git checkout feature
git merge master

或者,你也可以把它们压缩在一行里。

git merge master feature

feature 分支中新的合并提交(merge commit)将两个分支的历史连在了一起。你会得到下面这样的分支结构:

enter image description here

Git代码回滚选Reset、Checkout还是Revert

Git代码回滚选Reset、Checkout还是Revert#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

git resetgit checkoutgit revert 是你的 Git 工具箱中最有用的一些命令。它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文件。

因为它们非常相似,所以我们经常会搞混,不知道什么场景下该用哪个命令。在这篇文章中,我们会比较 git resetgit checkoutgit revert 最常见的用法。希望你在看完后能游刃有余地使用这些命令来管理你的仓库。

Git repo的主要组成

Git 仓库有三个主要组成——工作目录,缓存区和提交历史。这张图有助于理解每个命令到底产生了哪些影响。当你阅读的时候,牢记这张图。

提交层面的操作#

你传给 git resetgit checkout 的参数决定了它们的作用域。如果你没有包含文件路径,这些操作对所有提交生效。我们这一节要探讨的就是提交层面的操作。注意,git revert 没有文件层面的操作。

Reset#

在提交层面上,reset 将一个分支的末端指向另一个提交。这可以用来移除当前分支的一些提交。比如,下面这两条命令让 hotfix 分支向后回退了两个提交。

git checkout hotfix
git reset HEAD~2

hotfix 分支末端的两个提交现在变成了悬挂提交。也就是说,下次 Git 执行垃圾回收的时候,这两个提交会被删除。换句话说,如果你想扔掉这两个提交,你可以这么做。reset 操作如下图所示:

把hotfix分支reset到HEAD~2

如果你的更改还没有共享给别人,git reset 是撤销这些更改的简单方法。当你开发一个功能的时候发现「糟糕,我做了什么?我应该重新来过!」时,reset 就像是 go-to 命令一样。

除了在当前分支上操作,你还可以通过传入这些标记来修改你的缓存区或工作目录:

  • –soft – 缓存区和工作目录都不会被改变
  • –mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响
  • –hard – 缓存区和工作目录都同步到你指定的提交

把这些标记想成定义 git reset 操作的作用域就容易理解多了。

Git log高级用法

Git log高级用法#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

每一个版本控制系统的出现都是为了让你记录代码的变化。你可以看到项目的历史记录——谁贡献了什么、bug 是什么时候引入的,还可以撤回有问题的更改。但是,首先你得知道如何使用它。这也就是为什么会有 git log 这个命令。

到现在为止,你应该已经知道如何用 git log 命令来显示最基本的提交信息。但除此之外,你还可以传入各种不同的参数来获得不一样的输出。

git log 有两个高级用法:一是自定义提交的输出格式,二是过滤输出哪些提交。这两个用法合二为一,你就可以找到你项目中你需要的任何信息。

格式化 Log 输出#

首先,这篇文章会展示几种 git log 格式化输出的例子。大多数例子只是通过标记向 git log 请求或多或少的信息。

如果你不喜欢默认的 git log 格式,你可以用 git config 的别名功能来给你想要的格式创建一个快捷方式。

Oneline#

--oneline 标记把每一个提交压缩到了一行中。它默认只显示提交ID和提交信息的第一行。git log --oneline 的输出一般是这样的:

0e25143 Merge branch 'feature'
ad8621a Fix a bug in the feature
16b36c6 Add a new feature
23ad9ad Add the initial code base

它对于获得项目的总体情况很有帮助。

Decorate#

很多时候,知道每个提交关联的分支或者标签很有用。--decorate 标记让 git log 显示指向这个提交的所有引用(比如说分支、标签等)。

Git 钩子:自定义你的工作流

Git 钩子:自定义你的工作流#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

Git 钩子是在 Git 仓库中特定事件发生时自动运行的脚本。它可以让你自定义 Git 内部的行为,在开发周期中的关键点触发自定义的行为。

git hook

Git 钩子最常见的使用场景包括推行提交规范,根据仓库状态改变项目环境,和接入持续集成工作流。但是,因为脚本可以完全定制,你可以用 Git 钩子来自动化或者优化你开发工作流中任意部分。

在这篇文章中,我们会先简要介绍 Git 钩子是如何工作的。然后,我们会审视一些本地和远端仓库使用最流行的钩子。

Git钩子概述#

Git 钩子是仓库中特定事件发生时 Git 自动运行的普通脚本。因此,Git 钩子安装和配置也非常容易。

钩子在本地或服务端仓库都可以部署,且只会在仓库中事件发生时被执行。在文章后面我们会具体地研究各种钩子。接下来所讲的配置对本地和服务端钩子都起作用。

安装钩子#

钩子存在于每个 Git 仓库的 .git/hooks 目录中。当你初始化仓库时,Git 自动生成这个目录和一些示例脚本。当你观察 .git/hooks 时,你会看到下面这些文件:

applypatch-msg.sample       pre-push.sample
commit-msg.sample           pre-rebase.sample
post-update.sample          prepare-commit-msg.sample
pre-applypatch.sample       update.sample
pre-commit.sample

这里已经包含了大部分可用的钩子了,但是 .sample 拓展名防止它们默认被执行。为了安装一个钩子,你只需要去掉 .sample 拓展名。或者你要写一个新的脚本,你只需添加一个文件名和上述匹配的新文件,去掉 .sample 拓展名。

比如说,试试安装一个 prepare-commit-msg 钩子。去掉脚本的 .sample 拓展名,在文件中加上下面这两行:

#!/bin/sh

echo "# Please include a useful commit message!" > $1

钩子需要能被执行,所以如果你创建了一个新的脚本文件,你需要修改它的文件权限。比如说,为了确保 prepare-commit-msg 可执行,运行下面这个命令:

Git提交引用和引用日志

Git提交引用和引用日志#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

提交是 Git 的精髓所在,你无时不刻不在创建和缓存提交、查看以前的提交,或者用各种Git命令在仓库间转移你的提交。大多数的命令都对同一个提交操作,而有些会接受提交的引用作为参数。比如,你可以给 git checkout 传入一个引用来查看以前的提交,或者传入一个分支名来切换到对应的分支。

引用一次提交的各种方式

知道提交的各种引用方式之后,Git 的命令就会变得更加强大。在这章中,我们研究提交的各种引用方式,来一窥 git checkoutgit branchgit push 等命令的工作原理。

我们还会学到如何使用 Git 的引用日志查看似乎已被删除的提交。

哈希字串#

引用一个提交最直接的方式是通过 SHA-1 的哈希字串,这是每个提交唯一的 ID。你可以在 git log 的输出中找到提交的哈希字串。

commit 0c708fdec272bc4446c6cabea4f0022c2b616eba
Author: Mary Johnson <mary@example.com>
Date:   Wed Jul 9 16:37:42 2014 -0500

    一些提交信息

在 Git 命令中传递时,你只需要提供足以确定那个提交的哈希子串即可。比如,你可以这样用 git show 的命令显示上面的提交:

git show 0c708f

有时,我们需要把分支、标签或者其他间接的引用转变成对应提交的哈希。git rev-parse 命令正是你需要的。下面这个命令返回 master 分支提交的哈希字串:

git rev-parse master

当你写的自定义脚本中需要将提交引用作为参数时,这个命令非常有用。你可以让 git rev-parse 帮你处理转换,而不用手动做这件事。

引用#

ref 是提交的间接引用。你可以把它当做哈希字串的别名,但对用户更友好。这就是 Git 内部表示分支和标签的机制。

Git常见问题20250507

git配置#

我应该在 user.name 中放什么?#

您应该填写您的个​​人姓名,通常是使用名字和姓氏的形式。例如, Git 的当前维护者使用 “Junio C Hamano” 。这将是您所做的每个提交中存储的姓名部分。

此配置对远程服务的身份验证没有任何影响;有关详细信息,请参阅 git-config[1] 中的 credential.username 。

http.postBuffer 到底起什么作用?#

此选项可更改 Git 通过 HTTP 或 HTTPS 将数据推送到远程时使用的缓冲区大小。如果数据大于此大小,处理 Git 的 HTTP 支持的 libcurl 将使用分块传输编码,因为事先不知道推送的数据的大小。

将此值保留为默认大小是可以的,除非您知道远程服务器或中间的代理不支持 HTTP/1.1(引入了分块传输编码)或已知分块数据会中断。这通常(错误地)被建议作为一般推送问题的解决方案,但由于几乎每个服务器和代理都至少支持 HTTP/1.1,因此提高此值通常无法解决大多数推送问题。无法正确支持 HTTP/1.1 和分块传输编码的服务器或代理在当今的互联网上不会那么有用,因为它会中断大量流量。

请注意,增加此值将增加 Git 通过 HTTP 或 HTTPS 执行的每个相关推送所使用的内存,因为无论是否全部使用,都会分配整个缓冲区。因此,最好将其保留为默认值,除非您确定需要不同的值。

git如何配置不同的编辑器?#

如果您没有为 Git 专门指定编辑器,它将默认使用您通过 VISUAL 或 EDITOR 环境变量配置的编辑器,如果两者都未指定,则使用系统默认编辑器(通常为 vi )。由于有些人发现 vi 难以使用或更喜欢其他编辑器,因此可能需要更改使用的编辑器。

如果要为大多数需要编辑器的程序配置通用编辑器,可以编辑 shell 配置(例如 ~/.bashrc 或 ~/.zshenv ),使其包含一行,将 EDITOR 或 VISUAL 环境变量设置为适当的值。例如,如果您更喜欢编辑器 nano ,则可以编写以下内容:

export VISUAL=nano

如果要为 Git 专门配置编辑器,可以设置 core.editor 配置值或 GIT_EDITOR 环境变量。有关这些选项的查询顺序的详细信息,请参阅 git-var[1] 。

Git备忘录

Git 是一个免费的开源分布式版本控制系统,旨在快速高效地处理从小型到超大型项目的所有项目。

Git 易于学习,占用空间小,性能快如闪电。它超越了 Subversion、CVS、Perforce 和 ClearCase 等 SCM 工具,具有廉价的本地分支、方便的暂存区域和多个工作流程等功能。

– 来自git-scm的官方介绍

git是一个分布式版本控制软件,最初由林纳斯·托瓦兹创作,于2005年以GPL许可协议发布。最初目的是为了更好地管理Linux内核开发而设计。应注意的是,这与GNU Interactive Tools(一个类似Norton Commander界面的文件管理器)不同。

git最初的开发动力来自于BitKeeper和Monotone。git最初只是作为一个可以被其他前端(比如Cogito或Stgit)包装的后端而开发的,但后来git内核已经成熟到可以独立地用作版本控制。很多被广泛使用的软件项目都使用 git 进行版本控制,其中包括 Linux 内核、X.Org服务器和OLPC内核等项目的开发流程。

下载Git for Windows

Git备忘录#

git创建仓库#

在本地初始化仓库,然后将本地仓库与一个 GitHub 上的空仓库连接起来。

$ mkdir lrepo
$ cd lrepo
$ git init
$ git remote add origin [url]

git clone一个已存在于 GitHub 上的仓库,包括所有的文件、分支和提交(commits)

$ git clone [url]

git全局配置#

## 配置用户名
$ git config --global user.name "[name]"

## 配置邮箱
$ git config --global user.email "[email address]"

### 配置彩色输出
$ git config --global color.ui auto

git分支#

分支是使用 Git 工作的一个重要部分。你做的任何提交都会发生在当前“checked out”到的分支上。使用 git status 查看那是哪个分支。

Git重写项目历史

Git重写项目历史#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

概述#

Git 的主要职责是保证你不会丢失提交的修改。但是,它同样被设计成让你完全掌控开发工作流。这包括了让你自定义你的项目历史,而这也创造了丢失提交的可能性。Git 提供了可以重写项目历史的命令,但也警告你这些命令可能会让你丢失内容。

这份教程讨论了重写提交快照的一些常见原因,并告诉你如何避免不好的影响。

git commit –amend#

git commit --amend 命令是修复最新提交的便捷方式。它允许你将缓存的修改和之前的提交合并到一起,而不是提交一个全新的快照。它还可以用来简单地编辑上一次提交的信息而不改变快照。

Git Tutorial: git commit –amend

但是,amend 不只是修改了最新的提交——它进行了一次替换。对于 Git 来说,这看上去像一个全新的提交,即上图中用星号表示的那一个。在公共仓库工作时一定要牢记这一点。

git commit --amend用法#

git commit --amend

合并缓存的修改和上一次的提交,用新的快照替换上一个提交。缓存区没有文件时运行这个命令可以用来编辑上次提交的提交信息,而不会更改快照。

讨论#

仓促的提交在你日常开发过程中时常会发生。很容易就忘记了缓存一个文件或者弄错了提交信息的格式。--amend 标记是修复这些小意外的便捷方式。

不要修复公共提交#

git reset这节中,我们说过永远不要重设和其他开发者共享的提交。对于修复也是一样:永远不要修复一个已经推送到公共仓库中的提交。

修复过的提交事实上是全新的提交,之前的提交会被移除出项目历史。这和重设公共快照的后果是一样的。如果你修复了其他开发者在之后继续开发的一个提交,看上去他们的工作基础从项目历史中消失了一样。对于在这上面的开发者来说这是很困惑的,而且很难恢复。

例子#

下面这个🌰展示了 Git 开发工作流中的一个常见情形。我们编辑了一些希望在同一个快照中提交的文件,但我们忘记添加了其中的一个。修复错误只需要缓存那个文件并且用 --amend 标记提交:

# 编辑 hello.py 和 main.py
git add hello.py
git commit

# 意识到你忘记添加 main.py 的更改
git add main.py
git commit --amend --no-edit

编辑器会弹出上一次提交的信息,加入 --no-edit 标记会修复提交但不修改提交信息。需要的话你可以修改,不然的话就像往常一样保存并关闭文件。完整的提交会替换之前不完整的提交,看上去就像我们在同一个快照中提交了 hello.pymain.py

Git保持同步

Git保持同步#

BY 童仲毅(geeeeeeeeek@github

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

SVN 使用唯一的中央仓库作为开发者之间沟通的桥梁,在开发者的工作拷贝和中央仓库之间传递变更集合(changeset),协作得以发生。这和Git的协作模型有所不同,Git 给予每个开发者一份自己的仓库拷贝,拥有自己完整的本地历史和分支结构。用户通常共享一系列的提交而不是单个变更集合。Git 允许你在仓库间共享整个分支,而不是从工作副本提交一个差异集合到中央仓库。

下面的命令让你管理仓库之间的连接,将分支「推送」到其他仓库来发布本地历史,或是将分支「拉取」到本地仓库来查看其它开发者的贡献。

git remote#

git remote 命令允许你创建、查看和删除和其它仓库之间的连接。远程连接更像是书签,而不是直接跳转到其他仓库的链接。它用方便记住的别名引用不那么方便记住的 URL,而不是提供其他仓库的实时连接。

例如,下图显示了你的仓库和中央仓库以及另一个开发者仓库之间的远程连接。你可以向 Git 命令传递 origin 和 john 的别名来引用这些仓库,替代完整的 URL。

Git Tutorial: git remote

git remote用法#

git remote

列出你和其他仓库之间的远程连接。

git remote -v

和上个命令相同,但同时显示每个连接的 URL。

git remote add <name> <url>

创建一个新的远程仓库连接。在添加之后,你可以将 <name> 作为 <url> 便捷的别名在其他 Git 命令中使用。

git remote rm <name>

移除名为的远程仓库的连接。

git remote rename <old-name> <new-name>

将远程连接从 <old-name> 重命名为 <new-name>

讨论#

Git 被设计为给每个开发者提供完全隔离的开发环境。也就是说信息并不是自动地在仓库之间传递。开发者需要手动将上游提交拉取到本地,或手动将本地提交推送到中央仓库中去。git remote 命令正是将 URL 传递给这些「共享」命令的快捷方式。