
查看存档信息 git log
查看状态 git status
可以得知, 与当前存档相比, 哪些文件发生了变化.
可以在~/.gitconfig 设置几个需要使用的全局变量:
git config --global user.name"Name Surname" git config --global user.email yourname@example.com可以使用 git config --global --list检查 git的全局配置
可以如下定制 git 的默认行为
git config --global init.defaultBranch maingit config --global pull.rebase truegit config --global push.default current
Git 操作涉及几个数据(工作树、索引、本地仓库、远程仓库)。
**git add** 和 **git rm**。**git commit****git push** 命令发送数据到远程仓库。**git fetch** 和 **git pull** 命令从远程仓库接收数据。
**git pull** 命令在 **git fetch** 后执行 **git merge** 或 **git rebase** 命令。**git merge** 联合两个独立分支的历史结尾到一个点。(在没有定制的 git pull ,这个是默认的,同时对上游作者发布分支到许多人时,也是好的 )**git rebase** 创建一个远程分支的序列历史的单个分支,跟着本地分支。(这是定制 pull.rebase true 的情况,对我们其余的用途有用。)工作树是在 .git/ 目录之外的文件。在 .git/ 目录里面的文件,包括索引、本地仓库数据和一些 git 配置的文本文件。
| Git 命令 | 功能 |
|---|---|
| git init | 创建(本地)存储库 |
| git clone URL | 克隆远程存储库到本地仓库工作目录树 |
| git pull origin main | 通过远程仓库 origin 更新本地 main 分支 |
| git add . | 增加工作树里面的文件仅作为预先存在的索引文件 |
| git add -A . | 增加工作树里面的所有文件到索引(包括已经删除的) |
| git rm filename | 从工作树和索引中删除文件 |
| git commit | 提交在索引中的暂存改变到本地存储库 |
| git commit -a | 添加工作树里的所有的改变到索引并提交它们到本地仓库(添加 + 提交) |
| git push -u origin branch_name | 使用本地 branch_name 分支更新远程仓库 origin(初始启用) |
| git push origin branch_name | 使用本地 branch_name 分支更新远程仓库 origin(随后调用) |
| git diff treeish1 treeish2 | 显示 treeish1 提交和 treeish2 提交的不同 |
| gitk | VCS 存储库分支历史树的图形界面显示 |
| Git 命令行 | 功能 |
|---|---|
| gitk --all | 参看完整的 Git 历史和操作,比如重置 HEAD 到另外一个提交、挑选补丁、创建标签和分支…… |
| git stash | 得到一个干净的工作树,不会丢失数据 |
| git remote -v | 检查远程设置 |
| git branch -vv | 检查分支设置 |
| git status | 显示工作树状态 |
| git config -l | 列出 git 设置 |
| git reset --hard HEAD;git clean -x -d -f | 反转所有工作树的改变并完全清理它们 |
| git rm --cached filename | 反转由 git add filename 改变的暂存索引 |
| git reflog | 获取参考日志(对从删除的分支中恢复提交有用) |
| git branch new_branch_name HEAD@{6} | 从 reflog 信息创建一个新的分支 |
| git remote add new_remote URL | 增加一个由 URL 指向的远程仓库 new_remote |
| git remote rename origin upstream | 远程仓库的名字从 origin 重命名到 upstream |
| git branch -u upstream/branch_name | 设置远程跟踪到远程仓库 upstream 和它的分支名 branch_name。 |
| git remote set-url origin https://foo/bar.git | 改变 origin 的 URL |
| git remote set-url --push upstream DISABLED | 禁止推送到 upstream(编辑 .git/config 来重新启用) |
| git remote update upstream | 获取 upstream 仓库中所有远程分支更新 |
| git fetch upstream foo:upstream-foo | 创建本地(可能是孤立的)upstream-foo 分支,作为upstream 仓库中 foo 分支的一个拷贝 |
| git checkout -b topic_branch; git push -u topic_branch origin | 制作一个新的 topic_branch 并把它推送到 origin |
| git branch -m oldname newname | 本地分支改名 |
| git push -d origin branch_to_be_removed | 删除远程分支(新的方式) |
| git push origin:branch_to_be_removed | 删除远程分支(老的方式) |
| git checkout --orphan unconnected | 创建一个新的 unconnected 分支 |
| git rebase -i origin/main | 从 origin/main 重新排序、删除、压缩提交到一个干净的分支历史 |
| git reset HEAD^;git commit --amend | 压缩最后两个提交为一个 |
| git checkout topic_branch; git merge --squash topic_branch | 压缩整个 topic_branch 到一个提交 |
| git fetch --unshallow --update-head-ok origin’+refs/heads/:refs/heads/’ | 反转一个浅克隆到一个所有分支的完整克隆 |
| git ime | 分开最后的提交到一系列单个逐一文件的小提交。(要求 imediff) |
| git repack -a -d;git prune | 本地仓库重新打包到一个单独的包中(这可能限制从删除分支里面恢复丢失数据等机会) |
git 用户手册(英文):https://mirrors.edge.kernel.org/pub/software/scm/git/docs/user-manual.html
gitmagic:https://www-cs-students.stanford.edu/~blynn/gitmagic/intl/zh_cn/
gittutorial(上):https://git-scm.com/docs/gittutorial
(下):https://git-scm.com/docs/gittutorial-2
giteverydayhttps://git-scm.com/docs/giteveryday
方式一:在本地直接创建一个仓库 git init,把当前目录变成仓库
方式二:从远程服务器上克隆一个已经存在的仓库 git clone

