基本概念
一个分布式版本控制系统,可离线进行提交。每个节点都可保存完整历史版本,即使远程仓库损坏,使用任意一个节点即可恢复。
- 工作区(Working Directory 或 Workspace)
- 暂存区(Stage 或 Index)
- 仓库(Repository)
- 远程仓库(Remote Repository)
常用命令
git add
# 添加文件入暂存区
git add <file>
# 添加当前目录所有修改文件到暂存区
git add .
# 添加 git 管理目录中所有修改文件到暂存区
git add -A(--all)
git commit
# 将工作区和暂存区的已跟踪文件提交到本地仓库并且添加注释
git commit -am "comment"
# 提交暂存区的代码
git commit -m "feat(Home): add some feature"
# 修改上一次提交记录,重新添加注释
git commit --amend -m "feat(Home): add some feature"
# 修改上一次提交记录 author 信息
git commit --amend --author "user.name <user.email>"
# 修改上一次提交记录,但复用其他信息 --no-edit 参数可以避免弹出编辑器
git commit --amend --no-edit
get fetch
更新本地远程分支
# 创建并更新所有的本地远程分支(origin/branchName)
get fetch
# 只是手动指定了要 fetch 的远程仓库
git fetch origin
# 指定远程仓库和 FETCH_HEAD,并且只拉取该分支的提交
git fetch origin dev
git merge
合并代码
# 将<branch>合并进入当前分支
git merge <branch>
# 丢弃分支信息,快速合并<branch>分支。
# 使用快速合并模式,分支上就不会出现 Merge Commit 分叉。
# 如果无法以快速合并模式合并,则也生成新的 Merge Commit。
# git 默认为 --ff 快速合并模式
git merge --ff <branch>
# 非快速合并模式,产生 Merge Commit 节点,保留分支信息。 --no-ff : --no-fast-forward
git merge --no-ff <branch> -m "comment"
# 仅仅以快速合并模式合并,如果失败,则报错:“Not possible to fast-forward, aborting.”
git merge --ff-only
# 非 fast-forward 模式的时候,添加 commit 信息
git merge -m "Merge branch 'dev' into master"
# 合并遇到冲突时,退出合并
git merge --abort
# 将<branch>合并入当前分支,并且将<branch>的所有 commits 都压缩为一次 commit。
git merge --squash <branch>
git pull
拉取代码并合并
# 拉取远程仓库 origin 中的 master 分支并合并到当前分支,等于 git fetch + git merge
git pull origin master
# 以 rebase 的方式合并代码 等于 git fetch + git rebase
git pull --rebase
git push
将本地的分支版本上传到远程仓库
git push <远程仓库名> <本地分支名>:<远程分支名>
# 如果本地分支名与远程分支名相同,则可以省略冒号:
git push <远程仓库名> <本地分支名>
# 推送远程并自动跟踪(方便直接使用 git push 命令) -u 是 --set-upstream 的缩写
git push -u origin master
# 如果已经自动跟踪,则可快速上传
git push
# 如果本地版本与远程版本有差异,但又要强制推送可以使用 -f 参数,一般在 rebase、reset 操作后
git push -f origin master
# 使用 --delete(-d)参数删除远程分支
# 删除 origin 主机的 master 分支
# 遇到分支未同步,需要使用 —D 进行删除 -D 是 --delete --force 的别名
git push origin -d master
git branch
分支是 git 中重要功能之一,开发人员可以在主开发线的基础上分离出新的开发线。
# 查看分支
git branch
# 查看所有分支
git branch -a
# 创建分支
git branch 'branchName'
# 重命名分支 --move 别名 -m
git branch --move oldBranchName newBranchName
git branch -m newBranchName # 默认修改当前分支名
# 删除分支 如果报合并错误,则使用 —D
git branch -d name
git checkout
# 切换分支
git checkout name
# 切换并创建分支
git checkout -b name
# 切换并创建分支 映射 origin/dev
git checkout -b dev orgin/dev
# 删除工作区中的修改文件
git checkout -- README.md
# 删除工作区的所有修改文件
git checkout .
git stash
储藏当前工作区和暂存区的代码,多用于紧急切换分支时
# 储藏当前未 commit 的代码
git stash
# 储藏时添加备注
git stash save "备注的内容"
# 列出所有的储藏
git stash list
# 删除所有的储藏
git stash clear
# 应用最近一次的储藏
git stash apply
# 应用指定的储藏
git stash apply stash@{0}
# 应用最近一次的储藏并删除(如果无冲突)
git stash pop
# 删除最近的一次储藏
git stash drop
git revert
以生成新的 commit 的方式回滚恢复某个或多个提交变更,和git reset的区别是,会保留之前的历史记录
# 新增一次提交,抵消掉上一次提交导致的所有变化。它不会改变过去的历史。
git revert HEAD
# 依次抵消指定这些提交,比如从 HEAD 中的第五次提交到 HEAD 第三次提交
git revert HEAD~5..HEAD~2
如果遇到 Merge Commit 则需要使用git revert -m <1|2>指定保留的分支。
git revert命令还有两个参数。
--no-edit:执行时不打开默认编辑器,直接使用 Git 自动生成的提交信息。--no-commit:只抵消暂存区和工作区的文件变化,不产生新的提交。
git reset
修改(重置)git 历史,回到指定的 commit 节点,并指定之后的所有 commits 的处理方式
# 将暂存区的所有修改撤回到工作区 git reset = git reset HEAD
git reset
# 回到指定的<commit>节点,并将所有(包括工作区)更改移至工作区
git reset <commit>
# 回到指定的<commit>节点,不改变当前工作区内容,并且将之后的所有 commits 移至暂存区
git reset --soft <commit>
# 回到指定的<commit>节点,不保留之后的所有的 commits,并清空工作区和暂存区
git reset --hard <commit>
git rebase
整合分支或者整合历史记录,它的原理是首先找到这两个分支的最近共同祖先 commit,然后对比当前分支相对于该祖先的历次提交。 更多内容查看Git - 变基 (git-scm.com)
# 对 <commit>(不含)到最新提交(含)之间的所有提交进行交互式变基 -i 表示 interactive
git rebase -i <commit>
git cherry-pick
将指定的提交应用于其他分支
git cherry-pick <commit>
# 一次转移多个提交
git cherry-pick <commit1> <commit2>
# 将多个连续的提交转移,<commit1>为更早的提交。其中不包含<commit1>,但包含<commit2>
git cherry-pick <commit1>..<commit2>
# 如果转移期间遇到冲突,将冲突解决并切暂存后,使用以下方法继续转移
git cherry-pick --continue
# 遇到代码冲突后,放弃或者退出 cherry-pick。代码回到操作前的样子,就像什么都没发生过。
git cherry-pick --abort
# 退出 cherry-pick 操作,但保留成功的 cherry-pick commit。
git cherry-pick --quit
git worktree
仅需维护一个 repo,又可以同时在多个 branch 上工作,互不影响
# 新增 new_branch_name 工作树 至'../folder_path' 目录
git worktree add <path> <branch>
git worktree add -b <new_branch> <path> <source_branch>
# 删除
git worktree remove [-f] <path> # 删除干净的 worktree(未跟踪、未修改),并且删除文件夹
git worktree prune [-n] [-v] [--expire <expire>] # 从链接中清除已经被删除的 worktree
# 移动 worktree 到其他目录
git worktree move <path> <new-path>
# 查看所有 worktree
git worktree list [-v | --porcelain [-z]]
其他常用命令
# 初始化空 git 仓库
git init
# 关联远程仓库并设置别名为 origin
git remote add origin "https://....git"
# 查看所有关联的远程仓库
git remote --verbose
# 按照 URL 最后一个 / 之后的名称创建本地项目目录。如果想要自定义名称,可在该命令后加上 name 参数
git clone [url] [name]
# 设置全局用户名 如果去掉 --global 参数只对当前仓库有效。
git config --global user.name "Your name"
# 设置全局邮箱地址
git config --global user.email "name@example.com"
# 帮助存储密码凭证
git config --global credential.helper store
# 设置 merge 模式为非快速合并
git config --global merge.ff false
# 设置 pull 操作的合并的方式
git config --global pull.rebase true
# 查看当前状态
git status
# 查看工作区与暂存区的差异(不显示新增文件)
git diff
# 查看暂存区与仓库的差异
git diff -cached
# 撤销对文件的修改,移除暂存区
git restore --staged <file>
# 删除仓库中的文件夹
git rm --cached -rf 文件夹
# 删除仓库中的文件夹文件
git rm --cached
# 查看历史记录
git log
# 可以查看所有分支的所有操作记录(包括本地的提交、回退、已删除的提交操作记录等)
git reflog
本地远程分支
- 它们以
<remote>/<branch>的形式命名。 - 使用git fetch 命令进行同步更新
- 通常使用
git merge <remote>/<branch>或者git rebase <remote>/<branch>进行合并操作。
远程跟踪分支是远程分支状态的引用。它们是无法移动的本地引用。一旦你进行了网络通信, Git 就会为你移动它们以精确反映远程仓库的状态。 这样可以提醒你该分支在远程仓库中的位置就是你最后一次连接到它们的位置。
HEAD~ 和 HEAD^ 区别
- ~2表示沿着commit树向上搜索两层,并获得该层的第一个commit(如果该层有多个commit的话)
- ^2表示获得某个commit的第2个父commit(merge两个分支后产生的merge commit就拥有两个父commit)
G H I J
\ / \ /
D E F
\ | / \
\ | / |
|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
.gitignore 文件夹
配置忽略文件,git 将不会跟踪这些文件
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf
常见错误
-
CRLF 回车换行转换问题
Carriage-Return、Line-FeedCR表示的是 ASCII 码的第13个符号\r回车,LF表示的是 ASCII 码的第10个符号\n换行- windows 中使用
\r \n - mac 使用
\r - Linux 使用
\n
- windows 中使用
-
空文件夹无法提交
-
git 默认不区分文件夹大小写
git cofig --globa core.ignorecare false设置大小写敏感
示例
关联 GitHub 远程仓库
# 增加远程仓库配置 并设置别名
git remote add origin https://github.com/name/item.git
# 把本地仓库推到远程 -u增加关联,后续不用
git push -u origin master
# 查看当前本地配置的远程仓库配置
git remote -v
# 克隆仓库
git clone https://github.com/name/item.git
# 从远程获取最新版本并merge到本地
git pull
# 移除远程仓库关联
git remote remove <name>
# 允许无历史相关记录合并至本地
git pull origin master --allow-unrelated-histories
协作
- 获取 git 远程仓库的地址和权限(账号密码)
- 将代码拉取到本地
git pull origin master - 开发功能
- 提交代码
push分支至远程仓库 (如多人合作开发分支先使用git rebase origin/master)
冲突解决
不同分支(或不同开发者)对同一文件进行修改会产生冲突。冲突的解决方案非常简单,将内容修改为最终想要的结果,然后继续执行 git add 与 git commit 就可以了。
免密登录
1.创建非对称加密对
ssh-keygen -t rsa -b 4096 -f my_id -C "name@example.com"
[-t rsa]表示使用 RSA 算法。[-b 4096]表示 RSA 密钥长度 4096 bits (默认 2048 bits)。Ed25519算法不需要指定。[-f my_id]表示在【当前工作目录】下生成一个私钥文件 my_id (同时也会生成一个公钥文件 my_id.pub)。[-C "email@example.com"]表示在公钥文件中添加注释,即为这个公钥“起个别名”(不是 id,可以更改)。
生成
- 私钥:
id_rsa - 公钥:
id_rsa.pub
- 加密对文件默认存储在
user/.ssh文件夹中 - 将公钥配置到帐号密钥中
settings->SSH and GPG key ->new SSH Key - 克隆代码时,选择 ssh 模式进行克隆
git clone git@github.com:name/item.git
最佳实践
- 在敲下该命令后,会提示输入 passphrase,即为私钥添加一个“解锁口令”。
- 私钥必须要有 passphrase。如果私钥文件遗失,没有 passphrase 也无法解锁(只能暴力破解)。不要偷懒,passphrase 一定要加。
- 一对密钥只对应一个 Git 服务。一对密钥通吃各 Git 服务不太明智。
- 严格来讲,你应该在不同的机器上用不同的密钥,出了问题好排查处理。但实际上复杂的管理反而更容易让人犯错,选择你能 hold 住的方式更为重要。
分支管理
GitFlow 是团队开发的一种最佳实践,将代码划分为以下几个分支
- Master:主分支。上面只保存正式发布的版本。
- Hotfix:线上代码Bug修复分支。开发完后需要合并回Master和Develop分支,同时在Master上打一个tag。
- Release:待发布分支,Release分支基于Develop分支创建,在这个分支上测试,修改BUG。
- Develop:开发分支。开发者都在这个分支上提交代码。
- Feature:功能分支。当开发某个功能时,创建的一个单独的分支,开发完毕后再合并到dev分支。
参考链接: