Git 是一个分布式版本控制系统,用于跟踪软件开发过程中对文件的修改,使得团队成员可以在不同的地方工作,同时保持代码的一致性和完整性。它由 Linus Torvalds 于 2005 年开发,主要用于 Linux 内核的开发,后来被广泛应用于各种软件项目。
一、git的特点
1、分布式
每个开发者都有完整的代码仓库副本,可以离线工作,不依赖中央服务器。不同的开发者可以通过交换补丁来协作。
2、快速高效
Git在本地做版本管理,大部分操作无需联网,速度很快。Git的分支模型和合并机制也非常高效灵活。
3、数据完整性
Git使用SHA-1算法保证数据完整性,每个文件和提交都有唯一的校验和标识。
4、分支模型
Git鼓励使用分支来进行开发、测试、发布等流程。创建、切换、合并分支都非常快捷方便。
5、staging area
Git有一个暂存区的概念,可以选择性地将修改添加到下一次提交中,让提交更条理化。
二、常用命令介绍
下面是一些Git的常用命令:
1、git init
git init
是Git的一个命令,用于在当前目录下初始化一个新的Git仓库。它会在当前目录下创建一个名为.git
的隐藏子目录,用于存储Git的所有数据和元数据。具体来说,git init
命令执行以下操作:
创建.git
目录,包含以下子目录和文件:
objects
目录:存储Git的对象数据,包括文件内容、目录树和提交信息等。refs
目录:存储引用(references),包括分支、标签等。HEAD
文件:指向当前检出的分支。config
文件:存储当前仓库的配置信息。description
文件:仓库的描述信息,主要用于GitWeb等工具。hooks
目录:存储钩子脚本。
在当前目录下创建一个默认的主分支,通常名为master
(现在新版Git默认名为main
)。
允许在当前目录下开始执行其他Git命令,如git add
、git commit
等。
使用示例:
$ mkdir myproject
$ cd myproject
$ git init
Initialized empty Git repository in /path/to/myproject/.git/
这样就在myproject
目录下初始化了一个空的Git仓库,可以开始向其中添加文件和提交了。
需要注意的是,git init
只需要在新建仓库时执行一次。如果你克隆了一个已有的Git仓库,就不需要再执行git init
了,因为.git
目录已经存在。
另外,git init
还有一些选项,比如--bare
可以创建一个裸仓库(bare repository),通常用于作为中央仓库供其他人推送和拉取。
2、git clone
git clone
是Git的一个命令,用于将一个远程Git仓库复制到本地。它会在本地创建一个与远程仓库完全一样的副本,包括所有的分支、标签和提交历史。
git clone
的基本语法如下:
git clone <repository> [<directory>]
其中:
<repository>
是远程仓库的URL,可以是以下几种格式:- HTTP(S):
https://github.com/user/repo.git
- SSH:
git@github.com:user/repo.git
- Git:
git://github.com/user/repo.git
- HTTP(S):
<directory>
是可选的,用于指定克隆到本地的目录名。如果不指定,则默认使用远程仓库的名称。
使用示例:
$ git clone https://github.com/git/git.git
Cloning into 'git'...
remote: Enumerating objects: 338123, done.
remote: Total 338123 (delta 0), reused 0 (delta 0), pack-reused 338123
Receiving objects: 100% (338123/338123), 167.38 MiB | 6.68 MiB/s, done.
Resolving deltas: 100% (253389/253389), done.
这个命令会将Git的官方仓库克隆到本地的git
目录下。克隆完成后,你就可以在本地查看和修改代码,并通过git push
将修改推送到远程仓库。
git clone
实际上是一个复合命令,它相当于依次执行了以下命令:
git init
:在本地初始化一个空的Git仓库。git remote add origin <repository>
:将远程仓库的URL添加到本地仓库的远程列表中,别名为origin
。git fetch origin
:从远程仓库获取所有分支和标签的元数据。git checkout <default-branch>
:检出远程仓库的默认分支(通常是master
或main
)。
因此,克隆得到的本地仓库已经与远程仓库建立了连接,可以直接使用git pull
和git push
与远程仓库同步。
git clone
还有一些常用的选项,比如:
--depth=<depth>
:创建一个浅克隆(shallow clone),只获取最近的<depth>
个提交,可以显著减少下载的数据量。--branch <branch>
或-b <branch>
:克隆指定的分支而不是默认分支。--recursive
:递归克隆所有的子模块。
3、git add
git add
是Git的一个命令,用于将工作区(working directory)中的修改添加到暂存区(staging area或index)。暂存区是Git在本地维护的一个临时区域,用于存放将要提交的修改。通过git add
将修改添加到暂存区,然后再使用git commit
将暂存区的修改提交到仓库,这样可以更精细地控制每次提交的内容。
git add
的基本语法如下:
git add <pathspec>...
其中<pathspec>
可以是文件名、目录名或通配符,用于指定要添加到暂存区的文件或目录。可以同时指定多个<pathspec>
。
使用示例:
# 将单个文件添加到暂存区
$ git add README.md
# 将多个文件添加到暂存区
$ git add file1.txt file2.txt
# 将所有以.js结尾的文件添加到暂存区
$ git add *.js
# 将当前目录及子目录下的所有修改添加到暂存区
$ git add .
git add
有以下几个常用选项:
-u
或--update
:只添加已经被Git跟踪的文件,不添加新文件。-A
或--all
:添加所有修改,包括新文件、修改和删除。-p
或--patch
:交互式地选择要添加的修改,可以添加文件的部分内容。-f
或--force
:强制添加被忽略的文件。
需要注意的是,git add
只是将修改添加到暂存区,并没有真正提交到仓库。要提交修改,还需要使用git commit
命令。另外,如果在git add
之后又对文件进行了修改,那么需要再次执行git add
将最新的修改添加到暂存区。
git add
是Git工作流程中非常重要的一步,它允许你在提交之前仔细检查和调整要提交的内容。合理使用git add
可以使提交更加清晰和有条理,方便后续的代码审查和版本管理。
4、git commit
git commit
是Git的一个命令,用于将暂存区(staging area)中的修改提交到本地仓库。每次提交都会在仓库中创建一个新的提交对象,包含提交的元数据(如作者、日期、提交信息等)和对应的文件快照。提交是Git版本管理的基本单位,代表了项目在某个时间点的状态。
git commit
的基本语法如下:
git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
[--dry-run] [(-c | -C | --fixup | --squash) <commit>]
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
[--date=<date>] [--cleanup=<mode>] [--[no-]status]
[-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]
其中最常用的选项是-m
,用于指定提交信息:
git commit -m "Add new feature"
这个命令会将暂存区中的修改提交到仓库,并使用"Add new feature"
作为提交信息。
如果不使用-m
选项,那么Git会打开默认的文本编辑器,让你输入提交信息。提交信息通常包括一个简短的标题(第一行)和详细的描述(空一行后的内容),用于说明这次提交的目的和内容。
以下是一些git commit
的常用选项:
-a
或--all
:自动将所有已跟踪的文件的修改添加到暂存区,然后提交。相当于先执行git add
,再执行git commit
。--amend
:修改上一次提交。可以修改提交信息,或将新的修改合并到上一次提交中。-v
或--verbose
:在提交信息的末尾显示将要提交的修改的差异(diff)。-s
或--signoff
:在提交信息的末尾添加一个Signed-off-by
行,表示你同意了Developer Certificate of Origin (DCO)。--author=<author>
:指定提交的作者,格式为Name <Email>
。--date=<date>
:指定提交的日期,格式为YYYY-MM-DD HH:MM:SS
或RFC 2822
格式。
需要注意的是,在执行git commit
之前,必须先使用git add
将修改添加到暂存区。只有暂存区中的修改才会被提交。
git commit
是Git工作流程中最关键的一步,它将你的修改永久地记录在仓库中,并生成一个新的版本。合理地组织提交,并编写清晰的提交信息,可以大大提高代码的可读性和可维护性。
5、git status
git status
是Git的一个命令,用于显示工作区和暂存区的当前状态。它会告诉你哪些文件被修改了,哪些文件被添加到了暂存区,以及哪些文件还没有被Git跟踪。通过git status
,你可以快速了解当前工作区的情况,决定下一步的操作。
git status
的基本语法如下:
git status [<options>...] [--] [<pathspec>...]
其中<pathspec>
可以用于限定显示的路径范围,<options>
可以用于控制显示的格式和详细程度。不过大多数情况下,直接执行git status
就足够了。
使用示例:
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.js
Untracked files:
(use "git add <file>..." to include in what will be committed)
new_file.txt
这个输出告诉我们:
- 当前在
master
分支上,并且与远程的origin/master
分支同步。 README.md
文件被修改了,并已经添加到暂存区,准备下次提交。main.js
文件被修改了,但还没有添加到暂存区。new_file.txt
是一个新文件,还没有被Git跟踪。
根据这些信息,我们可以决定是否需要执行git add
,git commit
或其他操作。
git status
有以下几个常用选项:
-s
或--short
:以更简洁的格式显示状态。会用两列字母表示每个文件的状态,如M
表示修改,A
表示添加,??
表示未跟踪等。-b
或--branch
:显示当前分支的名称和与远程分支的关系。--show-stash
:显示贮藏(stash)的数量。--ignored
:显示被忽略的文件。
需要注意的是,git status
只显示工作区和暂存区的状态,不显示已提交的修改。要查看提交历史,需要使用git log
等命令。
在日常开发中,养成经常执行git status
的习惯可以帮你更好地掌控工作区的状态,避免误操作。在执行git add
,git commit
,git push
等关键操作之前,都建议先执行一下git status
,确认状态符合预期。
6、git log
git log
命令用于查看 Git 仓库中的提交记录。它会按时间倒序列出所有的提交记录,每个提交记录都包含以下信息:
- SHA-1 校验和: 一个唯一标识该提交的哈希值
- 作者名字和邮箱
- 提交时间
- 提交说明
使用 git log
时,你可以添加一些选项来自定义输出格式和内容。下面是一些常用选项:
--oneline
: 将每个提交记录压缩到一行--graph
: 以 ASCII 图形显示分支合并历史--decorate
: 显示指向当前提交的引用(如 HEAD、分支、标签等)--stat
: 显示每次提交所引入的文件修改统计信息--shortstat
: 仅显示 --stat 中最后的行数修改添加移除统计--name-only
: 显示已修改的文件清单--relative-date
: 使用较短的相对时间显示 (例如,"2 weeks ago")--after
和--before
: 根据日期过滤提交记录--author
: 根据作者过滤提交记录--grep
: 根据提交说明过滤提交记录
例如:
$ git log --oneline --decorate --graph --all
这个命令会以简洁的单行格式显示所有分支的提交记录,并以 ASCII 图形表示分支合并历史,同时显示指向每个提交的引用。
git log
是了解项目历史和调试问题的重要工具。通过合理使用过滤选项,你可以快速找到感兴趣的提交记录。
7、git diff
git diff
是 Git 版本控制系统中另一个常用的命令,用于查看文件或提交之间的差异。它可以比较工作区、暂存区和提交之间的差异,以便了解代码的变更情况。
以下是 git diff
命令的一些常见用法和选项:
-
比较工作区与暂存区的差异:
git diff
不带任何选项的
git diff
命令会比较工作区与暂存区之间的差异,显示尚未暂存的文件修改。 -
比较暂存区与最新提交的差异:
git diff --staged
使用
--staged
选项会比较暂存区与最新提交之间的差异,显示已经暂存但尚未提交的文件修改。 -
比较两个提交之间的差异:
git diff <commit1> <commit2>
通过指定两个提交的引用(如提交的 SHA-1 校验和或分支名),可以比较两个提交之间的差异。
-
比较当前分支与其他分支的差异:
git diff <branch>
通过指定分支名,可以比较当前分支与其他分支之间的差异。
-
比较指定文件的差异:
git diff -- <file>
通过指定文件路径,可以只查看特定文件的差异。
-
显示差异的统计信息:
git diff --stat
使用
--stat
选项会显示差异的统计信息,包括修改的文件数量和每个文件的修改行数。 -
忽略空白字符的差异:
git diff -w
使用
-w
选项会忽略空白字符的差异,只关注实际代码的变更。 -
显示差异的上下文行数:
git diff -U<n>
使用
-U<n>
选项可以指定显示差异时的上下文行数,默认为 3 行。例如git diff -U10
会显示差异的前后 10 行上下文。
git diff
命令的输出通常使用 Unix 的 diff 格式,其中以 -
开头的行表示删除的内容,以 +
开头的行表示新增的内容。
通过灵活运用 git diff
命令的不同选项和参数,可以方便地查看代码的变更情况,了解不同版本或分支之间的差异。这对于代码审查、问题定位和合并冲突解决等任务非常有帮助。
8、git branch
git branch
是 Git 版本控制系统中用于管理分支的命令。分支是 Git 的一个重要特性,它允许在不影响主线开发的情况下进行独立的开发和实验。
以下是 git branch
命令的一些常见用法和选项:
-
列出所有分支:
git branch
不带任何选项的
git branch
命令会列出本地仓库中的所有分支,当前分支会以星号(*
)标记。 -
创建新分支:
git branch <branch-name>
通过指定新的分支名,可以创建一个新的分支。新分支将从当前所在的提交位置开始。
-
切换分支:
git checkout <branch-name>
使用
git checkout
命令可以切换到指定的分支。切换分支会将工作区的文件内容更新为目标分支的最新状态。 -
创建并切换到新分支:
git checkout -b <branch-name>
使用
git checkout -b
命令可以创建一个新分支并立即切换到该分支,相当于执行了git branch <branch-name>
和git checkout <branch-name>
两个命令。 -
删除分支:
git branch -d <branch-name>
使用
git branch -d
命令可以删除指定的分支。如果该分支还没有被合并到其他分支,Git 会提示无法删除。 -
强制删除分支:
git branch -D <branch-name>
使用
git branch -D
命令可以强制删除指定的分支,即使该分支还没有被合并。请谨慎使用该命令,因为它会丢失未合并的更改。 -
列出远程分支:
git branch -r
使用
git branch -r
命令可以列出远程仓库中的所有分支。 -
列出所有分支(本地和远程):
git branch -a
使用
git branch -a
命令可以列出本地和远程仓库中的所有分支。 -
重命名分支:
git branch -m <old-branch-name> <new-branch-name>
使用
git branch -m
命令可以重命名当前分支。如果要重命名其他分支,需要先切换到该分支,然后执行重命名命令。
通过 git branch
命令,可以方便地管理和操作分支,实现并行开发、特性开发、bug 修复等工作流。结合其他 Git 命令,如 git merge
和 git rebase
,可以灵活地进行分支合并和变基操作,以保持代码的整洁和可维护性。
9、git checkout
git checkout
是 Git 版本控制系统中一个非常常用的命令,用于在不同的分支、提交或文件版本之间进行切换。它可以将工作区的文件内容更新为指定分支、提交或文件的状态。
以下是 git checkout
命令的一些常见用法和选项:
-
切换到指定分支:
git checkout <branch-name>
通过指定分支名,可以切换到该分支。切换分支会将工作区的文件内容更新为目标分支的最新状态。
-
创建并切换到新分支:
git checkout -b <branch-name>
使用
git checkout -b
命令可以创建一个新分支并立即切换到该分支,相当于执行了git branch <branch-name>
和git checkout <branch-name>
两个命令。 -
切换到指定提交:
git checkout <commit-hash>
通过指定提交的哈希值(或部分哈希值),可以将工作区的文件内容更新为该提交时的状态。这会使仓库处于"分离头指针"状态,即不在任何分支上。
-
切换到指定标签:
git checkout <tag-name>
通过指定标签名,可以将工作区的文件内容更新为该标签对应的提交状态。同样会使仓库处于"分离头指针"状态。
-
切换到指定文件的特定版本:
git checkout <commit-hash> -- <file-path>
通过指定提交的哈希值和文件路径,可以将指定文件恢复到该提交时的状态,而不影响其他文件。
-
丢弃工作区的修改:
git checkout -- <file-path>
使用
git checkout --
命令可以丢弃工作区中指定文件的修改,将其恢复为最近一次提交的状态。请谨慎使用该命令,因为它会丢失未提交的更改。 -
切换到上一个分支:
git checkout -
使用
git checkout -
命令可以快速切换到上一个所在的分支。
需要注意的是,在切换分支或提交时,如果工作区有未提交的修改且与目标分支或提交有冲突,Git 会阻止切换操作以防止数据丢失。此时,可以先提交或暂存修改,或者使用 git stash
命令将修改暂存起来,然后再进行切换。
git checkout
命令提供了灵活的方式来切换和探索不同的分支、提交和文件版本,是 Git 工作流中不可或缺的一部分。结合其他 Git 命令,如 git branch
、git merge
和 git reset
,可以高效地管理和操作代码仓库。
10、git merge
git merge
是 Git 版本控制系统中用于合并分支的命令。它可以将一个分支的更改合并到当前分支,从而将不同分支上的开发工作整合在一起。
以下是 git merge
命令的一些常见用法和注意事项:
-
合并指定分支到当前分支:
git merge <branch-name>
在当前分支上执行
git merge
命令,并指定要合并的分支名,可以将指定分支的更改合并到当前分支。 -
合并时自动提交:
git merge --no-ff <branch-name>
使用
--no-ff
选项可以强制创建一个新的合并提交,即使可以进行快进式合并(fast-forward merge)。这样可以在历史记录中清晰地看到合并操作。 -
中止合并操作:
git merge --abort
如果在合并过程中发生冲突或想要中止合并,可以使用
--abort
选项来还原合并前的状态,并丢弃合并过程中的更改。 -
解决合并冲突:
当合并分支时,如果存在冲突的文件,Git 会标记这些文件并暂停合并过程。此时需要手动解决冲突,编辑冲突文件,并将修改后的文件暂存和提交。解决冲突后,可以继续合并操作。
-
合并策略:
Git 提供了不同的合并策略,可以根据需要选择合适的策略。默认使用的是 "recursive" 策略,它会尝试自动解决冲突。其他常见的合并策略包括 "resolve"、"octopus" 等。
-
预览合并结果:
git merge --no-commit --no-ff <branch-name>
使用
--no-commit
选项可以在合并完成后暂停提交,以便在提交之前检查合并结果。这样可以在确认无误后再手动提交合并。 -
合并特定提交:
git cherry-pick <commit-hash>
使用
git cherry-pick
命令可以将指定提交的更改合并到当前分支,而无需合并整个分支。这在需要选择性地应用某些提交时非常有用。
在进行合并操作时,建议先确保当前分支和要合并的分支都已经提交了最新的更改,并且在合并前先拉取远程仓库的最新状态,以减少冲突的可能性。
合并操作可能会引入冲突,需要仔细处理和解决冲突,以确保代码的正确性和一致性。在解决冲突时,可以使用 Git 提供的工具和编辑器,如 git mergetool
和 git difftool
,以便更方便地比较和修改冲突文件。
11、git push
git push
是 Git 版本控制系统中用于将本地仓库的更改推送到远程仓库的命令。它可以将本地分支的提交上传到远程仓库,使其他人可以访问和协作。
以下是 git push
命令的一些常见用法和选项:
-
推送当前分支到远程仓库:
git push
在当前分支上执行
git push
命令,会将当前分支的本地提交推送到关联的远程仓库分支。如果当前分支已经与远程分支建立了追踪关系,则可以省略远程仓库名和分支名。 -
推送指定分支到远程仓库:
git push <remote> <branch>
通过指定远程仓库名(如
origin
)和分支名,可以将指定分支的本地提交推送到远程仓库的对应分支。 -
推送所有分支到远程仓库:
git push --all
使用
--all
选项可以将所有本地分支的提交推送到远程仓库的对应分支。 -
推送标签到远程仓库:
git push --tags
使用
--tags
选项可以将本地创建的标签推送到远程仓库。 -
强制推送:
git push --force
使用
--force
选项可以强制推送本地分支到远程仓库,即使存在冲突或远程分支具有不同的提交历史。请谨慎使用该选项,因为它可能会覆盖远程仓库的提交。 -
设置上游分支:
git push -u <remote> <branch>
使用
-u
选项可以在推送时设置当前分支的上游分支,建立本地分支与远程分支的追踪关系。设置后,后续的git push
和git pull
操作可以省略远程仓库名和分支名。 -
删除远程分支:
git push <remote> --delete <branch>
通过指定远程仓库名和分支名,并使用
--delete
选项,可以删除远程仓库中的指定分支。
在推送之前,建议先使用 git pull
命令拉取远程仓库的最新更改,以确保本地分支与远程分支的同步。如果在推送过程中遇到冲突,需要先解决冲突,然后再进行推送。
推送操作将本地的提交上传到远程仓库,使其他协作者可以访问和获取最新的代码更改。它是分布式版本控制的核心操作之一,促进了团队成员之间的协作和代码共享。
需要注意的是,推送操作可能会影响其他人的工作,因此在推送前应该与团队成员进行沟通和协调,遵循适当的分支管理策略和工作流程,以减少冲突和确保代码的稳定性。
12、git pull
git pull
是 Git 版本控制系统中用于从远程仓库获取最新更改并合并到本地分支的命令。它相当于执行了 git fetch
和 git merge
两个命令的组合。
以下是 git pull
命令的一些常见用法和选项:
-
拉取当前分支的最新更改:
git pull
在当前分支上执行
git pull
命令,会从关联的远程仓库分支获取最新的提交,并将其合并到本地分支。如果当前分支已经与远程分支建立了追踪关系,则可以省略远程仓库名和分支名。 -
拉取指定远程仓库和分支的更改:
git pull <remote> <branch>
通过指定远程仓库名(如
origin
)和分支名,可以从指定的远程仓库分支获取最新的提交,并将其合并到当前本地分支。 -
拉取并重置本地分支到远程分支的状态:
git pull --rebase
使用
--rebase
选项可以在拉取远程更改时使用变基(rebase)操作,将本地分支的提交重放到远程分支的最新状态之上。这样可以保持提交历史的线性性,避免不必要的合并提交。 -
拉取并解决合并冲突:
在执行
git pull
命令时,如果本地分支和远程分支存在冲突的更改,Git 会提示存在合并冲突。此时需要手动解决冲突,编辑冲突文件,并将修改后的文件暂存和提交。解决冲突后,合并操作将自动完成。 -
仅获取远程更改而不合并:
git fetch
使用
git fetch
命令可以从远程仓库获取最新的提交和分支信息,但不会自动合并到本地分支。这样可以在合并之前检查和比较远程更改,或者在合并前切换到其他分支。
在执行 git pull
命令之前,建议先确保本地工作区的更改已经提交或暂存,以避免在合并过程中引入冲突。如果在拉取过程中遇到冲突,需要仔细解决冲突,确保代码的正确性和一致性。
拉取操作使本地分支与远程分支保持同步,获取其他协作者的最新更改。它是团队协作中非常常见的操作,确保每个成员都能及时获得最新的代码版本。
需要注意的是,在拉取之前,应该先了解远程分支的状态和更改内容,以便更好地理解和处理可能出现的冲突。同时,也要遵循团队的分支管理策略和工作流程,与其他成员进行有效的沟通和协调,以减少冲突和确保代码的稳定性。
Git还有很多高级用法,如变基(rebase)、子模块、钩子脚本等,可以实现更复杂的版本管理和工作流程。总之Git是一个功能强大、灵活高效的版本控制工具,适合各种规模的软件项目,被广泛应用于开源社区和商业公司。学习掌握Git已成为现代程序员的必备技能之一。