要首先将文件添加到暂存区才能进行提交
暂存区相当于货车,货物放到货车上再运到仓库中
git status查看未跟踪的文件和暂存区中的文件
git add将文件添加到暂存区,可以使用通配符来同时添加多个文件
git log查看提交记录,--oneline 参数只显示 ID 和提交信息

**git ls-files**查看暂存区文件
查看差异:
git diff:

默认是查看工作区和暂存区之间的差异
git diff HEAD比较工作区和版本库的差异
git diff --cached比较暂存区和版本库的差异
git diff 提交 ID1 提交 ID2比较两个提交版本之间的差异
git diff 提交 ID1 提交 ID2 文件名比较两个提交版本特定文件中的差异内容
git diff 分支 1 分支 2比较分支之间的差异
删除文件
rm filename; git add . ;git commitgit rm直接将工作区和暂存区的文件同时删除,--cached 参数表示不删除本地文件不要忘了提交
忽略不应该加入版本库中的文件**.gitignore**
应该忽略哪些文件:
如:以下这些文件

要忽略这些文件,只需要在 .gitignore 文件中添加这些文件,可以使用通配符*
也可以添加文件目录,以/结尾

如:
git 官方提供了常用语言的忽略文件模板https://github.com/github/gitignore
分支只是简单的指向某个提交记录,建议早用分支,多用分支,
这是因为即使创建再多的分支也不会造成储存或内存上的开销,并且按逻辑分解工作到不同的分支要比维护那些特别臃肿的分支简单多了。
在将分支和提交记录结合起来后,我们会看到两者如何协作。现在只要记住使用分支其实就相当于在说:“我想基于这个提交以及它所有的 parent 提交进行新的工作。”
最新版本都是用 git switch 切换分支,因为 checkout 过于臃肿
git checkout -b
在 Git 中合并两个分支时会产生一个特殊的提交记录,它有两个 parent 节点。翻译成自然语言相当于:“我要把这两个 parent 节点本身及它们所有的祖先都包含进来。”
有 main 分支和 A 分支时,git merge A,就是把 A 分支合并到 main 中,创建的新提交同时指向两个分支的父母节点,而 A 分支的指针还停留在原地,再执行 git checkout A;git merge main,因为 main 继承自 bugFix,Git 什么都不用做,只是简单地把 bugFix 移动到 main 所指向的那个提交记录。

Rebase 实际上就是取出一系列的提交记录,**“复制”**它们,然后在另外一个地方逐个的放下去。
如有 A 分支和 main 两个分支,当前在 A 分支,执行git rebase main,那么就会将 A 分支指向的节点复制一份并放到 main 的顶点处,
C3 仍然存在,C3’是副本
切换到 main 分支,执行git rebase bugFix,由于 bugFix 继承自 main,所以 Git 只是简单的把 main 分支的引用向前移动了一下而已。

