💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## git config 初次运行 Git 前的配置——`git config` `git config` 工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置: 1. `etc/gitconfig` 文件:包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 --system 选项的 git config 时,它会从此文件读写配置变量。 2. `~/.gitconfig` 或 `~/.config/git/config` 文件:只针对当前用户。 可以传递 --global 选项让 Git 读写此文件。 3. `.git/config`文件:当前使用仓库的 Git 目录中的 config 文件,针对该仓库有效。 每一个级别覆盖上一级别的配置,所以 `.git/config` 的配置变量会覆盖 `/etc/gitconfig` 中的配置变量。 在 Windows 系统中,Git 会查找 $HOME 目录下(一般情况下是 C:\Users\$USER)的.gitconfig 文件。 Git 同样也会寻找 /etc/gitconfig 文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。 ### 用户信息 当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改: ~~~bash $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com ~~~ >[warning] 如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 >当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global 选项的命令来配置。 ### 文本编辑器 Git 会使用操作系统默认的文本编辑器,通常是 Vim(Linux)。 如果你想使用不同的文本编辑器,例如 Emacs(Mac),可以这样做: ~~~bash $ git config --global core.editor emacs ~~~ ### 检查配置信息 使用 `git config --list` 命令来列出所有 Git 当时能找到的配置。 ~~~bash $ git config --list user.name=John Doe user.email=johndoe@example.com color.status=auto color.branch=auto color.interactive=auto color.diff=auto ~~~ 可能会看到重复的变量名,因为 Git 会从不同的文件中读取同一个配置(例如:`/etc/gitconfig` 与 `~/.gitconfig`)。 这种情况下,Git 会使用它找到的每一个变量的最后一个配置。 可以通过输入 `git config <key>`: 来检查 Git 的某一项配置 ~~~bash $ git config user.name John Doe ~~~ ## git help 获取帮助 若你使用 Git 时需要获取帮助,有三种方法可以找到 Git 命令的使用手册: ~~~bash $ git help <verb> $ git <verb> --help $ man git-<verb> ~~~ 例如,要想获得 config 命令的手册,执行 ~~~bash $ git help config ~~~ 这些命令很棒,因为你随时随地可以使用而无需联网。 如果你觉得手册或者本书的内容还不够用,你可以尝试在 Freenode IRC 服务器( irc.freenode.net )的 #git 或 #github 频道寻求帮助。 这些频道经常有上百人在线,他们都精通 Git 并且乐于助人。 ## git init ### 在空目录中初始化仓库 进入该目录并输入: ~~~bash $ git init ~~~ 该命令将创建一个名为` .git` 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。 ### 在非空目录中初始化仓库 通过 `git add` 命令来实现对指定文件的跟踪,然后执行 `git commit` 提交: ~~~bash $ git add *.c $ git add LICENSE $ git commit -m 'initial project version' ~~~ 就得到了一个实际维护(或者说是跟踪)着若干个文件的 Git 仓库。 ## git clone 获得一份已经存在了的 Git 仓库的拷贝,就要用到 `git clone` 命令。 Git 克隆的是该 Git 仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。 执行 `git clone`命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。事实上,如果你的服务器的磁盘坏掉了,你通常可以使用任何一个克隆下来的用户端来重建服务器上的仓库(虽然可能会丢失某些服务器端的挂钩设置,但是所有版本的数据仍在)。 克隆仓库的命令格式是 `git clone [url]` 。比如,要克隆 Git 的可链接库 `libgit2`,可以用下面的命令: ~~~bash $ git clone https://github.com/libgit2/libgit2 ~~~ 这会在当前目录下创建一个名为 “libgit2” 的目录,并在这个目录下初始化一个 .git 文件夹,从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。 你进入到这个新建的 libgit2 文件夹,所有的项目文件已经在里面了,准备就绪等待后续的开发和使用。如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以使用如下命令: ~~~bash $ git clone https://github.com/libgit2/libgit2 mylibgit ~~~ 这将执行与上一个命令相同的操作,不过在本地创建的仓库名字变为 `mylibgit`。 Git 支持多种数据传输协议。上面的例子使用的是 `https://` 协议,不过你也可以使用` git://` 协议或者使用 `SSH` 传输协议,比如 `user@server:path/to/repo.git` 。 ## git fetch 从远程仓库中抓取与拉取`git fetch [remote-name]` 这个命令会访问远程仓库,从中拉取所有你还没有的数据。执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。 如果你使用 `clone` 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 `origin` 为简写。所以,`git fetch origin` 会抓取克隆(或上一次抓取)后新推送的所有工作。 `git fetch` 命令会将数据拉取到你的本地仓库, 它并不会自动合并或修改你当前的工作。当准备好时你必须手动将其合并入你的工作。 ## git push 推送到远程仓库:`git push [remote-name] [branch-name]` 当你想分享你的项目时,必须将其推送到上游。当你想要将 master 分支推送到 origin 服务器时(克隆时通常Git会自动设置好那两个名字),那么运行这个命令就可以将你所做的备份到服务器: ~~~bash $ git push origin master ~~~ 只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。 ## git pull ## git status ## git add ## git commit ### 提交时附带简短说明。 ~~~bash $ git commit -m "xx" ~~~ xx:即为要附加在本次提交的简短说明文字。 ### 修改最近一次提交的信息 ~~~bash $ git commit --amend ~~~ 执行上述命令后,git会启动安装时配置的文本编辑器,最近一次提交的信息会在该编辑器中显示进行修改。 ## git rebase ## git log 用于回顾提交历史的工具是 `git log` 命令。 默认不用任何参数的话,git log 会按提交时间列出所有的更新,最近的更新排在最上面。正如你所看到的,这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。 ~~~bash $ git log commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 16:40:33 2008 -0700 removed unnecessary test commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 10:31:28 2008 -0700 first commit ~~~ ### 显示提交的内容差异 选项`-p`,用来显示每次提交的内容差异,可以加上 -2 来仅显示最近两次提交: ~~~ bash $ git log -p -2 ~~~ 该选项除了显示基本信息之外,还在附带了每次 commit 的变化。当进行代码审查,或者快速浏览某个搭档提交的 commit 所带来的变化的时候,这个参数就非常有用了。 ### 看到每次提交的简略的统计信息 想看到每次提交的简略的统计信息,你可以使用 `--stat` 选项: ~~~ bash $ git log --stat ~~~ `--stat` 选项在每次提交的下面列出所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加了。在每次提交的最后还有一个总结。 ### 指定不同于默认格式的方式展示提交历史 选项`--pretty`,指定使用不同于默认格式的方式展示提交历史。这个选项有一些内建的子选项。比如用`oneline` 将每个提交放在一行显示,查看的提交数很大时非常有用。另外还有 `format`,`short`,`full` 和`fuller` 可以用,展示的信息或多或少有些不同。 ~~~ bash $ git log --pretty=oneline ca82a6dff817ec66f44342007202690a93763949 changed the version number 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test a11bef06a3f659402fe7563abf99ad00de2209e6 first commit ~~~ `format`,可以定制要显示的记录格式。这样的输出对后期提取分析格外有用 — 因输出的格式不会随着Git的更新而发生改变: ~~~ bash $ git log --pretty=format:"%h - %an, %ar : %s" ca82a6d - Scott Chacon, 6 years ago : changed the version number 085bb3b - Scott Chacon, 6 years ago : removed unnecessary test a11bef0 - Scott Chacon, 6 years ago : first commit ~~~ Table 2-1. git log --pretty=format 常用的选项 | 选项 | 说明 | | --- | --- | | %H | 提交对象(commit)的完整哈希字串 | | %h | 提交对象的简短哈希字串 | | %T | 树对象(tree)的完整哈希字串 | | %t | 树对象的简短哈希字串 | | %P | 父对象(parent)的完整哈希字串 | | %p | 父对象的简短哈希字串 | | %an | 作者(author)的名字 | | %ae | 作者的电子邮件地址 | | %ad | 作者修订日期(可以用 --date= 选项定制格式) | | %ar | 作者修订日期,按多久以前的方式显示 | | %cn | 提交者(committer)的名字 | | %ce | 提交者的电子邮件地址 | | %cd | 提交日期 | | %cr | 提交日期,按多久以前的方式显示 | | %s | 提交说明 | `作者`指的是实际作出修改的人,`提交者`指的是最后将此工作成果提交到仓库的人。所以,当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。 当 `oneline` 或 `format` 与另一个 log 选项 `--graph` 结合使用时尤其有用。这个选项添加了一些ASCII字符串来形象地展示你的分支、合并历史: ~~~ bash $ git log --pretty=format:"%h %s" --graph * 2d3acf9 ignore errors from SIGCHLD on trap * 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit |\ | * 420eac9 Added a method for getting the current branch. * | 30e367c timeout code and tests * | 5a09431 add timeout protection to grit * | e1193f8 support for heads with slashes in them |/ * d6016bc require time for xmlschema * 11d191e Merge branch 'defunkt' into local ~~~ Table 2-2. git log 的常用选项 | 选项 | 说明 | | --- | --- | | `-p` | 按补丁格式显示每个更新之间的差异。 | | `--stat` | 显示每次更新的文件修改统计信息。 | | `--shortstat` | 只显示 --stat 中最后的行数修改添加移除统计。 | | `--name-only` | 仅在提交信息后显示已修改的文件清单。 | | `--name-status` | 显示新增、修改、删除的文件清单。 | | `--abbrev-commit` | 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。 | | `--relative-date` | 使用较短的相对时间显示(比如,“2 weeks ago”)。 | | `--graph` | 显示 ASCII 图形表示的分支合并历史。 | | `--pretty` | 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。 | ## git reflog 在任何时候通过执行 `git reflog` 命令来了解你曾经做过什么: ~~~bash $ git reflog 1a410ef HEAD@{0}: reset: moving to 1a410ef ab1afef HEAD@{1}: commit: modified repo.rb a bit 484a592 HEAD@{2}: commit: added repo.rb ~~~ 这里可以看到我们已经检出的两次提交,然而并没有足够多的信息。 为了使显示的信息更加有用,我们可以执行` git log -g`,这个命令会以标准日志的格式输出引用日志。 ~~~bash $ git log -g commit 1a410efbd13591db07496601ebc7a059dd55cfe9 Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>) Reflog message: updating HEAD Author: Scott Chacon <schacon@gmail.com> Date: Fri May 22 18:22:37 2009 -0700 third commit commit ab1afef80fac8e34258ff41fc1b867c702daa24b Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>) Reflog message: updating HEAD Author: Scott Chacon <schacon@gmail.com> Date: Fri May 22 18:15:24 2009 -0700 modified repo.rb a bit ~~~ ## git branch 本地分支管理 ### 创建 当前分支为master ~~~ bash $ git checkout -b iss53 Switched to a new branch "iss53" ~~~ ### 切换 当前分支为master ~~~ bash $ git checkout iss53 Switched to branch "iss53" ~~~ >[info] 在切换分支时,一定要注意你工作目录里的文件会被改变。如果是切换到一个较旧的分支,你的工作目录会恢复到该分支最后一次提交时的样子。如果 Git 不能干净利落地完成这个任务,它将禁止切换分支。 ### 合并 当前分支为master ~~~ bash $ git merge hotfix Updating f42c576..3a0874c ~~~ ### 删除 当前分支为master ~~~ bash $ git branch -d iss53 ~~~ ### 所有分支 当前分支为master,列出本地所有分支 ~~~ bash $ git branch -a ~~~ ## git remote **远程仓库**:是指托管在因特网或其他网络中的你的项目的版本库。 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。 管理远程仓库包括了解如何添加远程仓库、移除无效的远程仓库、管理不同的远程分支并定义它们是否被跟踪等等。 可以运行 `git remote` 命令。它会列出你指定的每一个远程服务器的简写。如果你已经克隆了自己的仓库,那么至少应该能看到 origin - 这是 Git 给你克隆的仓库服务器的默认名字: ~~~ bash $ git remote origin ~~~ 也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。 ~~~ bash $ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push) ~~~ 如果你的远程仓库不止一个,该命令会将它们全部列出。 ### 查看远程仓库 * `git remote [-v]`命令。 列出你指定的每一个远程服务器的简写。如果你已经克隆了自己的仓库,那么至少应该能看到 `origin` 这是 Git 给你克隆的仓库服务器的默认名字: ~~~bash $ git clone https://github.com/schacon/ticgit Cloning into 'ticgit'... remote: Reusing existing pack: 1857, done. remote: Total 1857 (delta 0), reused 0 (delta 0) Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done. Resolving deltas: 100% (772/772), done. Checking connectivity... done. ~~~ ~~~bash $ cd ticgit $ git remote origin ~~~ 可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。 ~~~bash $ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push) ~~~ 与几个协作者合作的,拥有多个远程仓库的仓库看起来像下面这样: ~~~bash $ git remote -v bakkdoor https://github.com/bakkdoor/grit (fetch) bakkdoor https://github.com/bakkdoor/grit (push) cho45 https://github.com/cho45/grit (fetch) cho45 https://github.com/cho45/grit (push) defunkt https://github.com/defunkt/grit (fetch) defunkt https://github.com/defunkt/grit (push) koke git://github.com/koke/grit.git (fetch) koke git://github.com/koke/grit.git (push) origin git@github.com:mojombo/grit.git (fetch) origin git@github.com:mojombo/grit.git (push) ~~~ * `git remote show [remote-name] ` 如果想要查看某一个远程仓库的更多信息,可以使用该命令。 如果想以一个特定的缩写名运行这个命令,例如 origin,会得到像下面类似的信息: ~~~bash $ git remote show origin * remote origin Fetch URL: https://github.com/schacon/ticgit Push URL: https://github.com/schacon/ticgit HEAD branch: master Remote branches: master tracked dev-branch tracked Local branch configured for 'git pull': master merges with remote master Local ref configured for 'git push': master pushes to master (up to date) ~~~ 它同样会列出远程仓库的 URL 与跟踪分支的信息。还有: 1. 远程仓库的 URL 2. 当前正处于 `master` 分支 3. 跟踪分支:`master`、`dev-branch`。 4. 如果运行` git pull`,就抓取远程 master 分支的内容,合并到本地 master 分支。 5. 如果运行` git push`,就向远程 master 分支推送本地 master 分支的内容。 还可以通过` git remote show` 看到更多的信息。 ~~~bash $ git remote show origin * remote origin URL: https://github.com/my-org/complex-project Fetch URL: https://github.com/my-org/complex-project Push URL: https://github.com/my-org/complex-project HEAD branch: master Remote branches: master tracked dev-branch tracked markdown-strip tracked issue-43 new (next fetch will store in remotes/origin) issue-45 new (next fetch will store in remotes/origin) refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove) Local branches configured for 'git pull': dev-branch merges with remote dev-branch master merges with remote master Local refs configured for 'git push': dev-branch pushes to dev-branch (up to date) markdown-strip pushes to markdown-strip (up to date) master pushes to master (up to date) ~~~ 这个命令列出了当你在特定的分支上执行 `git push` 会自动地推送到哪一个远程分支。它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了,还有当你执行 `git pull` 时哪些分支会自动合并。 ### 添加远程仓库 运行 `git remote add <shortname> <url>` 添加一个新的远程 Git 仓库,同时指定一个你可以轻松引用的简写: ~~~bash $ git remote add pb https://github.com/paulboone/ticgit $ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push) pb https://github.com/paulboone/ticgit (fetch) pb https://github.com/paulboone/ticgit (push) ~~~ 接下来,在命令行中使用字符串 pb 来代替整个 URL。例如,如果你想拉取 Paul 的仓库中有但你没有的信息,可以运行 `git fetch pb`: ~~~bash $ git fetch pb remote: Counting objects: 43, done. remote: Compressing objects: 100% (36/36), done. remote: Total 43 (delta 10), reused 31 (delta 5) Unpacking objects: 100% (43/43), done. From https://github.com/paulboone/ticgit * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit ~~~ ### 远程仓库重命名 `git remote rename <nameNow> <nameChangeTo>` 修改一个远程仓库的简写名。例如,想要将 pb 重命名为 paul,可以用 git remote rename 这样做: ~~~bash $ git remote rename pb paul ~~~ ~~~bash $ git remote origin paul ~~~ 远程分支名字也会被修改。那些过去引用 `pb/master` 的现在会引用 `paul/master`。 ### 远程仓库移除 `git remote rm <nameNow>` 如果因为一些原因想要移除一个远程仓库 - 你已经从服务器上搬走了或不再想使用某一个特定的镜像了,又或者某一个贡献者不再贡献了 - 可以使用: ~~~bash $ git remote rm paul ~~~ ~~~bash $ git remote origin ~~~ ### 指定URL所用协议 set your authentication credential to the git Remote URI: ~~~bash $ git remote set-url origin https://yourusername@github.com/user/repo.git ~~~ Then you'll be asked for a password when trying to `git push`. Or, set a password too: ~~~bash $ git remote set-url origin https://youruser:password@github.com/user/repo.git ~~~ But, github password will be stored in plaintext in your .git directory, which is obviously undesirable. change your repo config on your PC to ssh way: 1. edit `.git/config` file under your repo directory 2. find `url=entry under section [remote "origin"]` 3. change it from `url=https://MichaelDrogalis@github.com/derekerdmann/lunch_call.git` to `url=ssh://git@github.com/derekerdmann/lunch_call.git`. that is, change all the texts before `@` symbol to `ssh://git` 4. Save config file and quit. now you could use `git push origin master` to sync your repo on GitHub ### 从远程仓库中抓取与拉取 `$ git fetch [remote-name]`命令。 git会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。当准备好时你必须手动将其合并入你的工作。 可以使用` git pull` 命令来自动的抓取(git fetch)然后合并(git merge)远程分支到当前分支。前提是所在本地分支已经设置了跟踪一个远程分支。默认情况下,`git clone` 命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或不管是什么名字的默认分支)。运行 `git pull` 都会查找当前分支所跟踪的服务器与分支,从服务器上抓取数据然后尝试合并该远程分支。 ### 推送到远程仓库 `git push [remote-name] [branch-name]`命令。 当你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字),那么运行这个命令就可以将你所做的备份到服务器: ~~~ bash $ git push origin master ~~~ 只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会被拒绝。你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。 ### 创建远程分支 `git push origin [branch-name]`命令 远程分支就是本地分支push到服务器上。比如master就是一个最典型的远程分支(默认)。 远程跟踪分支是远程分支状态的引用。它们是你不能移动的本地引用,当你做任何网络通信操作时,它们会自动移动。远程跟踪分支像是你上次连接到远程仓库时,那些分支所处状态的书签。 它们以 (remote)/(branch) 形式命名。例如,如果你想要看你最后一次与远程仓库` origin` 通信时 `master` 分支的状态,你可以查看 `origin/master` 分支。你与同事合作解决一个问题并且他们推送了一个 `iss53` 分支,你可能有自己的本地 iss53 分支;但是在服务器上的分支会指向 `origin/iss53` 的提交。 > 远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义一样。同时 “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用,“origin” 是当你运行 git clone 时默认的远程仓库名字。如果你运行 git clone -o booyah,那么你默认的远程分支名字将会是 booyah/master。 只要你不与 origin 服务器连接,你的 origin/master 指针就不会移动。如果要同步你的工作,运行 `git fetch origin` 命令。这个命令查找 “origin” 是哪一个服务器(在本例中,它是 git.ourcompany.com),从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master 指针指向新的、更新后的位置。 当抓取到新的远程跟踪分支时,本地不会自动生成一份可编辑的副本(拷贝)。换一句话说,这种情况下,不会有一个新的 `serverfix` 分支 - 只有一个不可以修改的 `origin/serverfix` 指针。 这时可以运行 `git merge origin/serverfix `将这些工作合并到当前所在的分支。如果想要在自己的 serverfix 分支上工作,可以将其建立在远程跟踪分支之上: ~~~ bash $ git checkout -b serverfix origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix' ~~~ 这会产生一个本地分支`serverfix`,起点位于 `origin/serverfix`。 ### 跟踪分支 `git checkout -b [branch] [remotename]/[branch]`命令 上述的本地分支`serverfix`也被称为“跟踪分支”,是与远程分支有直接关系的本地分支。如果在一个跟踪分支上输入 git pull,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。 当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/master 的 master 分支。然而,也可以设置其他的跟踪分支 - 其他远程仓库上的跟踪分支,或者不跟踪 master 分支。最简单的就是之前看到的例子。另外, Git 提供了 --track 快捷方式: ~~~ bash $ git checkout --track origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix' ~~~ 设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支,你可以在任意时间使用 -u 或 --set-upstream-to 选项运行 git branch 来显式地设置。 ~~~ bash $ git branch -u origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. ~~~ >当设置好跟踪分支后,可以通过 @{upstream} 或 @{u} 快捷方式来引用它。所以在 master 分支时并且它正在跟踪 origin/master ,可以使用 git merge @{u} 来取代 git merge origin/master。 ### 查看设置的所有跟踪分支 `git branch` 的 `-vv` 选项。这会将所有的本地分支列出来并且包含更多的信息,如每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后或是都有。 例如: ~~~ bash $ git branch -vv iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets master 1ae2a45 [origin/master] deploying index fix * serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it testing 5ea463a trying something new ~~~ 上述代码表示: * ` iss53` 分支正在跟踪 `origin/iss53` 并且 “ahead” 是 2,意味着本地有两个提交还没有推送到服务器上。 * `master` 分支正在跟踪 `origin/master` 分支并且是最新的。 * `serverfix` 分支正在跟踪 `teamone` 服务器上的 `server-fix-good` 分支并且领先 2 落后 1,意味着服务器上有一次提交还没有合并入同时本地有三次提交还没有推送。 * `testing` 分支并没有跟踪任何远程分支。 上述数字的值来自于最后一次从每个服务器上抓取的数据。这个命令并没有连接服务器,它只会告诉你关于本地缓存的服务器数据。如果想要统计最新的领先与落后数字,需要在运行此命令前抓取所有的远程仓库。可以像这样做: `$ git fetch --all; git branch -vv` ### 删除远程分支 运行带有` --delete` 选项的 `git push` 命令来删除一个远程分支。如果想要从服务器上删除 serverfix 分支,运行下面的命令: ~~~ bash $ git push origin --delete serverfix To https://github.com/schacon/simplegit - [deleted] serverfix ~~~ 基本上这个命令做的只是从服务器上移除这个指针。Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。 ### 删除本地的远程跟踪分支 `$ git remote prune [-n | --dry-run]<name> `命令。 在远程分支被删除后,若本地的相应跟踪分支还存在(用`git branch -avv`命令后,在“remotes/ name”里还有出现),则就用这个prune命令进行删去。 --dry-run,只是报告并不进行删除。 ~~~ bash $ git remote prune origin ~~~ ## git tag `git tag` 命令用来为代码历史记录中的某一个点指定一个永久的书签。 一般来说它用于发布相关事项。 ### 列出标签 ~~~ bash $ git tag ~~~ 这个命令以字母顺序列出标签;但是它们出现的顺序并不重要。 ### 查找标签 例如,Git 自身的源代码仓库包含标签的数量超过 500 个。如果只对 1.8.5 系列感兴趣,可以运行: ~~~ bash $ git tag -l 'v1.8.5*' v1.8.5 v1.8.5-rc0 v1.8.5-rc1 v1.8.5-rc2 v1.8.5-rc3 v1.8.5.1 v1.8.5.2 v1.8.5.3 ~~~ ### 创建标签 Git 使用两种主要类型的标签: * 轻量标签(lightweight) * 附注标签(annotated) 一个轻量标签很像一个不会改变的分支 - 它只是一个特定提交的引用。 附注标签是存储在 Git 数据库中的一个完整对象。它们是可以被校验的;其中包含打标签者的名字、电子邮件地址、日期时间;还有一个标签信息;并且可以使用 GNU Privacy Guard (GPG)签名与验证。通常建议创建附注标签,这样你可以拥有以上所有信息;但是如果你只是想用一个临时的标签,或者因为某些原因不想要保存那些信息,轻量标签也是可用的。 #### 创建轻量标签 轻量标签本质上是将提交校验和存储到一个文件中 - 没有保存任何其他信息。给最新的提交创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名字: ~~~ bash $ git tag v1.4-lw $ git tag v0.1 v1.3 v1.4 v1.4-lw v1.5 ~~~ 这时,如果在标签上运行`git show`,你不会看到额外的标签信息。命令只会显示出提交信息: ~~~ bash $ git show v1.4-lw commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number ~~~ #### 创建标注标签 给最新的提交创建标注标签,在运行 `tag` 命令时指定 -a 选项: ~~~ bash $ git tag -a v1.4 -m 'my version 1.4' $ git tag v0.1 v1.3 v1.4 ~~~ -m 选项指定了一条将会存储在标签中的信息。如果没有为附注标签指定一条信息,Git 会运行编辑器要求你输入信息。 通过使用 git show 命令可以看到标签信息与对应的提交信息: ~~~ bash $ git show v1.4 tag v1.4 Tagger: Ben Straub <ben@straub.cc> Date: Sat May 3 20:19:12 2014 -0700 my version 1.4 commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number ~~~ 输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。 ### 删除标签 ~~~ bash $ git tag -d XXX 或 $ git tag XXX -d ~~~ ### 后期打标签 你也可以对过去的提交打标签。假设提交历史是这样的: ~~~ bash $ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support 0d52aaab4479697da7686c15f77a3d64d9165190 one more thing 6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment' 0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function 4682c3261057305bdd616e23b64b0857d832627b added a todo file 166ae0c4d3f420721acbb115cc33848dfcc2121a started write support 9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme ~~~ 现在,假设在 v1.2 时你忘记给项目打标签,也就是在 “updated rakefile” 提交。你可以在之后补上标签。要在那个提交上打标签,你需要在命令的末尾指定提交的校验和(或部分校验和): ~~~ bash $ git tag -a v1.2 9fceb02 ~~~ 可以看到你已经在那次提交上打上标签了: ~~~ bash $ git tag v0.1 v1.2 v1.3 v1.4 v1.4-lw v1.5 $ git show v1.2 tag v1.2 Tagger: Scott Chacon <schacon@gee-mail.com> Date: Mon Feb 9 15:32:16 2009 -0800 version 1.2 commit 9fceb02d0ae598e95dc970b74767f19372d61af8 Author: Magnus Chacon <mchacon@gee-mail.com> Date: Sun Apr 27 20:43:35 2008 -0700 updated rakefile ... ~~~ ### 共享标签 默认情况下,`git push` 命令并不会传送标签到远程仓库服务器上。在创建完标签后你必须显式地推送标签到共享服务器上。这个过程就像共享远程分支一样 - 你可以运行 `git push origin [tagname]`。 ~~~bash $ git push origin v1.5 Counting objects: 14, done. Delta compression using up to 8 threads. Compressing objects: 100% (12/12), done. Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done. Total 14 (delta 3), reused 0 (delta 0) To git@github.com:schacon/simplegit.git * [new tag] v1.5 -> v1.5 ~~~ 如果想要一次性推送很多标签,也可以使用带有` --tags` 选项的` git push` 命令。这将会把所有不在远程仓库服务器上的标签全部传送到那里。 ~~~ bash $ git push origin --tags Counting objects: 1, done. Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done. Total 1 (delta 0), reused 0 (delta 0) To git@github.com:schacon/simplegit.git * [new tag] v1.4 -> v1.4 * [new tag] v1.4-lw -> v1.4-lw ~~~ 现在,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。 ### 检出标签 在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用` git checkout -b [branchname] [tagname] `在特定的标签上创建一个新分支: ~~~ bash $ git checkout -b version2 v2.0.0 Switched to a new branch 'version2' ~~~ 当然,如果在这之后又进行了一次提交,version2 分支会因为改动向前移动了,那么 version2 分支就会和 v2.0.0 标签稍微有些不同,这时就应该当心了。 ### 为发布打标签 作为一个维护者,如果你决定要为标签签名的话,打标签的过程应该是这样子的: ~~~ bash $ git tag -s v1.5 -m 'my signed 1.5 tag' You need a passphrase to unlock the secret key for user: "Scott Chacon <schacon@gmail.com>" 1024-bit DSA key, ID F721C45A, created 2009-02-09 ~~~ ### 生成一个构建号 Git 中不存在随每次提交递增的“v123”之类的数字序列,如果你想要为提交附上一个可读的名称,可以对其运行` git describe` 命令。Git 将会给出一个字符串,它由最近的标签名、自该标签之后的提交数目和你所描述的提交的部分 SHA-1 值构成: ~~~ bash $ git describe master v1.6.2-rc1-20-g8c5b85c ~~~ 这样你在导出一个快照或构建时,可以给出一个便于人们理解的命名。实际上,如果你的 Git 是从 Git 自己的版本库克隆下来并构建的,那么 git --version 命令给出的结果是与此类似的。如果你所描述的提交自身就有一个标签,那么它将只会输出标签名,没有后面两项信息。 注意 `git describe` 命令只适用于有注解的标签(即使用 -a 或 -s 选项创建的标签),所以如果你在使用 git describe 命令的话,为了确保能为标签生成合适的名称,打发布标签时都应该采用加注解的方式。你也可以使用这个字符串来调用 checkout 或 show 命令,但是这依赖于其末尾的简短 SHA-1 值,因此不一定一直有效。比如,最近 Linux 内核为了保证 SHA-1 值对象的唯一性,将其位数由 8 位扩展到了 10 位,导致以前的 git describe 输出全部失效。 ### 准备一次发布 现在你可以发布一个构建了。其中一件事情就是为那些不使用 Git 的可怜包们创建一个最新的快照归档。使用 `git archive` 命令完成此工作: ~~~ bash $ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz $ ls *.tar.gz v1.6.2-rc1-20-g8c5b85c.tar.gz ~~~ 如果有人将这个压缩包解压,他就可以得到你的项目文件夹的最新快照。你也可以以类似的方式创建一个 zip 压缩包,但此时你应该向 `git archive` 命令传递 `--format=zip` 选项: ~~~ bash $ git archive master --prefix='project/' --format=zip > `git describe master`.zip ~~~ 现在你有了本次发布的一个 tar 包和一个 zip 包,可以将其上传到网站或以电子邮件的形式发送给人们。 ### 制作提交简报 现在是时候通知邮件列表里那些好奇你的项目发生了什么的人了。使用` git shortlog` 命令可以快速生成一份包含从上次发布之后项目新增内容的修改日志(changelog)类文档。它会对你给定范围内的所有提交进行总结;比如,你的上一次发布名称是 v1.0.1,那么下面的命令可以给出上次发布以来所有提交的总结: ~~~ bash $ git shortlog --no-merges master --not v1.0.1 Chris Wanstrath (8): Add support for annotated tags to Grit::Tag Add packed-refs annotated tag support. Add Grit::Commit#to_patch Update version and History.txt Remove stray `puts` Make ls_tree ignore nils Tom Preston-Werner (4): fix dates in history dynamic version method Version bump to 1.0.2 Regenerated gemspec for version 1.0.2 ~~~ 这份整洁的总结包括了自 v1.0.1 以来的所有提交,并且已经按照作者分好组,你可以通过电子邮件将其直接发送到列表中。