对于某些命令的详细用法,如果本页写的不详细

其他资料

Git 操作往往会遇到各种问题,比如,如何把未暂存的内容移动到一个新分支,或者删除的分支如何恢复。这个仓库就收集这类问题的操作方法
搞清楚每一个命令是什么用途,或者在 测试仓库中测试后再用于项目中
https://github.com/k88hudson/git-flight-rules/blob/master/README_zh-CN.md

暂存文件

暂存指定文件的更改

想暂存某些具体的文件

  1. # -- 意为后边跟的是路径;可以省略;在某些场景下省略会出错
  2. $ git add -- index.js index.css

批量暂存更改

想要一次性将所有文件暂存

  1. # 所有更改的文件
  2. $ git add .
  3. $ git add *
  4. # 任意目录下 js 文件
  5. $ git add **/*.js

暂存某个文件的部分内容

一不小心在一个文件中添加了两块功能的代码,但是想按照功能提交修改。

解决方法:

  1. 使用 SourceTree 的暂存块、暂存行功能
  2. git add -p

操作 Commit

只提交部分文件

一不小心执行了 git add . 暂存了所有文件,但我们只需要给部分文件做提交

  1. # 1. 直接 commit 指定文件路径
  2. # git commit <option> [--] <pathspec>
  3. $ git commit -m 'msg' -- **/*.js # 任意路径下的任意 js 文件
  4. $ git commit **/*.js -m "msg"
  5. # 2. 使用 git reset 撤销; 已暂存的文件取消暂存,重新放在工作区
  6. # 默认是 HEAD ;所以 HEAD 可省略
  7. $ git reset [HEAD] <filePath>

修改最新提交信息

修改 commit 的 msg

修补式提交 - 修补提交命令 --amend

  1. # 1. 进入 vim 修改信息,保存
  2. git commit --amend
  3. # 2. 使用 reset 命令
  4. # 将 HEAD 指针指向上一次提交,暂存区和工作区不变(保持当前状态)
  5. # 使用 .git/COMMIT_EDITMSG(也就是上一次 commit 使用) 的信息重新提交
  6. $ git reset --soft HEAD^ && git commit -e -F .git/COMMIT_EDITMSG

修改老旧 commit msg

  1. # 变基(base):-i 采用交互式方式
  2. # 在出来的交互界面 选择当前要修改的 commit,改为 r(重新编写)
  3. $ git rebase -i <被变的 commit 的父亲>
  4. # 或者
  5. $ git rebase -i <commit-id>^
  6. ...
  7. Successfully rebase and update refs/heads/master

注意:编辑修改历史 commit 是对自己本地的分支进行修改;如果对已经推送到远程集成分支上,则不要轻易修改,否则会给小伙伴们造成不必要的麻烦

实操
====================
修改倒数第三个 commit 信息
Git 常见场景处理 - 图1
查看当前的 commit 信息历史

执行 git rebase ca7cece
修改“去除空格”的 pcik -> <r | reword>
Git 常见场景处理 - 图2
进入 rebase 的交互界面 - 1

Git 常见场景处理 - 图3
进入 rebase 的交互界面 - 2
Git 常见场景处理 - 图4
重新修改目标 commit;并 :wq 保存退出

Git 常见场景处理 - 图5
修改成功 对比修改前后的 commit 变化

修改了 历史 commit 后,自父亲之下所有的 commit 都会变化

blob 对象只看文件内容是否变化,如果两个文件相同,blob 就相同,即使是在不同的仓库中。 但 commit 对象包括树对象、父提交、作者、提交者、msg、变更时间等属性,任何一个属性值变化,在 git 中,就是不同的 commit。

$ git cat-file -p newMaster tree 3544e61e812c47a2e0477fc218569fb4ad3da0d9 parent 762da6042475cc0d4183eedbcbedd02b9fe7caee author YiBu tiandaochouqinyn@163.com 1568129498 +0800 committer YiBu tiandaochouqinyn@163.com 1568129498 +0800 new master 新行

合并多个 Commit

场景
===
一开始连续创建了许多 commit,过了段时间发现,这几个 commit 就是一个功能,需要合并 commit 以保证分支历史的简洁、清晰。
整理过去创建的 commit 的场景。

TODO:合并 commit 的过程中可能会有冲突,此种情况待测试

如何合并到第一个提交

当使用 git reset <commitId> 要合并到第一个提交时,vim 界面不会出现第一个提交,此时可以手动添加不存在的提交信息

合并连续的 commit 为一个

  1. # 1. 合并最近的两个提交 -> 为一个
  2. $ git reset --soft HEAD^^
  3. $ git commit -m "msg"
  4. # 2. 合并到 <commit-id> 的提交(但是不包括当前 commit-id)
  5. git rebase -i <commit-id>
  6. # 合并前两条的 commit 信息
  7. $ git rebase -i HEAD~2
  8. pick 5e130d9 添加 b 函数
  9. pick bc4e0d5 askdkajdkasjdkajdka几节课
  10. # Rebase f6687e6..bc4e0d5 onto f6687e6 (2 commands)
  11. #
  12. # Commands:
  13. # p, pick = use commit
  14. # r, reword = use commit, but edit the commit message
  15. # e, edit = use commit, but stop for amending
  16. # squash = 使用这个 commit,但是要融合进前一个 commit
  17. # s, squash = use commit, but meld into previous commit
  18. # f, fixup = like "squash", but discard this commit's log message
  19. # x, exec = run command (the rest of the line) using shell
  20. # d, drop = remove commit
  21. #
  22. # These lines can be re-ordered; they are executed from top to bottom.
  23. #
  24. # If you remove a line here THAT COMMIT WILL BE LOST.
  25. #
  26. # However, if you remove everything, the rebase will be aborted.
  27. #
  28. # Note that empty commits are commented out

实操演示
=========

查看当前分支历史
image.png

执行 git rebash -i dd10 准备合并前四个 commit
image.png

将要合并的 commit 标识改为 s 或者 squash(挤压、压入)
image.png

上一步保存后,出现编辑 commit 信息界面:为什么做此次变更
# 标识的为注释,不出现在 msg 中。
image.png

保存后查看 分支信息 git log --graph --oneline --all
image.png

使用 git reflog 查看合并过程执行了那些操作
image.png

合并间隔 commit 为一个

利用 git rebase -i 进入 vim 交互界面,调整间隔 commit 顺序后,再合并 commit

查看提交历史
image.png

执行 git rebase -i 1f40772
image.png

调整 commit 顺序,并合并 commit。
(如果缺少 commit-id,只要补充对应的 commands 和 commit-id 就可以整合 commit;适用于合并根提交情况)
image.png

image.png

image.png

拆分已提交的 Commit

松耦合

  1. # 1. 将当前提交撤销,重置为上一次提交。将撤销的提交的改动保存在工作区内
  2. $ git reset HEAD^
  3. # 2. 通过补丁块拣选方式选择要提交的修改。Git 会逐一显示工作区更改
  4. $ git add -p
  5. # 3. 以撤销提交的提交说明为蓝本,撰写新的提交
  6. # -C 重新使用特定的 commit 信息
  7. # -c 重新使用并编辑特定的 commit 信息
  8. # -e 强制编辑 commit 信息
  9. $ git commit -e -C HEAD^
  10. # 对工作区的其余修改进行提交,完成一个提交拆分两个的操作
  11. $ git add -u
  12. $ git commit

TODO:紧耦合

要拆分的提交,不同的实现逻辑耦合在一起,难以通过拣选的方式修改

TODO:拆分历史某个提交

  1. # 1、执行 rebase
  2. $ git rebase -i HEAD~3
  3. # 2、修改目标提交的操作命令;
  4. # 将需要拆分的 commit 的 pick 修改为 edit
  5. edit commit1
  6. pick commit2
  7. pick commit3
  8. # 3、将暂存区与 HEAD 的文件重置为上一次状态;类似文件修改但未执行 git add 前的状态
  9. $ git reset HEAD^
  10. # 4、挑选需要提交的内容,进行提交。如
  11. git add change1.cpp
  12. git commit -m "Version 1-A"
  13. git add change2.cpp
  14. git commit -m "Version 1-B"
  15. # 5、完成后续 rebase 过程
  16. $ git rebase --continue

发现提交的 commit 少提交或误提交一部分文件或内容

单步悔棋

  1. # 处理误提交的内容
  2. ## 第一步:
  3. ## 如果是少提交内容:将其添加到暂存区
  4. $ git add <少提交的内容>
  5. ## 如果是提交了不该提交的东西:先将暂存区和工作区的文件恢复
  6. $ git checkout HEAD^ -- <fileName>
  7. ## 第二步:
  8. ## 修补式提交:重新编写提交信息
  9. $ git commit --amend -m "msg"
  10. ## 或者:在上一次的 msg 基础上修改
  11. $ git commit -e -F .git/COMMIT_EDITMSG

重置用户信息:提交作者

发现项目的用户配置信息错误,需要纠正

  1. # 1、修改项目的用户信息
  2. $ git config --local user.name 'name'
  3. $ git config --local user.email 'XXX@XXX'
  4. # 2、重置上次信息可以配合 git rebase 修改历史提交的作者信息
  5. # 3、替换“拆分历史提交”的第 4 步操作
  6. $ git rebase -i <commit^>
  7. ## 修改目标 <commit> pick 为 edit,保存退出编辑界面
  8. # 4、这个命令会更改提交时间
  9. $ git commit --amend --reset-author
  10. $ git rebase --continue
  11. # 4、只修改作者信息
  12. ## -C 创建提交时使用指定的提交对象的日志消息、作者信息、时间戳
  13. $ git commit --author "Name <name@163.com>" --amend --no-edit -C HEAD
  14. $ git rebase --continue

官方文档:changing author info~~ ~~
官方地址:changing author info
新建一个裸仓库,以直接修改仓库里信息的方式修改作者,将分支推送到远程
博客:修改git commit的author信息
会更改 commit 的时间
Git Pro: Git Tool Rewriting History
中文版:重写历史

查看 commit 历史、提交日志

  1. # 查看所有分支的前 8 个日志,以图形方式显示
  2. $ git log -n8 --graph --all

文件、版本之间差异

只有执行过 ADD 的文件更改才能显示出差异;新文件不行

比较暂存区和 HEAD 文件差异

index 暂存区
HEAD 版本库当前版本

  1. $ git diff --cached [HEAD]
  2. $ git diff --staged [HEAD]

比较工作区和暂存区文件差异

  1. $ git diff

比较不同分支或提交之间的差异

  1. # commit-id 可以为 commit-id 、分支名、tag 等
  2. $ git diff <commit-id-1> <commit-id-2>
  3. # 查看不同提交之间指定文件差异
  4. $ git diff <C1> <C2> -- <filePaths>

查看不同提交之间文件变化统计信息

  1. # 统计提交之间那些文件发生了变化
  2. $ git diff --stat
  3. file1 | 2 ++
  4. filw2 | 2 ++
  5. 2 files changed, 4 insertions(+), 2 deletions(-)
  6. # 详细增减行数统计以及文件路径
  7. $ git diff --numstat
  8. 2 0 file1
  9. 2 0 filw2
  10. # 只显示文件路径
  11. $ git diff --name-only

查看某次提交后,所有变动的文件

场景:修改一些列 Bug 后,部署到服务器(只部署修改的文件)

  1. # 不包含 commitId 中的文件,如要包含可使用 commitId^
  2. $ git diff --name-only <commitId>

文件、版本控制

暂存区恢复成 HEAD 一样

  1. # 如果只需要操作部分文件,在命令后边加 -- <filePaths>
  2. # 1. 保留暂存区更改
  3. $ git commit ...
  4. # 2. 丢弃暂存区更改
  5. # 重置暂存区为 HEAD 版本,但是工作区不变
  6. # -mixed -- reset the index but not the working tree (default)
  7. $ git reset [--mixed] HEAD

取消暂存区部分文件的更改

  1. $ git reset HEAD -- <fileNames>

让工作区恢复为与暂存区一样

  1. # 如果只需要操作部分文件,在命令后边加 -- <filePaths>
  2. # 1. 保留工作区更改
  3. $ git add <filePath>
  4. # 2. 丢弃工作区更改
  5. ## 危险操作,一旦执行,修改将找不回来
  6. $ git checkout -- <filePath>

消除最近几次提交 | 版本回退

  1. # commit-id 可以通过 Git log 查询;也可以通过 git reflog 查询
  2. ## 危险操作,会丢弃 commit-id 后的版本;并且工作区和暂存区的修改也将丢弃,变为 commit-id 指定内容。
  3. $ git reset --hard <commit-id>

删除文件的方式

  1. # 彻底删除文件:本地以及版本库都不需要
  2. ## 方法 1:
  3. $ rm <file> && git add <file>
  4. ## 方法 2:
  5. $ git rm <file>
  6. # 本地依然需要,但是不需要让 Git 管理了
  7. ## 如,不小心将 dist/*、 node_model/* 加入版版本控制
  8. $ git rm --cached <file>

临时加塞紧急任务如何处理

场景描述
===
临时加塞紧急任务,但是功能没完成不想单独生成一个 commit

stash 恢复的文件会直接覆盖工作区

  1. # 贮藏当前所有的变更(保存当前工作进度)
  2. $ git stash
  3. # 列出当前所有的 Stashing
  4. $ git stash list
  5. # 恢复 stash@{0} 的 Stashing
  6. $ git stash apply stash@{0}
  7. # 删除已经恢复的 Stashing
  8. $ git stash drop

指定不需要管理的文件

如:程序构建出的中间文件或暂存文件或私密文件

忽略规则只对尚未 track 的文件有效,如果已经被追踪过了需要清除

  1. $ git rm -r --cached [path]

文件可以放在任何目录,起作用范围对其所处目录及子目录有效

  1. # .gitignore
  2. # 基本符合 glob 规则

由于 git 只管理文件,所以对于空文件夹是不做追踪的
解决:在空文件夹中新建一个文件,通常使用 .gitkeep

分支操作

Git 会把每次提交依据时间连成一条线,这条提交线就是分支。
新建分支时,Git 创建一个指针如 dev ,指向 master 相同的提交,并且 HEAD 头指针 指向新分支 dev

新建分支

  1. # 新建分支并切换到新分支
  2. $ git checkout -b <newBranch>
  3. # 只新建分支不切换
  4. $ git branch <newBranch>
  5. # 以某个 commit-id(即 start-point) 为基准新建分支
  6. ## commit-id: 指某个本地分支、远程分支、或具体的 commit
  7. $ git checkout <commit-id> -b <newBranch>
  8. $ git branch <commit-id> <newBranch>
  9. ## 或者
  10. $ git checkout -b <newBranch> <commit-id>
  11. $ git branch <newBranch> <commit-id>

基于远程分支新建本地分支

  1. # 远程存在的分支,本地没有此分支
  2. ## 会新建同名本地分支,并设置追踪关系
  3. $ git checkout --track origin/branch-name
  4. # 通用命令:如果本地没有对 origin/branch-name 的引用,需要先 git fetch
  5. ## 既可以新建同名又可以修改名字建分支
  6. $ git checkout -b branch-name origin/branch-name

分支切换

  1. $ git checkout <branch>

分支切换可能不会成功,因为当工作区对某些文件做了修改但是没有提交后,git 会阻止进行分支切换。此时可以后三种处理方式

  1. 放弃修改所有修改 git checkout -- .
  2. 提交一个 commit git add . && git commit -m "msg"
  3. 保存工作进度 git stash

删除不常用的分支

  1. # bn 为分支名
  2. # 当没有分支有新的提交,并且没有完全合并入其他分支时,会警告
  3. $ git branch -d bn
  4. error: The branch 'bn' is not fully merged.
  5. if you are sure you want to delete it, run "git brnach -D bn".
  6. # 强制删除分支
  7. $ git branch -D <branch>
  8. # 删除远程分支
  9. $ git push origin --delete <远程分支>
  10. # 删除远程分支 === 推送一个空分支
  11. $ git push origin :<远程分支>

分支修改

  1. # 修改分支名称
  2. $ git branch -m <oldBranch> <newBranch>
  3. fatal: A branch named 'master' already exists.
  4. # 强制修改分支名称
  5. $ git branch -M <oldBranch> <newBranch>
  6. # 本地分支与远程分支关联
  7. $ git branch --set-upstream-to <branch-name> origin/<branch-name>

分支集成策略

远程操作

clone 克隆

从远程指定的分支克隆

  1. $ git clone <url> -b dev

详细操作

remote 远程主机操作

  1. # 查看所有远程主机地址详情
  2. $ git remote -v
  3. origin <xxx 仓库网址> (fetch)
  4. origin <xxx 仓库网址> (push)
  5. # 列出所有远程主机
  6. $ git remote show
  7. origin
  8. # 查看某一个远程主机详细信息
  9. $ git remote show origin
  10. # 添加一个远程主机
  11. $ git remote add <主机名> <网址>
  12. # 删除远程主机
  13. $ git remote rm <主机名>
  14. # 重命名远程主机
  15. $ git remote rename <原主机名> <新主机名>

Fetch 拉取远程更新

  1. # 拉取某个主机上的全部更新
  2. $ git fetch <远程主机名>
  3. # 只取特定分支跟新
  4. $ git fetch origin master

Pull 获取更新并合并

  1. # 获取远程分支更新并合并到当前分支
  2. $ git pull origin master
  3. # 建立分支之间的追踪关系
  4. $ git branch --set-upstream master origin/next
  5. # 建立追踪关系后:默认从当前分支对应的远程分支上拉取合并
  6. $ git pull

可能产生冲突的场景

不同的人修改了不同文件

合并顺利,没有冲突。注意防止逻辑冲突

不同人修改了的同文件的不同区域

会自动合并

不同人修改了同文件的同一区域

直接冲突

同时变更了文件名和文件内容

可以感知到文件名变更;自动合并

把同一文件改成了不同文件名

钩子的使用

客户端钩子的使用:提交代码时触发事件处理

服务端钩子的使用:服务端接受推送事件处理