HEAD
HEAD 是一个对当前所在分支的符号引用 —— 也就是指向你正在其基础上进行工作的提交记录。
HEAD 总是指向当前分支上最近一次提交记录。大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的。
HEAD 通常情况下是指向分支名的(如 bugFix)。在你提交时,改变了 bugFix 的状态,这一变化通过 HEAD 变得可见。
分离 HEAD:
由于 head 通常默认指向分支名,如 head–>main–>C1,
分离 head 就是直接将 head 指向某个节点,git checkout 节点名哈希值
在真实的 git 中,提交使用哈希值(共四十位)标识,使用git log可以查看提交的哈希值
通过哈希值指定提交记录不方便,git 中使用了相对引用
^ 向上移动 1 个提交记录~<num> 向上移动多个提交记录,如 ~3 git checkout main^将 head 节点指向 main 的父节点
git checkout main^^将 head 节点指向 main 的第二个父节点
git checkout HEAD^指向 head 所在节点的父节点
git checkout HEAD~4将 head 向上移动四
移动分支指向(可以使用 head 相对引用,也可以直接使用哈希值)
git branch -f main HEAD~3使用-f 参数将 main 指向 head 的前三个
相对引用为我们提供了一种简洁的引用提交记录 C1 的方式, 而 -f 则容许我们将分支强制移动到那个位置。
git reset 通过把分支记录回退几个提交记录来实现撤销改动。你可以将这想象成“改写历史”。
git reset 向上移动分支,原来指向的提交记录就跟从来没有提交过一样。
git reset HEAD^

git reset有以上三种模式,--mixed 是默认参数,上图中打勾表示保留,打叉表示清空。
谨慎使用
--hard参数,除非是确认不需要修改的所有内容,因为工作区即当前目录下的文件也会被删除
--mixed提交之前需要再次 git add
git 记录了可回溯的操作日志,使用git reflog 来查看操作日志,使用git reset 来指定回退的版本号就可以回溯了
虽然在你的本地分支中使用 git reset 很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效的哦!
为了撤销更改并分享给别人,我们需要使用 git revert。
git revert HEAD

在我们要撤销的提交记录后面居然多了一个新提交!这是因为新提交记录 C2' 引入了更改 —— 这些更改刚好是用来撤销 C2 这个提交的。也就是说 C2' 的状态与 C1 是相同的。
revert 之后就可以把你的更改推送到远程仓库与别人分享啦。
git cherry-pick <提交号>... 用于最直接的将一些提交复制到当前位置(HEAD)下面,可以同时复制多个,按顺序 git cherry-pick C1 C2 C3--interactive 的 rebase 命令, 简写为 -i 如果你在命令后增加了这个选项,Git 会打开一个 UI 界面并列出将要被复制到目标分支的备选提交记录,它还会显示每个提交记录的哈希值和提交说明,提交说明有助于你理解这个提交进行了哪些更改。
当 rebase UI 界面打开时, 你能做 3 件事:
pick 的状态来完成,关闭就意味着你不想要这个提交记录)如:git rebase -i HEAD~4
使用git rebase -i或git cherry-pick直接将 bug 分支修复的节点复制到 main 分支下
newImage 分支上进行了一次提交,然后又基于它创建了 caption 分支,然后又提交了一次。此时你想对某个以前的提交记录进行一些小小的调整。比如设计师想修改一下 newImage 中图片的分辨率,尽管那个提交记录并不是最新的了。git rebase -i 将提交重新排序,然后把我们想要修改的提交记录挪到最前git commit --amend 来进行一些小修改git rebase -i 来将他们调回原来的顺序使用
rebase -i对提交记录进行重新排序。只要把我们想要的提交记录挪到最前端,我们就可以很轻松的用--amend修改它,然后把它们重新排成我们想要的顺序。但这样做就唯一的问题就是要进行两次排序,而这有可能造成由 rebase 而导致的冲突。
使用 git cherry-pick 实现,cherry-pick 可以将提交树上任何地方的提交记录取过来追加到 HEAD 上(只要不是 HEAD 上游的提交就没问题)。
git tag分支很容易被移动、改变,使用 git tag 可以创建一个永远指向某个提交的标记,相当于里程碑
更难得的是,它们并不会随着新的提交而移动。你也不能切换到某个标签上面进行修改提交,它就像是提交树上的一个锚点,标识了某个特定的位置。
git tag <tagname> <commit name>
git describe用来描述离你最近的锚点(也就是标签)Git Describe 能帮你在提交历史中移动了多次以后找到方向
用法: git describe <ref>
<ref> 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会使用你目前所在的位置(HEAD)。
它输出的结果是这样的:
<tag>_<numCommits>_g<hash>
tag 表示的是离 ref 最近的标签, numCommits 是表示这个 ref 与 tag 相差有多少个提交记录, hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位。
当 ref 提交记录上有某个标签时,则只输出标签名称
^ 后加数字在 merge 合并之后,提交同时有两个父节点,就可以通过 git checkout main^2 将 HEAD 移动到第二条支路的父节点,
^~ 的链式操作,只针对相对引用 HEAD 有效git checkout HEAD~^2~2

