创建仓库
git init
git init
命令创建一个新的 Git 仓库。它用来将已存在但还没有版本控制的项目转换成一个 Git 仓库,或者创建一个空的新仓库。大多数Git命令在未初始化的仓库中都是无法使用的,所以这就是你运行新项目的第一个命令了。
运行 git init
命令会在你项目的根目录下创建一个新的 .git
目录,其中包含了你项目必需的所有元数据。除了 .git
目录之外,已经存在的项目不会被改变(就像 SVN 一样,Git 不强制每个子目录中都有一个 .git
目录)。
用法
git init
将当前的目录转换成一个 Git 仓库。它在当前的目录下增加了一个 .git
目录,于是就可以开始记录项目版本了。
git init <directory>
在指定目录创建一个空的 Git 仓库。运行这个命令会创建一个名为 directory
,只包含 .git
子目录的空目录。
git init --bare <directory>
初始化一个裸的 Git 仓库,但是忽略工作目录。共享的仓库应该总是用 --bare
标记创建(见下面的讨论)。一般来说,用 —bare
标记初始化的仓库以 .git
结尾。比如,一个叫my-project
的仓库,它的空版本应该保存在 my-project.git
目录下。
git clone
git clone
命令拷贝整个 Git 仓库。这个命令就像 svn checkout
一样,除了「工作副本」是一个完备的Git仓库——它包含自己的历史,管理自己的文件,以及环境和原仓库完全隔离。
为了方便起见,clone
自动创建了一个名为 origin
的远程连接,指向原有仓库。这让和中央仓库之间的交互更加简单。
用法
git clone <repo>
将位于 <repo>
的仓库克隆到本地机器。原仓库可以在本地文件系统中,或是通过 HTTP 或 SSH 连接的远程机器。
git clone <repo> <directory>
将位于 <repo>
的仓库克隆到本地机器上的 <directory>
目录。
git config
git config
命令允许你在命令行中配置你的 Git 安装(或是一个独立仓库)。这个命令定义了所有配置,从用户信息到仓库行为等等。一些常见的配置命令如下所列。
用法
git config user.name <name>
定义当前仓库所有提交使用的作者姓名。通常来说,你希望使用 --global
标记设置当前用户的配置项。
git config --global user.name <name>
定义当前用户所有提交使用的作者姓名。
git config --global user.email <email>
定义当前用户所有提交使用的作者邮箱。
git config --global alias.<alias-name> <git-command>
为Git命令创建一个快捷方式(别名)。
git config --system core.editor <editor>
定义当前机器所有用户使用命令时用到的文本编辑器,如 git commit
。<editor>
参数用编辑器的启动命令(如 vi)替代。
git config --global --edit
用文本编辑器打开全局配置文件,手动编辑。
保存更改
git add
git add
命令将工作目录中的变化添加到暂存区。它告诉 Git 你想要在下一次提交时包含这个文件的更新。但是,git add
不会实质上地影响你的仓库——在你运行 git commit
前更改都还没有真正被记录。
使用这些命令的同时,你还需要 git status
来查看工作目录和暂存区的状态。
用法
git add <file>
将 <file>
中的更改加入下次提交的缓存。
git add <directory>
将 <directory>
下的更改加入下次提交的缓存。
git add -i
开始交互式的缓存,你可以选择文件的一部分加入到下次提交缓存。它会向你展示一堆更改,等待你输入一个命令。y
将这块更改加入缓存,n
忽略这块更改,s
将它分割成更小的块,e
手动编辑这块更改,以及 q
退出。
git commit
git commit
命令将缓存的快照提交到项目历史。提交的快照可以认为是项目安全的版本,Git 永远不会改变它们,除非你这么要求。和 git add
一样,这是最重要的 Git 命令之一。
尽管和它和 svn commit
名字一样,但实际上它们毫无关联。快照被提交到本地仓库,不会和其他 Git 仓库有任何交互。
用法
git commit
提交已经缓存的快照。它会运行文本编辑器,等待你输入提交信息。当你输入信息之后,保存文件,关闭编辑器,创建实际的提交。
git commit -m "<message>"
提交已经缓存的快照。但将 <message>
作为提交信息,而不是运行文本编辑器。
git commit -a
提交一份包含工作目录所有更改的快照。它只包含跟踪过的文件的更改(那些之前已经通过 git add
添加过的文件)。
查看状态
git status
git status
命令显示工作目录和缓存区的状态。你可以看到哪些更改被缓存了,哪些还没有,以及哪些还未被 Git 追踪。status 的输出 不会 告诉你任何已提交到项目历史的信息。如果你想看的话,应该使用 git log
命令。
用法
git status
列出已缓存、未缓存、未追踪的文件。
git log
git log
命令显示已提交的快照。你可以列出项目历史,筛选,以及搜索特定更改。git status
允许你查看工作目录和缓存区,而 git log
只作用于提交的项目历史。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agejKIu4-1624792561395)(https://wac-cdn.atlassian.com/dam/jcr:52d530ce-7f51-48e3-920b-a18f776048d3/01.svg)]
log 输出可以有很多种自定义的方式,从简单地筛选提交,到用完全自定义的格式显示。其中一些最常用的 git log
配置如下所示。
用法
git log
使用默认格式显示完整地项目历史。如果输出超过一屏,你可以用 空格键
来滚动,按 q
退出。
git log -n <limit>
用 <limit>
限制提交的数量。比如 git log -n 3
只会显示 3 个提交。
git log --oneline
将每个提交压缩到一行。当你需要查看项目历史的上层情况时这会很有用。
git log --stat
除了 git log
信息之外,包含哪些文件被更改了,以及每个文件相对的增删行数。
git log -p
显示代表每个提交的一堆信息。显示每个提交全部的差异(diff),这也是项目历史中最详细的视图。
git log --author="<pattern>"
搜索特定作者的提交。<pattern>
可以是字符串或正则表达式。
git log --grep="<pattern>"
搜索提交信息匹配特定 <pattern>
的提交。<pattern>
可以是字符串或正则表达式。
git log <since>..<until>
只显示发生在 <since>
和 <until>
之间的提交。两个参数可以是提交 ID、分支名、HEAD
或是任何一种引用。
git log <file>
只显示包含特定文件的提交。查找特定文件的历史这样做会很方便。
git log --graph --decorate --oneline
还有一些有用的选项。--graph
标记会绘制一幅字符组成的图形,左边是提交,右边是提交信息。--decorate
标记会加上提交所在的分支名称和标签。--oneline
标记将提交信息显示在同一行,一目了然。
检出
git checkout
git checkout
这个命令有三个不同的作用:检出文件、检出提交和检出分支。在这一章中,我们只关心前两种用法。
检出提交会使工作目录和这个提交完全匹配。你可以用它来查看项目之前的状态,而不改变当前的状态。检出文件使你能够查看某个特定文件的旧版本,而工作目录中剩下的文件不变。
用法
git checkout master
回到 master 分支。分支会在下一节中讲到,而现在,你只需要将它视为回到项目「当前」状态的一种方式。
git checkout <commit> <file>
查看文件之前的版本。它将工作目录中的 <file>
文件变成 <commit>
中那个文件的拷贝,并将它加入缓存区。
git checkout <commit>
更新工作目录中的所有文件,使得和某个特定提交中的文件一致。你可以将提交的哈希字串,或是标签作为 <commit>
参数。这会使你处在分离 HEAD 的状态。
回滚
git revert
git revert
命令用来撤销一个已经提交的快照。但是,它是通过搞清楚如何撤销这个提交引入的更改,然后在最后加上一个撤销了更改的 新 提交,而不是从项目历史中移除这个提交。这避免了Git丢失项目历史,这一点对于你的版本历史和协作的可靠性来说是很重要的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HfLbCU42-1624792661778)(https://wac-cdn.atlassian.com/dam/jcr:b6fcf82b-5b15-4569-8f4f-a76454f9ca5b/03%20(7)].svg)
用法
git revert <commit>
生成一个撤消了 <commit>
引入的修改的新提交,然后应用到当前分支。
git reset
如果说 git revert
是一个撤销更改安全的方式,你可以将 git reset
看做一个 危险 的方式。当你用 git reset
来重设更改时(提交不再被任何引用或引用日志所引用),我们无法获得原来的样子——这个撤销是永远的。使用这个工具的时候务必要小心,因为这是少数几个可能会造成工作丢失的命令之一。
和 git checkout
一样,git reset
有很多种用法。它可以被用来移除提交快照,尽管它通常被用来撤销缓存区和工作目录的修改。不管是哪种情况,它应该只被用于 本地 修改——你永远不应该重设和其他开发者共享的快照。
用法
git reset <file>
从缓存区移除特定文件,但不改变工作目录。它会取消这个文件的缓存,而不覆盖任何更改。
git reset
重设缓冲区,匹配最近的一次提交,但工作目录不变。它会取消 所有 文件的缓存,而不会覆盖任何修改,给你了一个重设缓存快照的机会。
git reset --hard
重设缓冲区和工作目录,匹配最近的一次提交。除了取消缓存之外,--hard
标记告诉 Git 还要重写所有工作目录中的更改。换句话说:它清除了所有未提交的更改,所以在使用前确定你想扔掉你所有本地的开发。
git reset <commit>
将当前分支的末端移到 <commit>
,将缓存区重设到这个提交,但不改变工作目录。所有 <commit>
之后的更改会保留在工作目录中,这允许你用更干净、原子性的快照重新提交项目历史。
git reset --hard <commit>
将当前分支的末端移到 <commit>
,将缓存区和工作目录都重设到这个提交。它不仅清除了未提交的更改,同时还清除了 <commit>
之后的所有提交。
git clean
git clean
命令将未跟踪的文件从你的工作目录中移除。它只是提供了一条捷径,因为用 git status
查看哪些文件还未跟踪然后手动移除它们也很方便。和一般的 rm
命令一样,git clean
是无法撤消的,所以在删除未跟踪的文件之前想清楚,你是否真的要这么做。
git clean
命令经常和 git reset --hard
一起使用。记住,reset 只影响被跟踪的文件,所以还需要一个单独的命令来清理未被跟踪的文件。这个两个命令相结合,你就可以将工作目录回到之前特定提交时的状态。
用法
git clean -n
执行一次git clean的『演习』。它会告诉你那些文件在命令执行后会被移除,而不是真的删除它。
git clean -f
移除当前目录下未被跟踪的文件。-f
(强制)标记是必需的,除非 clean.requireForce
配置项被设为了 false
(默认为 true
)。它 不会 删除 .gitignore
中指定的未跟踪的文件。
git clean -f <path>
移除未跟踪的文件,但限制在某个路径下。
git clean -df
移除未跟踪的文件,以及目录。
git clean -xf
移除当前目录下未跟踪的文件,以及 Git 一般忽略的文件。
项目同步
git remote
git remote
命令允许你创建、查看和删除和其它仓库之间的连接。远程连接更像是书签,而不是直接跳转到其他仓库的链接。它用方便记住的别名引用不那么方便记住的 URL,而不是提供其他仓库的实时连接。
例如,下图显示了你的仓库和中央仓库以及另一个开发者仓库之间的远程连接。你可以向 Git 命令传递 origin 和 john 的别名来引用这些仓库,替代完整的 URL。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HLkI4lui-1624792712381)(https://www.atlassian.com/dam/jcr:df13d351-6189-4f0b-94f0-21d3fcd66038/01.svg)]
用法
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 fetch
git fetch
命令将提交从远程仓库导入到你的本地仓库。拉取下来的提交储存为远程分支,而不是我们一直使用的普通的本地分支。你因此可以在整合进你的项目副本之前查看更改。
用法
git fetch <remote>
拉取仓库中所有的分支。同时会从另一个仓库中下载所有需要的提交和文件。
git fetch <remote> <branch>
和上一个命令相同,但只拉取指定的分支。
git pull
在基于 Git 的协作工作流中,将上游更改合并到你的本地仓库是一个常见的工作。我们已经知道应该使用 git fetch
,然后是 git merge
,但是 git pull
将这两个命令合二为一。
用法
git pull <remote>
拉取当前分支对应的远程副本中的更改,并立即并入本地副本。效果和 git fetch
后接 git merge origin/.
一致。
git pull --rebase <remote>
和上一个命令相同,但使用 git rebase
合并远程分支和本地分支,而不是使用 git merge
。
git push
Push 是你将本地仓库中的提交转移到远程仓库中时要做的事。它和 git fetch
正好相反,fetch 将提交导入到本地分支,而 push 将提交导出到远程分支。它可以覆盖已有的更改,所以你需要小心使用。这些情况请见下面的讨论。
用法
git push <remote> <branch>
将指定的分支推送到 <remote>
上,包括所有需要的提交和提交对象。它会在目标仓库中创建一个本地分支。为了防止你覆盖已有的提交,如果会导致目标仓库非快速向前合并时,Git 不允许你 push。
git push <remote> --force
和上一个命令相同,但即使会导致非快速向前合并也强制推送。除非你确定你所做的事,否则不要使用 --force
标记。
git push <remote> --all
将所有本地分支推送到指定的远程仓库。
git push <remote> --tags
当你推送一个分支或是使用 --all
选项时,标签不会被自动推送上去。--tags
将你所有的本地标签推送到远程仓库中去。
分支
git branch
分支代表了一条独立的开发流水线。分支是我们在第二篇中讨论过的「编辑/缓存/提交」流程的抽象。你可以把它看作请求全新「工作目录、缓存区、项目历史」的一种方式。新的提交被存放在当前分支的历史中,导致了项目历史被 fork 了一份。
git branch
命令允许你创建、列出、重命名和删除分支。它不允许你切换分支或是将被 fork 的历史放回去。因此,git branch
和 git checkout
、git merge
这两个命令通常紧密地结合在一起使用。
用法
git branch
列出仓库中所有分支。
git branch <branch>
创建一个名为 <branch>
的分支。不会 自动切换到那个分支去。
git branch -d <branch>
删除指定分支。这是一个安全的操作,Git 会阻止你删除包含未合并更改的分支。
git branch -D <branch>
强制删除指定分支,即使包含未合并更改。如果你希望永远删除某条开发线的所有提交,你应该用这个命令。
git branch -m <branch>
将当前分支命名为 <branch>
。
git checkout
git checkout
命令允许你切换用 git branch
创建的分支。查看一个分支会更新工作目录中的文件,以符合分支中的版本,它还告诉 Git 记录那个分支上的新提交。将它看作一个选中你正在进行的开发的一种方式。
在上一篇中,我们看到了如何用 git checkout
来查看旧的提交。「查看分支」和「将工作目录更新到选中的版本/修改」很类似;但是,新的更改 会 保存在项目历史中——这不是一个只读的操作。
用法
git checkout <existing-branch>
查看特定分支,分支应该已经通过 git branch
创建。这使得 <existing-branch>
成为当前的分支,并更新工作目录的版本。
git checkout -b <new-branch>
创建并查看 <new-branch>
,-b
选项是一个方便的标记,告诉Git在运行 git checkout <new-branch>
之前运行 git branch <new-branch>
。
git checkout -b <new-branch> <existing-branch>
和上一条相同,但将 <existing-branch>
作为新分支的基,而不是当前分支。
git merge
合并是 Git 将被 fork 的历史放回到一起的方式。git merge
命令允许你将 git branch
创建的多条分支合并成一个。
注意,下面所有命令将更改 并入 当前分支。当前分支会被更新,以响应合并操作,但目标分支完全不受影响。也就是说 git merge
经常和 git checkout
一起使用,选择当前分支,然后用 git branch -d
删除废弃的目标分支。
用法
git merge <branch>
将指定分支并入当前分支。Git 会决定使用哪种合并算法(下文讨论)。
git merge --no-ff <branch>
将指定分支并入当前分支,但 总是 生成一个合并提交(即使是快速向前合并)。这可以用来记录仓库中发生的所有合并。