我的GitHub | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|
baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目录
Bash下的快捷操作
常用命令
-
cd
:change directory 改变目录,bash中不带参数时默认进入【/c/Users/当前用户】目录,cmd中不带参数时等价于pwd -
cd -
:回到前一个目录,cmd中没有此命令 -
cd ..
:回到父目录 -
cd aaa
:进入指定目录,可以是相对目录或绝对目录 -
pwd
:打印工作目录路径 -
ls
和ll
:列出当前目录中的所有文件,cmd中没有ll命令 -
touch aaa.txt
:在当前目录下新建一个文件 -
mkdir aaa
:在当前目录下新建一个目录 -
rm aaa.txt
:删除指定的文件 -
rm -r aaa
:删除指定的目录,参数r
为recusive是递归的意思 -
mv aaa.txt bbb
:将文件移到指定目录下 -
q
:结束一个命令 - explorer aa:打开指定的目录或文件
常用操作
- 复制内容:选中后就已经复制了(勾选了"选择时复制"),或
Ctrl + Insert
- 粘贴内容:点击鼠标中键,或
Shift + Insert
- 搜索内容:
Alt + F3
,按Enter
或Shift + Enter
选中下/上一个匹配内容 - 缩放文字:
Ctrl + 【+/-】
- 窗口清屏:
Alt + F8
(重置),cmd 下的命令是cls
【重要】 - 窗口全屏:
Alt + F11
,再按一次还原
移动光标
- 一个单词一个单词向
左/右
移动光标:Alt + B/F
【重要】 - 移动光标到整条命令的
起始/结束
位置:Ctrl + A/E
【重要】 - 一个字符一个字符向
左/右
移动光标:Ctrl + B/F
删除输入内容
- 删除光标
左/右
侧的所有内容:Ctrl + U/K
【重要】 - 删除光标
左
侧的单词:Ctrl + W
【重要】 - 删除光标
右
侧的单词:Alt + D
- 删除光标
左/右
侧的字符:Ctrl + H/D
(或backspace键、delete键)
Tab键的作用
- 输入内容(文件名或命令)的前几个字母时,按tab,如果有内容可以匹配,它就会显示出完整的内容
- 如果有多个内容匹配到,它会显示最先找到的一个,再按一次tab,它就会匹配的下一个
- 我们可以不停地按Tab键在匹配的内容中来回切换,直到找到我们文件名为止
Git默认Vim编辑器基本使用
Git默认的编辑器是Vim,在很多情境下会遇到它,例如commit提交,如果提供-m
指令,直接在后面写上此次提交的说明信息;如果不提供-m
指令,默认将会弹出Vim编辑器,如下:
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
此编辑器和平时所用编辑器差距很大,Vim编辑器命令很多,下面介绍一下简单操作,以完成基本的Git操作。
Vim主要有如下两种模式:
- Normal 模式:命令模式,按
ESC
或Ctrl + [
进入,此模式下无法输入内容,但是可以复制、黏贴、保存、退出-
:w
表示保存 -
:q
表示离开,如果未保存会有提示 -
:q!
表示不保存离开 -
:wq
表示保存并离开(用的最多)
-
- Insert 模式:编辑模式,点击i、a 或 o 键可以进入
Git 使用场景
合并多个commit:rebase -i【s】
基本步骤
- 执行
git rebase -i HEAD~影响的最少commit数
或git rebase -i 前一个commitId
- 将
需要合并的那条commit
前面的pick
改为s
,保存后退出 - 修改commit日志,保存后退出
详细操作
在使用 Git 作为版本控制的时候,我们可能会由于各种各样的原因提交了许多临时的 commit
,而这些 commit 拼接起来才是完整的任务。那么我们为了避免太多的 commit 而造成版本控制的混乱,通常我们推荐将这些 commit 合并成一个。
首先你要知道自己想合并的是哪几个提交,可以使用 git log 命令来查看提交历史,假如最近 4 条历史如下:
commit 8b5cbda494a68582164048159e605e731f357444 (HEAD -> master)
commit a472755058e78a33595390f87d03d855fc25da84
commit 6ab13045d47157842961fae70baa7ef25e1856b1
commit 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f (origin/master, origin/HEAD)
历史记录是按照时间排序的,时间近的排在前面。
如果想要合并第 2 和第 3 条记录,有两个方法,这两个方法效果是一致的:
- 从HEAD版本开始往过去数 3 个版本
git rebase -i HEAD~3
- 指名要合并的版本
之前
的版本号
git rebase -i 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f
请注意 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f 这个版本是不参与合并的,可以把它当做一个坐标
执行了 rebase 命令之后,会弹出一个窗口,内容如下:
pick 6ab1304 11111111
pick a472755 222222222
pick 8b5cbda 3333333
# Rebase 00b8fe5..8b5cbda onto 00b8fe5 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword(改写) = use commit, but edit the commit message
# e, edit = use commit, but stop for amending(修正)
# s, squash(塞入) = use commit, but meld into(融入) previous commit
# f, fixup(修正) = like "squash", but discard(丢弃) this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
# Note that empty commits are commented out(被注释掉的)
可以看到,里面有详细的命令提示。我们将需要合并的那条commit
前面的pick
改为s
,之后保存并关闭文本编辑窗口即可。改完之后文本内容如下:
pick 6ab1304 11111111
s a472755 222222222
pick 8b5cbda 3333333
然后保存退出。如果没有冲突,或者冲突已经解决,则会出现如下的编辑窗口:
# This is a combination of 2 commits.
# This is the 1st commit message:
11111111
# This is the commit message #2:
222222222
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit(空消息会终止提交).
#
# Date: Sun Jul 7 21:14:02 2019 +0800
#
# interactive(互动) rebase in progress; onto 00b8fe5
# Last commands done (2 commands done):
# pick 6ab1304 11111111
# squash a472755 222222222
# Next command to do (1 remaining command):
# pick 8b5cbda 3333333
# You are currently rebasing branch 'master' on '00b8fe5'.
#
# Changes to be committed:
# modified: build.gradle
如果不做任何修改的话,默认是保留两次 commit 的日志,中间有一个空白行,你可以随意修改合并后的日志。
保存并退出后再次输入 git log 查看 commit 历史信息,你会发现这两个 commit 已经合并了。
commit 9adb987d31f11f8d38f8d817096d2d21a7390a1d (HEAD -> master)
commit 052ea3ea0b30c375e79ad9e891c5e5202768b11b
commit 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f (origin/master, origin/HEAD)
虽然我们只是合并了第 2 条和第 3 条的commit,但是第 1 条的 commitId 也变了。
如果有冲突,需要修改。修改的时候要注意,保留最新的历史,不然我们的修改就丢弃了。
修改以后要记得敲下面的命令:
git add .
git rebase --continue
如果你想放弃这次压缩的话,执行以下命令:
git rebase --abort
删除多个commit:rebase -i【d】
和上面的操作基本一致。
例如我的提交历史如下:
commit 831be8ec644c4943374adca03880732c7ec9d6bd (HEAD -> master)
commit 6a8ecb529a4ec6b6e0fc83e0789043b7785e73fe
commit 3b228d8af9e52806c106ef3f0c27e622b5407faf
commit 9adb987d31f11f8d38f8d817096d2d21a7390a1d (origin/master, origin/HEAD)
我想删除第2条和第3条提交,基本步骤:
- 执行
git rebase -i HEAD~影响的最少commit数
或git rebase -i 前一个commitId
- 将
需要删除的那几条commit
前面的pick
改为d
,保存后退出 - 修改commit日志,保存后退出
注意,这个操作感觉出现冲突的概率比较大,例如我上面三次commit都是在同一个文件的第一行插入一行新的文字:
//添加3
//添加2
//添加1
执行rebase后就会提示冲突了:
git rebase -i 9adb987d31f11f8d38f8d817096d2d21a7390a1d
Auto-merging build.gradle
CONFLICT (content): Merge conflict in build.gradle
error: could not apply 831be8e... 333
Resolve all conflicts manually手动, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 831be8e... 333
解决冲突后按以下操作:
git add .
git rebase --continue
可以发现,相应 commit 都还原了,包括修改的文件以及提交的commit记录。
修改多个commit:rebase -i【r】
和上面的操作基本一致。
例如我的提交历史如下:
commit 442... (HEAD -> master)
commit 5a1...
commit 305...
commit f30... (origin/master, origin/HEAD)
我想修改第2条和第3条提交,基本步骤:
- 执行
git rebase -i HEAD~影响的最少commit数
或git rebase -i 前一个commitId
- 将
需要修改的那几条commit
前面的pick
改为r
,保存后退出 - 每个改为reword的提交都会提示你一个编辑窗口让你修改commit日志,修改保存后退出
注意,修改后会生成新的commitId
挑选多个commit:cherry-pick
cherry-pick 的翻译是择优挑选
,使用git cherry-pick
命令,可以选择将现有的一个或者多个提交的修改引入当前内容。
git cherry-pick <commitid> <commitid>
挑选多个提交合并,提交之间用空格
相隔。
git cherry-pick <start-commit>..<end-commit>
挑选一个范围内的多个提交合并,不包含start-commit(最早的提交),包含end-commit(最近的提交)。另外要注意两个 commit 之间要求有连续关系的,并且前者要在后者之前,顺序不能颠倒。
git cherry-pick <start-commit>^..<end-commit>
这个和上面一样,区别就是加了一个^
符号,就变成闭区间了,包含 start-commit。
git cherry-pick <branch name>
挑选 branch 最顶端的提交。
git cherry-pick --continue //继续下个操作
git cherry-pick --quit //退出
git cherry-pick --abort //停止本次操作
当 cherry-pick 多个 commit 时,假设遇到冲突:
-
--continue
继续进行下个 -
--quit
结束 cherry-pick 操作但是不会影响冲突之前多个提交中已经成功的 -
--abort
直接打回原形,回到 cherry-pick 前的状态,包括多个提交中已经成功的
使用 git branch -d 删除分支的条件
参考:git branch -d 和 git branch -D 的区别
结论:在使用
-d
删除分支时,该分支必须完全和它的上游分支merge完成,如果没有上游分支,必须要和HEAD
完全merge。
案例一
- 1、现有一个本地分支 v0.1,我做一些修改后 commit (没有 commit或stash 是不能切换到其他分支的)
- 2、然后切到其他分支(因为不能删除当前分支)后删除 v0.1 试试 ,可以发现删除失败
git branch -d v0.1
error: The branch 'v0.1' is not fully merged.
If you are sure you want to delete it, run 'git branch -D v0.1'.
3、然后切到 v0.1 上,将修改推送到远端:git push origin v0.1
4、然后再切到其他分支后删除 v0.1 试试,可以发现删除成功,但是有警告
git branch -d v0.1
warning: deleting branch 'v0.1' that has been merged to 'refs/remotes/origin/v0.1', but not yet merged to HEAD.
Deleted branch v0.1 (was 4a79623).
上面的步骤进行一些优化:
4、假如我们后面删除前是切到了 master 分支,所以当前HEAD
为 master 分支("所以"这个词用的对吗?)
5、将 v0.1 上的修改 merge 过来git merge v0.1
,然后再删除 v0.1 试试,可以发现删除成功且没有警告
案例二
- 1、首先我基于当前分支 v0.1 创建了一个分支 v0.1_copy:
git branch v0.1_copy
(此分支并没有上游分支) - 2、然后切到 v0.1_copy 上,并进行一些修改,然后 commit
- 3、然后切到 v0.1 后删除 v0.1_copy 试试,可以发现删除失败
git branch -d v0.1_copy
error: The branch 'v0.1_copy' is not fully merged.
If you are sure you want to delete it, run 'git branch -D v0.1_copy'.
5、然后切到 v0.1 上,并将 v0.1_copy 上的修改 merge 过来git merge v0.1_copy
6、然后再删除 v0.1_copy 试试,可以发现删除成功且没有警告
git branch -d v0.1_copy
Deleted branch v0.1_copy (was 03cb1c6).
总结
简单来说就是这么一个设计思想:
- 如果一个分支有和远端分支关联(有上游分支),那么在删除此分支前需要将此分支上的commit push到远端,不然在分支被删除时在其上所做的 commit 也一并被删除了,设计者认为这样的操作风险极大
- 如果一个分支没有和远端分支关联(没有上游分支),由于在此分支上的 commit 不能 push 到远端,那么为了防止 commit 也一并被删除了,设计者要求必须要和
HEAD
完全merge才能删除
总之一句话,删除分支不能导致有任何已做的 commit 无法追踪,如果你想这么做,必须使用 -D 达到你的目的
解决 push 时提示 Everything up-to-date 问题
问题复现
1、现在有一个本地分支 v0.1,且其和远端分支 v0.1 关联,此时你在本地 v0.1 做的任何修改都可以通过git push origin v0.1
推到远端,这很正常
2、然后你通过git branch v0.1_backup
创建了一个备份分支,然后 checkout 到此分支后做了一些修改,当你 commit 后 push 到远端的 v0.1 时问题就出现了
git push origin v0.1
Everything up-to-date
其实这里的 "Everything up-to-date(最新)", 的含义是:
"all the branches you've told me how to push are up to date".
也就是说远端的v0.1是最新的
并且此时其实并没有push到远端的
git status
On branch v0.1_backup
Your branch is ahead of 'origin/v0.1' by 1 commit.
原因是很简单的,分支 v0.1_backup 并没有和远端分支关联
$ git branch -vv
master de18ed6 [origin/master] 修改1
v0.1 03cb1c6 [origin/v0.1] 修改2
* v0.1_backup 88eb433 修改3
3、现在你通过git branch -u origin/v0.1 v0.1_backup
可以将其和远端的 v0.1 关联
$ git branch -vv
master de18ed6 [origin/master] 修改1
v0.1 03cb1c6 [origin/v0.1] 修改2
* v0.1_backup 88eb433 [origin/v0.1: ahead 1] 修改3
4、然后再 push 到远端的 v0.1 会发现,问题依旧
解决方式
解决方式有三个:
1、改名,将本地分支名 v0.1_backup 改为和远程分支名一样的 v0.1 就可以了。神马,同名的分支已存在?那你为什么不在已存在的那个分支上操作呢?
2、merge,比如上面说的和远程分支同名的本地分支 v0.1 已存在时,可以先将 v0.1_backup 的修改 merge 到 v0.1 上,然后再在 v0.1 上 push 就可以了。虽然麻烦,但是这是标准操作(个人感觉)。
3、使用下面的命令也可以
git push origin v0.1_backup:v0.1
Author 与 Committer 有什么区别
- Author 是实际的修改者(patch 的作者),Committer 是提交者(把 patch 应用到 repository 里的人)
- 很多项目限制只有少数人可以提交 patch,但大家(patch 的作者)都可以把 patch 发送给这些人
- committer 只能通过 commit 得到,通过 git commit --reset-author 或者 --author="Name" 可以修改 Author(一般不会修改)
2019-7-14