今日份鸡汤:努力从来不嫌晚,只要你坚定开始就可以啦~
进入正题:
1、Git clone(远程项目clone到本地):
参数挺多,但常用的就几个:
1> 最简单直接的命令:git clone xxx.git
2> 如果想clone到指定目录:git clone xxx.git "指定目录"
3> clone时创建新的分支替代默认Origin HEAD(master):git clone -b new_branch_name xxx.git
4> clone 远程分支
git clone 命令默认的只会建立master分支,如果你想clone指定的某一远程分支(如:dev)的话,可以如下:
A. 查看所有分支(包括隐藏的) git branch -a 显示所有分支,如:
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master
B. 在本地新建同名的("dev")分支,并切换到该分支
git checkout -t origin/dev 该命令等同于:git checkout -b dev origin/dev
2、分支查看:
1> 查看本地分支:git branch
2> 查看远程分支:git branch -r
3> 查看跟踪分支:git branch -vv
3、git checkout -b(从已有本地分支拉新分支):
开发过程中经常用到从master分支copy一个开发分支,下面我们就用命令行完成这个操作:
1> 切换到被copy的分支(master),并且从远端拉取最新版本
git checkout master
git pull
2> 从当前分支拉copy开发分支:git checkout -b dev
执行上面的命令后提示 Switched to a new branch 'dev',证明已经切换到新的分支上
3> 把新建的分支push到远端:git push origin dev
4> 拉取远端分支:git pull
执行上述命令提示:
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> dev
经过验证,当前的分支并没有和本地分支关联,根据提示进行下一步:
5> 关联:git branch --set-upstream-to=origin/dev
6> 再次拉取 验证:git pull
看到提示:Already up-to-date,到此完事。
4、git tag(给当前分支打标签):
列出tag:
git tag:在控制台打印出当前仓库的所有tag
git tag -l 'v0.1.*': 搜索符合模式的Tag
打tag:
git tag分为两种类型:轻量tag和附注tag。轻量tag是指向提交对象的引用,附注Tag则是仓库中的一个独立对象。建议使用附注Tag。
创建轻量Tag:git tag v0.1.2-light
创建附注Tag:git tag -a v0.1.2 -m "0.1.2版本" (我一般上线前打tag都用这种)
创建轻量Tag不需要传递参数,直接指定Tag名称即可。
创建附注Tag时,参数a即annotated的缩写,指定Tag类型,后附Tag名。参数m指定Tag说明,说明信息会保存在Tag对象中。
切换到Tag:git checkout tagName (与切换分支命令相同)
查看Tag信息:git show v0.1.2(用git show命令可以查看Tag的版本信息)
删除Tag:git tag -d v0.1.2(误打或需要修改Tag时,需要先将Tag删除,参数d即delete的缩写,意为删除其后指定的Tag。)
删除远程tag:git push origin --delete tag tagName
给指定的commit打Tag
打Tag不必要在head之上,也可在之前的版本上打,这需要你知道某个提交对象的校验和(通过git log获取)。
补打Tag:git tag -a v0.1.1 9fbc3d0
Tag推送到服务器
通常的git push不会将Tag对象提交到git服务器,我们需要进行显式的操作:
git push origin v0.1.2:将v0.1.2 Tag提交到git服务器
git push origin --tags: 将本地所有Tag一次性提交到git服务器
注意:如果想看之前某个Tag状态下的文件,可以这样操作
1> git tag:查看当前分支下的Tag
2> git checkout v0.21 :此时会指向打v0.21 Tag时的代码状态,(但现在处于一个空的分支上)
5、git reset(本地版本回滚):
当我们在合代码的时候经常会遇到一些问题,这时候分支就处于merging状态,这时候可以用下面的命令撤销
git reset --hard HEAD(这个实际工作场景确实用过几次)
1> git reset HEAD^ :回退版本,一个^表示一个版本,可以多个,另外也可以使用 git reset HEAD~n这种形式。
如果HEAD指针指向的是master分支,那么HEAD还可以换成master,如果知道特定的commit-id,那么还可以直接使用 git reset commit-id 如果不加参数,实际上使用的是默认的参数mixed,
我们可以使用git log -3来查看最近三次的提交,形如 git log -n ,n就是想要输出的个数,可以看到commit-id,author,date等信息
下面介绍三种参数:
(1) soft 参数:git reset --soft HEAD~1 意为将版本库软回退1个版本,所谓软回退表示将本地版本库的头指针全部重置到指定版本,且将这次提交之后的所有变更都移动到暂存区
(2) 默认的mixed参数:git reset HEAD~1 意为将版本库回退1个版本,将本地版本库的头指针全部重置到指定版本,且会重置暂存区,即这次提交之后的所有变更都移动到未暂存阶段
(3) hard参数:git reset --hard HEAD~1 意将版本库为回退1个版本,但是不仅仅是将本地版本库的头指针全部重置到指定版本,也会重置暂存区,并且会将工作区代码也回退到这个版本
了解这三个参数已足够我们日常开发使用了, 注意soft参数与默认参数都不会修改工作区代码,只有hard参数才会修改工作区代码。
2> git reset 配合 git commit 追加提交
什么时候会用到追加提交,追加提交有什么优点?
(1)对未merge的版本库中的提交不满意,希望修改其中的某些信息,如代码,如提交描述等,可以使用git commit --amend进行追加提交,优点是不会产生新的commit-id
(2)修改方法:如果想修改的不是最新一版的提交,那么可以通过git reset --hard HEAD~n将版本回退到需要的那版,如果想修改代码,那么直接在工作区进行代码修改,
修改完之后git add到暂存区而不必再git pull,而如果是修改其他信息,那么可以直接使用git commit --amend进行追加提交,git commit --amend命令会打开一个编辑器,可以修改其中的信息,
如果修改了代码而不修改其他信息,则直接 Ctrl + X离开编辑器,再git push推送到远程服务器,如果也修改了其他信息,那么需要先使用Ctrl + M写入信息,再Ctrl + X离开编辑器,再推送。
3> 查看帮助:git reset -h | git reset --help
6、删除分支:
git 删除本地分支:git branch -D branchName
git 删除远程分支:git push origin :branchName (origin 后面有空格)
在Git v1.7.0 之后,可以使用这种语法删除远程分支:git push origin --delete branchName
7、git 远程分支回滚
简单的办法:
先用git log 查找出commit_id
git reset --hard commit_id
git push origin HEAD --force
其他:
根据–soft –mixed –hard,会对working tree和index和HEAD进行重置:
git reset –mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息
git reset –soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可
git reset –hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容
HEAD 最近一个提交
HEAD^ 上一次
<commit_id> 每次commit的SHA1值. 可以用git log 看到,也可以在页面上commit标签页里找到.
麻烦的办法:
这个是重点要说的内容,过程比本地回滚要复杂
应用场景:自动部署系统发布后发现问题,需要回滚到某一个commit,再重新发布
原理:先将本地分支退回到某个commit,删除远程分支,再重新push本地分支
操作步骤:
1>、git checkout the_branch
2>、git pull
3>、git branch the_branch_backup //备份一下这个分支当前的情况
4>、git reset --hard the_commit_id //把the_branch本地回滚到the_commit_id
5>、git push origin :the_branch //删除远程 the_branch
6>、git push origin the_branch //用回滚后的本地分支重新建立远程分支
7>、git push origin :the_branch_backup //如果前面都成功了,删除这个备份分支
如果使用了gerrit做远程代码中心库和code review平台,需要确保操作git的用户具备分支的push权限,并且选择了 Force Push选项(在push权限设置里有这个选项)
另外,gerrit中心库是个bare库,将HEAD默认指向了master,因此master分支是不能进行删除操作的,最好不要选择删除master分支的策略,换用其他分支。如果一定要这样做,可以考虑到gerrit服务器上修改HEAD指针。。。不建议这样做
8、git stash(git 储藏工具)
储藏(Stashing)
经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令。
“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。
储藏你的工作
为了演示这一功能,你可以进入你的项目,在一些文件上进行工作,有可能还暂存其中一个变更。如果你运行 git status,你可以看到你的中间状态:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# modified: index.html
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# modified: lib/simplegit.rb
现在你想切换分支,但是你还不想提交你正在进行中的工作;所以你储藏这些变更。为了往堆栈推送一个新的储藏,只要运行 git stash:
$ git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
你的工作目录就干净了:
$ git status
# On branch master
nothing to commit, working directory clean
这时,你可以方便地切换到其他分支工作;你的变更都保存在栈上。要查看现有的储藏,你可以使用 git stash list:
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
在这个案例中,之前已经进行了两次储藏,所以你可以访问到三个不同的储藏。你可以重新应用你刚刚实施的储藏,所采用的命令就是之前在原始的 stash 命令的帮助输出里提示的:git stash apply。如果你想应用更早的储藏,你可以通过名字指定它,像这样:git stash apply stash@{2}。如果你不指明,Git 默认使用最近的储藏并尝试应用它:
$ git stash apply
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# modified: index.html
# modified: lib/simplegit.rb
你可以看到 Git 重新修改了你所储藏的那些当时尚未提交的文件。在这个案例里,你尝试应用储藏的工作目录是干净的,并且属于同一分支;但是一个干净的工作目录和应用到相同的分支上并不是应用储藏的必要条件。你可以在其中一个分支上保留一份储藏,随后切换到另外一个分支,再重新应用这些变更。在工作目录里包含已修改和未提交的文件时,你也可以应用储藏——Git 会给出归并冲突如果有任何变更无法干净地被应用。
对文件的变更被重新应用,但是被暂存的文件没有重新被暂存。想那样的话,你必须在运行 git stash apply 命令时带上一个 --index 的选项来告诉命令重新应用被暂存的变更。如果你是这么做的,你应该已经回到你原来的位置:
$ git stash apply --index
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# modified: index.html
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# modified: lib/simplegit.rb
apply 选项只尝试应用储藏的工作——储藏的内容仍然在栈上。要移除它,你可以运行 git stash drop,加上你希望移除的储藏的名字:
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
你也可以运行 git stash pop 来重新应用储藏,同时立刻将其从堆栈中移走。
取消储藏(Un-applying a Stash)
在某些情况下,你可能想应用储藏的修改,在进行了一些其他的修改后,又要取消之前所应用储藏的修改。Git没有提供类似于 stash unapply 的命令,但是可以通过取消该储藏的补丁达到同样的效果:
$ git stash show -p stash@{0} | git apply -R
同样的,如果你沒有指定具体的某个储藏,Git 会选择最近的储藏:
$ git stash show -p | git apply -R
你可能会想要新建一个別名,在你的 Git 里增加一个 stash-unapply 命令,这样更有效率。例如:
$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply
从储藏中创建分支
如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 git stash branch,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。
$ git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# modified: index.html
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# modified: lib/simplegit.rb
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
这是一个很棒的捷径来恢复储藏的工作然后在新的分支上继续当时的工作。
9、git rebase(git 合并多个 Commit)
在使用 Git 作为版本控制的时候,我们可能会由于各种各样的原因提交了许多临时的 commit,而这些 commit 拼接起来才是完整的任务。那么我们为了避免太多的 commit 而造成版本控制的混乱,通常我们推荐将这些 commit 合并成一个。
首先假设我们有3个 commit,用git log -3命令来查看。
我们需要将 2dfbc7e8 和 c4e858b5 合并成一个 commit,那么我们输入如下命令
其中,-i 的参数是不需要合并的 commit 的 hash 值,这里指的是第一条 commit, 接着我们就进入到 vi 的编辑模式
可以看到其中分为两个部分,上方未注释的部分是填写要执行的指令,而下方注释的部分则是指令的提示说明。指令部分中由前方的命令名称、commit hash 和 commit message 组成。
当前我们只要知道 pick 和 squash 这两个命令即可。
pick 的意思是要会执行这个 commit
squash 的意思是这个 commit 会被合并到前一个commit
我们将 c4e858b5 这个 commit 前方的命令改成 squash 或 s,然后输入:wq以保存并退出
这是我们会看到 commit message 的编辑界面
其中, 非注释部分就是两次的 commit message, 你要做的就是将这两个修改成新的 commit message。
输入wq保存并推出, 再次输入git log查看 commit 历史信息,你会发现这两个 commit 已经合并了。
注意事项:如果这个过程中有操作错误,可以使用 git rebase --abort来撤销修改,回到没有开始操作合并之前的状态。