==>

在我们的本地仓库多了一个名为 o/main 的分支, 这种类型的分支就叫远程分支。由于远程分支的特性导致其拥有一些特殊属性。
远程分支反映了远程仓库(在你上次和它通信时)的状态。这会有助于你理解本地的工作与公共工作的差别 —— 这是你与别人分享工作成果前至关重要的一步.
远程分支有一个特别的属性,在你切换到远程分支时,自动进入分离 HEAD 状态。Git 这么做是出于不能直接在这些分支上进行操作的原因,你必须在别的地方完成你的工作,(更新了远程分支之后)再用远程分享你的工作成果。
远程分支有一个命名规范:
<remote name>/<branch name>因此,如果你看到一个名为 o/main 的分支,那么这个分支就叫 main,远程仓库的名称就是 o。
大多数的开发人员会将它们主要的远程仓库命名为 origin,并不是 o。这是因为当你用 git clone 某个仓库时,Git 已经帮你把远程仓库的名称设置为 origin 了
如果在本地切换到远程分支并提交会发生什么?git checkout o/main;git commit
Git 变成了分离 HEAD 状态,当添加新的提交时 o/main 也不会更新。这是因为 o/main 只有在远程仓库中相应的分支更新了以后才会更新。
git fetch从远程仓库获取数据远程仓库相关的操作实际可以归纳为两点:向远程仓库传输数据以及从远程仓库获取数据。既然我们能与远程仓库同步,那么就可以分享任何能被 Git 管理的更新(因此可以分享代码、文件、想法、情书等等)。
git fetch在从远程仓库获取数据时的做法:
1. 从远程仓库中下载本地仓库中缺失的提交记录
2. 更新远程分支指针` o/main `
git fetch实际上将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态。通过使用http://或git://协议与远程仓库通信
注意:git fetch 并不会改变你本地仓库的状态。它不会更新你的 main 分支,也不会修改你磁盘上的文件。
许多开发人员误以为执行了
git fetch以后,他们本地仓库就与远程仓库同步了。它可能已经将进行这一操作所需的所有数据都下载了下来,但是并没有修改你本地的文件。
git pull当远程分支中有新的提交时,你可以像合并本地分支那样来合并远程分支。也就是说就是你可以执行以下命令:
git cherry-pick o/maingit rebase o/maingit merge o/main实际上,由于先抓取更新再合并到本地分支这个流程很常用,因此 Git 提供了一个专门的命令来完成这两个操作。它就是我们要讲的 git pull。
git pull == git fetch + git merge
git pushgit push 负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。
git push不带任何参数时的行为与 Git 的一个名为push.default的配置有关。它的默认值取决于你正使用的 Git 的版本,但是在教程中我们使用的是upstream。 这没什么太大的影响,但是在你的项目中进行推送之前,最好检查一下这个配置
存在的问题:
git push到了远程仓库,当 B 进行 push 时,git 就不会允许,因为不知道如何合并比如下图:git push 失败是因为你最新提交的 C3 基于远程分支中的 C1。而远程仓库中该分支已经更新到 C2 了,所以 Git 拒绝了你的推送请求。

如何解决:
在 push 之前,获取远程仓库的提交记录并进行 rebase,再进行 push,即:
git fetch;git rebase o/main;git push
或者使用 merge 合并
git fetch;git merge o/main;git push
或者简单点的使用--rebase 参数
git pull --rebase;git push
git pull;git push也可以
如果你是在一个大的合作团队中工作, 很可能是 main 被锁定了, 需要一些 Pull Request 流程来合并修改。如果你直接提交(commit)到本地 main, 然后试图推送(push)修改, 你将会收到这样类似的信息:
! [远程服务器拒绝] main -> main(TF402455: 不允许推送(push)这个分支; 你必须使用 pull request 来更新这个分支.)
远程服务器拒绝直接推送(push)提交到 main, 因为策略配置要求 pull requests 来提交更新.
应该按照流程,新建一个分支, 推送(push)这个分支并申请 pull request,但是你忘记并直接提交给了 main,现在你卡住并且无法推送你的更新。
新建一个分支 feature,推送到远程服务器, 然后 reset 你的 main 分支和远程服务器保持一致, 否则下次你 pull 并且他人的提交和你冲突的时候就会有问题。
在开发社区里,有许多关于 merge 与 rebase 的讨论。以下是关于 rebase 的优缺点:
优点:
缺点:
比如, 提交 C1 可以被 rebase 到 C3 之后。这看起来 C1 中的工作是在 C3 之后进行的,但实际上是在 C3 之前。
一些开发人员喜欢保留提交历史,因此更偏爱 merge。而其他人可能更喜欢干净的提交树,于是偏爱 rebase。仁者见仁,智者见智。
main 和 o/main 的关联关系就是由分支的“remote tracking”属性决定的。main 被设定为跟踪 o/main —— 这意味着为 main 分支指定了推送的目的地以及拉取后合并的目标。
你可能想知道 main 分支上这个属性是怎么被设定的,你并没有用任何命令指定过这个属性呀!好吧, 当你克隆仓库的时候,Git 就自动帮你把这个属性设置好了。
当你克隆时,Git 会为远程仓库中的每个分支在本地仓库中创建一个远程分支(比如 o/main)。然后再创建一个跟踪远程仓库中活动分支的本地分支,默认情况下这个本地分支会被命名为 main。
克隆完成后,你会得到一个本地分支(如果没有这个本地分支的话,你的目录就是“空白”的),但是可以查看远程仓库中所有的分支(如果你好奇心很强的话)。这样做对于本地仓库和远程仓库来说,都是最佳选择。
如何指定远程跟踪属性:
让任意分支跟踪 o/main, 然后该分支会像 main 分支一样得到隐含的 push 目的地以及 merge 的目标。 这意味着你可以在分支 totallyNotMain 上执行 git push,将工作推送到远程仓库的 main 分支上。
git checkout -b totallyNotMain o/maintotallyNotMain 的分支,它跟踪远程分支 o/maingit branch -u 命令git branch -u o/main foo,这样 foo 就会跟踪 o/main 了 git push <remote> <place>
如:git push origin main
首先切到本地仓库中的“main”分支,获取所有的提交,再到远程仓库“origin”中找到“main”分支,将远程仓库中没有的提交记录都添加上去,搞定之后告诉我。
通过“place”参数来告诉 Git 提交记录来自于 main, 要推送到远程仓库中的 main。它实际就是要同步的两个仓库的位置。
git push 后不加任何参数的默认行为,要求 HEAD 不分离,指向某个分支
上述情况用于源和目的同一名称
当本地分支和远程目标分支的名字不同时:
git push origin <source>:<destination>
git push origin main^:foo使用^ 也有效,是 main 的前一个提交
与 git push 用法一致,只是方向不同
git fetch origin foo :Git 会到远程仓库的 foo 分支上,然后获取所有本地不存在的提交,放到本地的 o/foo 上。
git fetch origin foo:foo:方法本地的 foo 分支
git fetch origin C3:foo:用提交作为参数,则不会产生 o/的远程分支
source 参数为空时:
git push origin:foo会删除本地分支的 o/foo 和远程分支的 foo

==》

git fetch origin:bar会在本地创建一个新分支 bar1
与 git push、git fetch 用法一样
git pull origin foo 相当于:
git fetch origin foo;git merge o/foo
还有…
git pull origin bar:bugFix 相当于:
git fetch origin bar:bugFix;git merge bugFix
使用 ssh 的方式来与远程仓库进行通信
首先生成 ssh 密钥:cd ~;ssh-keygen -t rsa -b 4096
会生成.ssh 文件,里面有刚生成的公私钥

将公钥.pub 文件 中的内容复制
在 github 中,点击头像 --> settings–> SSH and GPG keys
新建 SSH 密钥并粘贴公钥
在 github 中创建新仓库,选择 SSH 模式在本地仓库中进行git clone

如果已经存在本地仓库,想要将本地仓库与远程仓库关联,那么只需要创建一个 github 新仓库,使用
git remote add 远程仓库别名(一般为 origin)github 提供的仓库地址
git remote -v:查看当前仓库和远程仓库对应的名字和地址
