git 分支管理 推送本地分支到远程分支等

1、创建本地分支 local_branch

git branch local_branch

2、创建本地分支local_branch 并切换到local_branch分支

git checkout -b local_branch

3、切换到分支local_branch

git checkout local_branch

4、推送本地分支local_branch到远程分支 remote_branch并建立关联关系

a.远程已有remote_branch分支并且已经关联本地分支local_branch且本地已经切换到local_branch

git push

b.远程已有remote_branch分支但未关联本地分支local_branch且本地已经切换到local_branch

git push -u origin/remote_branch

c.远程没有有remote_branch分支并,本地已经切换到local_branch

git push origin local_branch:remote_branch

5、删除本地分支local_branch

git branch -d local_branch

6、删除远程分支remote_branch

git push origin  :remote_branch

git branch -m | -M oldbranch newbranch 重命名分支,如果newbranch名字分支已经存在,则需要使用-M强制重命名,否则,使用-m进行重命名。

git branch -d | -D branchname 删除branchname分支

git branch -d -r branchname 删除远程branchname分支

7、查看本地分支

git branch

8、查看远程和本地分支

git branch -a

除了 pull 和 push 你应该知道 git 的操作

git 仓库简单示意图

| 工作区(Working) | 暂存区(Staging) | 版本库(Local repo)| 远程仓库(Remote repo)|

    |---- git add ---->|--- git commit --->|---- git push --->|
    |----------- git commit -am  --------->|---- git push --->|
    |<- git checkout --|<--- git reset ----|<--- git pull ----|
    |<--------- git reset --hard HEAD -----|<--- git pull ----|

与远程分支建立追踪关系(tracking)

git branch --set-upstream master origin/master

设置 rebase 让历史变得清晰

git config --global branch.autosetuprebase always # 所有分支
git config branch.master.rebase true # 指定分支

查看 git 配置信息

git config --list

禁止终端显示中文文件名为 xxxxxx 形式

git config --global core.quotepath false

更美观的输出 log

git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset' --abbrev-commit --date=relative -10
git log

查看简要的 log

git log --oneline --5

强制更新,覆盖本地修改

git fetch --all
git reset --hard origin/master

操作撤销(还没有 push)

git reset --soft 3ce07 # 回滚到多个提交之前,但保留没有提交的改变(不回滚工作区和缓存区)
git reset --hard HEAD # 回滚到最近一次的提交(会回滚工作区和缓存区)

操作撤销 (已经 push)

git revert c011e # 用一个新提交来消除一个历史提交所做的修改

版本撤销

git log
git reset --hard e54dd31

修改 commit 注释

git commit --amend -m "Fixes bug #42"

版本恢复

git reflog
git reset --hard c80ae4f

隐藏工作区

git stash # 暂存改动(默认备注)
git stash save "暂存头部样式修改" # 暂存改动,自定义备注
git stash list # 查看暂存的改动列表
git stash pop --index stash@{0} # 释放指定暂存项
git stash pop # 释放全部暂存的改动
git stash drop # 删除暂存的改动

查看修改日志

git log --author=yida # 查看特定成员的更新记录
git log --grep="等待页面" # 按关键字搜索更新记录
git log ./package.json # 查看指定文件的更改日志

打 Tag 操作

git tag v0.9 # 在 HEAD 打"轻 tag"
git tag -am "xxx" v0.9 # 在 HEAD 打"注解 tag"
git tag v0.9 a032c # 在指定提交打"轻 tag"
git tag -a v0.1 -m "xxx" a032c # 在指定提交打"注解 tag"
git tag # 查看打过的 tag
git tag -n # 查看打过的 tag 及注解
git push origin v1.0 # 将 tag 推送到远程
git push origin --tags # 推送全部尚未推送到远程的 tag
git tag -d v0.9 # 删除本地 tag
git push origin :refs/tags/v0.9 # 从远程删除 tag

基于某个 tag 创建新分支

假设在你的主分支上有一个 tag 为 v1.0 , 主分支的名字为 master:

git branch new_branch v1.0 # 以 tag v1.0 创建新的分支 newbranch
git checkout new_branch # 切换到分支 newbranch
git push origin new_branch # 把本地 newbranch 分支提交到远程仓库

添加忽略文件

echo '*~' >> .gitignore
git add .gitignore

添加全局忽略文件

git config --global core.excludesfile ~/.gitignore_global
vim ~/.gitignore_global

加入要忽略的文件名

Git 使用问题

问题1:怎样设置 git 操作免输账号密码?

1、在主文件夹下创建文件 .git-credentials, 用vim编辑:

cd ~
touch .git-credentials
vim .git-credentials

2、在 .git-credentials 添加 https://{username}:{password}@github.com,例如:

https://yida:[email protected]

3、在终端下执行命令:

git config --global credential.helper store

4、查看到 ~/.gitconfig 文件新加入一项配置:

[credential]
helper = store

以后 git 操作就不再需要密码验证

问题2:怎样设置 git 忽略已经被提交的文件?

git update-index --assume-unchanged .ftpconfig # 忽略跟踪 .ftpconfig
git update-index --no-assume-unchanged .ftpconfig # 恢复跟踪 .ftpconfig
git ls-files -v | grep -e "^[hsmrck]" # 查看当前被忽略、已经纳入版本库管理的文件

问题3: 如何把在本地 A 分支上的一个 commit(7b31b7)放到本地 B 分支上?

git checkout B
git cherry-pick 7b31b7

问题4. 查看谁弄乱了文件 index.php 的代码?

git blame index.php

问题5. 怎样恢复丢失的提交?

git reflog # 查看该所有操作日志 -- 例如,丢失的提交信息如下:
# 794b305 HEAD@{24}: rebase: 修改开户状态相关
git branch recover-branch 794b305 # 在丢失的 commit(794b305) 上创建一个新分支, 即可恢复此次提交

Git 工作流的正确打开方式

未分类

前言

一直在使用git做版本控制,也一直工作很顺利,直到和别人发生冲突的时候。这才注意到git 工作流并不是那么简单。比如,之前遇到的清理历史。百度到的资料很多,重复性也很多,但实践性操作很少,我很难直接理解其所表达的含义。直接望文生义经常得到错误的结论,只能用时间去检验真理了,不然看到的结果都是似懂非懂,最后还是一团糟。

学习git工作流

一、最简单的使用,不推荐

1.1 创建仓库

$ pwd
/home/ryan/workspace/l4git-workflow
$ touch readme.md
$ ls
readme.md
$ touch .gitignore
$ git init
初始化空的 Git 仓库于 /home/ryan/workspace/l4git-workflow/.git/
$ touch test.txt
$ git add .
$ git commit -m "init"
[master (根提交) dae77d6] init
 3 files changed, 12 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 readme.md
 create mode 100644 test.txt
$ git remote add origin [email protected]:Ryan-Miao/l4git-workflow.git
$ git push -u origin master
对象计数中: 5, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (3/3), 完成.
写入对象中: 100% (5/5), 388 bytes | 0 bytes/s, 完成.
Total 5 (delta 0), reused 0 (delta 0)
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。

未分类

1.2 模拟用户A

git clone [email protected]:Ryan-Miao/l4git-workflow.git
git checkout a
touch a.txt
//write one
//....
$ git add .
$ git commit -m "one"
[a 53ff45e] one
 2 files changed, 34 insertions(+), 2 deletions(-)
 create mode 100644 a.txt

此时,a还没有提交到 origin 。 git log 如下:

未分类

1.3 模拟用户B

git clone [email protected]:Ryan-Miao/l4git-workflow.git
git checkout b
$ touch b.txt

//write something
//…

$ git add .
$ git commit -m "b write one"
[b 847078e] b write one
 1 file changed, 1 insertion(+)
 create mode 100644 b.txt

//write something
//….

$ git add . $ git commit -m "b write two" [b 3f30f41] b write two 1 file changed, 2 insertions(+), 1 deletion(-)

此时,git log如下

未分类

1.4 模拟用户A

A和B分别是在本地开发,所以这种顺序是未知的,也许A比B先commit一次,也许B先commit一次。这里的先后是指commit的时间戳。但都是在本地提交的代码。
write something

git add .
git commit -m "a write two"

wirte something

git add .
git commit -m "write three"

A push to server branch a

$ git push origin a:a
Total 0 (delta 0), reused 0 (delta 0)
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      a -> a

A created a Pull Request

未分类

未分类

1.5 模拟用户C

C review the PR and then merged it.

未分类

此时,github的历史如下:

未分类

可以看出,merge的时候多了一次commit,message默认为

Merge pull request #1 from Ryan-Miao/a...

现在看起来,只有a一个人的历史记录,还算清楚,a做了3次提交。

1.6 模拟用户B

用户B提交前先pull master,更新最新的代码到本地,防止冲突。

git fetch
git merge origin/master

此时log看起来有点乱。如下:

未分类

让人感到混乱的是b原来的历史只有自己的提交,更新了master到本地之后,历史记录被插入了master中的历史。于是,发现原来自己干净的历史被中间插入多次commit。甚至两次merge master的日志显得又长又碍眼。但不管怎么说,B还是要提交的。

于是,B提交到远程分支b:

未分类

1.7 模拟用户C

这时候,A完成了feature a,然后提了PR,然后找他人C merge了。而后,B也完成了feature b,提了PR,需要review and merge。 C review之后,approved, 然后D review, D merge。

此时,项目基本走上正规。feature一个一个添加进去,重复之前的工作流程: fetch -》 work -》 commit -》 push -》 PR -》 merged。
然后,项目历史就变成了这样:

未分类

一眼大概看起来还好,每次都能看到提交历史,只要不是message写的特别少,差不多可以理解最近提交的内容。然而,仔细一看,顺序好像不对。目前一共两个feature,但历史却远远超过2个。没关系,保证细粒度更容易体现开发进度。然而,这些历史并不是按照feature的发布顺序,那么,当我想要找到feature a的时候就很难串联起来。如果commit足够多,时间跨度足够大,甚至根本看不出来feature a到底做了哪些修改。

这时候想要使用图形化git 历史工具来帮助理解历史:

未分类

这里,还好,还勉强能看出走向。但当10个上百个人同时开发的话,线简直不能看了,时间跨度足够大的话,线也看不完。

因此,这种模式,正是我们自己当前采用的模式。差评。这还不算完,后面更大的困难来了。最先发布的feature a出了问题,必须回滚。怎么做到。关于回滚,就是另一个话题了。 但我们应该知道使用revert而不是reset. 但revert只能回滚指定的commit,或者连续的commit,而且revert不能revert merge操作。这样,想回滚feature a, 我们就要找到a的几次提交的版本号,然后由于不是连续的,分别revert。这会造成复杂到不想处理了。好在github给了方便的东西,PR提供了revert的机会。找到以前的PR。

未分类

但是,这绝对不是个好操作!

二、推荐的工作流程

造成上述现象的原因是因为各自异步编程决定的。因为每个人都可以随时间提交,最后合并起来的时候以提交时间戳来作为序列的依据,就会变成这样。因此,当需要提交的远程服务器的时候,如果能重写下commit的时间为当前时间,然后push到服务端,历史就会序列到最后了。

2.1 模拟用户C

C用户新下载代码。

$ git clone [email protected]:Ryan-Miao/l4git-workflow.git c正克隆到 'c'...
remote: Counting objects: 28, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 28 (delta 8), reused 22 (delta 4), pack-reused 0
接收对象中: 100% (28/28), 5.90 KiB | 0 bytes/s, 完成.
处理 delta 中: 100% (8/8), 完成.
检查连接... 完成。

然后编辑,提交

$ cd c
$ git config user.name "C"
$ ls
a.txt  b.txt  readme.md  test.txt
$ vim c.txt
$ git add .
$ git commit -m "C write one"
[master cf3f757] C write one
 1 file changed, 2 insertions(+)
 create mode 100644 c.txt

2.2 模拟用户D

同时,D也需要开发新feature

$ git clone [email protected]:Ryan-Miao/l4git-workflow.git d正克隆到 'd'...
remote: Counting objects: 28, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 28 (delta 8), reused 22 (delta 4), pack-reused 0
接收对象中: 100% (28/28), 5.90 KiB | 0 bytes/s, 完成.
处理 delta 中: 100% (8/8), 完成.
检查连接... 完成。
$ cd d
/d$ git config user.name "D"
/d$ vim d.txt
/d$ git add .
/d$ git commit -m "d write one"
[master db7a6e9] d write one
 1 file changed, 1 insertion(+)
 create mode 100644 d.txt

2.3 C继续开发

$ vim c.txt
$ git add .
$ git commit -m "c write two"
[master 01b1210] c write two
 1 file changed, 1 insertion(+)

2.4 D继续开发

/d$ vim d.txt
/d$ git add .
/d$ git commit -m "d write two"
[master a1371e4] d write two
 1 file changed, 1 insertion(+)

2.5 C 提交

$ vim c.txt 
$ git add .
$ git commit -m "c write three"
[master 13b7dde] c write three
 1 file changed, 1 insertion(+)

C开发结束,提交到远程

$ git status
位于分支 master
您的分支领先 'origin/master' 共 3 个提交。
  (使用 "git push" 来发布您的本地提交)
无文件要提交,干净的工作区
$ git push origin master:C
对象计数中: 9, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (6/6), 完成.
写入对象中: 100% (9/9), 750 bytes | 0 bytes/s, 完成.
Total 9 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> C

2.6 C 提PR

然后,create a Pull Request.

未分类

2.7 C修改再push

然后,发现还有个bug要修复,再次修改提交到远程C

$ vim c.txt 
$ git add .
$ git commit -m "C finish something else"
[master 2c5ff94] C finish something else
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin master:C
对象计数中: 3, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (3/3), 完成.
写入对象中: 100% (3/3), 301 bytes | 0 bytes/s, 完成.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
   13b7dde..2c5ff94  master -> C

2.8 C发现提交次数过多,历史太乱,合并部分历史

这时,发现一个问题,由于C在开发过程中提交了多次,而这几次提交的message其实没有多大意思,只是因为C可能为了保存代码,也可能是暂存。总之,C的前3次提交的message的含义其实是一样的,都是创建C文件,都是一个主题,那么为了维护历史的干净。最好把这3条信息合并成一条C create file c.txt。

参考git 合并历史,我们需要将3次历史合并成显示为一次。

查看git历史,找到需要合并的起始区间

$ git log --oneline
2c5ff94 C finish something else
13b7dde c write three
01b1210 c write two
cf3f757 C write one
7151f4c 记录操作。
0bfe562 Merge pull request #2 from Ryan-Miao/b_remote
d81ce20 Merge remote-tracking branch 'origin/master' into b
2d74cfb Merge pull request #1 from Ryan-Miao/a
b90a3dd write three
4b1629e a write two
3f30f41 b write two
847078e b write one
53ff45e one
dae77d6 init

显然,是要合并cf3f757到13b7dde。那么找到前一个的版本号为7151f4c

git rebase - i 7151f4c

然后进入交互界面,因为我们想要把第3次和第2次以及第1次提交信息合并。将第3次的类型修改为squash, 意思是和第2次合并。然后将第2次的类型修改为squash, 同样是指合并的前一个commit。

未分类

不同git的交互略有不同,之前在windows上的git bash是完全按照vim的命令修改的。本次测试基于Ubuntu,发现存档命令为ctel + X。确认后进入下一个界面,合并3次提交后需要一个message

未分类

删除或者anyway you like, 更改message。存档。完成。

$ git rebase -i 7151f4c
[分离头指针 e3764c5] c create  file c.txt
 Date: Fri Oct 20 22:06:24 2017 +0800
 1 file changed, 4 insertions(+)
 create mode 100644 c.txt
Successfully rebased and updated refs/heads/master.

Tips

当在rebase过程中出现了失误,可以使用git rebase –abort返回初始状态。如果发现冲突,则可以解决冲突,然后git rebase –continue .

好像已有 rebase-merge 目录,我怀疑您正处于另外一个变基操作
过程中。 如果是这样,请执行

git rebase (--continue | --abort | --skip)

如果不是这样,请执行

rm -fr "/home/ryan/temp/c/.git/rebase-merge"

然后再重新执行变基操作。 为避免丢失重要数据,我已经停止当前操作。

此时,查看log, 显然,C的那三次提交已经合并了。

$ git log --oneline
50b9fe9 C finish something else
e3764c5 c create  file c.txt
7151f4c 记录操作。
0bfe562 Merge pull request #2 from Ryan-Miao/b_remote
d81ce20 Merge remote-tracking branch 'origin/master' into b
2d74cfb Merge pull request #1 from Ryan-Miao/a
b90a3dd write three
4b1629e a write two
3f30f41 b write two
847078e b write one
53ff45e one
dae77d6 init

2.9 C再次push

之前的push已经不能用了。需要开新分支推送过去。因为 rebase 只能在本地分支做。不要修改公共分支 。

$ git push origin master:C
To [email protected]:Ryan-Miao/l4git-workflow.git
 ! [rejected]        master -> C (non-fast-forward)
error: 无法推送一些引用到 '[email protected]:Ryan-Miao/l4git-workflow.git'
提示:更新被拒绝,因为推送的一个分支的最新提交落后于其对应的远程分支。
提示:检出该分支并整合远程变更(如 'git pull ...'),然后再推送。详见
提示:'git push --help' 中的 'Note about fast-forwards' 小节。

选择推送的新分支C2

$ git push origin master:C2
对象计数中: 6, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (5/5), 完成.
写入对象中: 100% (6/6), 569 bytes | 0 bytes/s, 完成.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> C2

创建新的PR

未分类

2.10 新的merge方式: rebase

通过开始的普通流程发现,每次merge的时候,都会多出一条新的提交信息,这让历史看起来很奇怪。那么,可以选择rebase到master,变基,就是重新以master为基本,把当前的提交直接移动到master的后面。不会因为提交时间的离散导致多次commit的message被拆散。 选择 rebase and merge

未分类

未分类

这时候,可以看到C提交的两次信息都是最新的,没有发生交叉。而且也没有产生多余的merge信息。

未分类

有人会问,那么岂不是看不到PR的地址了。点开C的历史。可以看到message下方是有PR的编号的:

未分类

对了,刚开始的PR要记得close

未分类

2.11 这时候D也完成了

/d$ git push origin master:D
对象计数中: 10, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (7/7), 完成.
写入对象中: 100% (10/10), 4.49 KiB | 0 bytes/s, 完成.
Total 10 (delta 2), reused 4 (delta 1)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> D

提PR, 这时候,如果采用merge:

未分类

未分类

结果必然发现,1) d提交message被按照时间分散插入历史了(被插入到c的历史之前), 2)多了一次 Merge pull request #5 from Ryan-Miao/D..的提交信息。同开头所述一样,历史开始变得混乱了。那么,这种问题怎么办呢?

2.12 提交前rebase

就像C rebase后merge到master一样。我们一样可以在本地做到这样的事情。在本地rebase,让我们本次feature的提交全部插到master节点之后,有序,而且容易revert。
本次,以新的E和F交叉commit为例子,最终将得到各自分开的历史

E:

$ git clone [email protected]:Ryan-Miao/l4git-workflow.git e
正克隆到 'e'...
remote: Counting objects: 52, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 52 (delta 18), reused 36 (delta 7), pack-reused 0
接收对象中: 100% (52/52), 7.91 KiB | 0 bytes/s, 完成.
处理 delta 中: 100% (18/18), 完成.
检查连接... 完成。

$ cd e
/e$ vim e.txt
/e$ git add .
/e$ git config user.name "E"
/e$ git commit -m "e commit one"
[master 77ecd73] e commit one
 1 file changed, 1 insertion(+)
 create mode 100644 e.txt

F:

$ git clone [email protected]:Ryan-Miao/l4git-workflow.git f
正克隆到 'f'...
remote: Counting objects: 52, done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 52 (delta 18), reused 36 (delta 7), pack-reused 0
接收对象中: 100% (52/52), 7.91 KiB | 0 bytes/s, 完成.
处理 delta 中: 100% (18/18), 完成.
检查连接... 完成。

$ cd f
$ vim f.txt
$ git config user.name "F"
$ git add .
$ git commit -m "d write one"
[master b41f8c5] d write one
 1 file changed, 2 insertions(+)
 create mode 100644 f.txt

E:

/e$ vim e.txt
/e$ git add .
/e$ git commit -m "e write two"
[master 2b8c9fb] e write two
 1 file changed, 1 insertion(+)

F:

$ vim f.txt
$ git add .
$ git commit -m "f write two"
[master de9051b] f write two
 1 file changed, 1 insertion(+)

E:

/e$ vim e.txt 
/e$ git add .
/e$ git commit -m "e write three"
[master b1b9f6e] e write three
 1 file changed, 2 insertions(+)

这时候,e完成了,需要提交。提交前先rebase:

/e$ git fetch
/e$ git rebase origin/master
当前分支 master 是最新的。

然后,再提交

/e$ git push origin master:E
对象计数中: 9, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (6/6), 完成.
写入对象中: 100% (9/9), 753 bytes | 0 bytes/s, 完成.
Total 9 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> E

然后, PR, merge.

同样F:

$ git status
位于分支 master
您的分支领先 'origin/master' 共 2 个提交。
  (使用 "git push" 来发布您的本地提交)
无文件要提交,干净的工作区
$ git fetch 
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 12 (delta 6), reused 6 (delta 3), pack-reused 0
展开对象中: 100% (12/12), 完成.
来自 github.com:Ryan-Miao/l4git-workflow
   24c6818..f36907c  master     -> origin/master
 * [新分支]          E          -> origin/E
$ git rebase origin/master
首先,回退分支以便在上面重放您的工作...
应用:d write one
应用:f write two

$ git push origin master:F
对象计数中: 6, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (4/4), 完成.
写入对象中: 100% (6/6), 515 bytes | 0 bytes/s, 完成.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To [email protected]:Ryan-Miao/l4git-workflow.git
 * [new branch]      master -> F

PR, rebase and merge。 这时候看history:

未分类

按照前几次的做法,E和F交叉在本地提交,每次commit的时间戳也是交叉,最终合并到master的时候,历史并没有被拆散。而是像我们期待的一样,顺序下来。这才是我们想要的。通过看图形化界面也能看出区别:

绿色的线是master

未分类

那么,操作便是fetch-》rebase。事实上,可以二合一为:

git pull --rebase origin master

未分类

三、最终结果

在都没提交到server的时候, 历史是分散在各个开发者的本地,但commit时间有先后。

未分类

按照rebase的用法,提交前rebase一次,就可以使得一个feature的提交串联到一起

未分类

最终在github的commit看起来也就是顺畅的多

未分类

四、金科玉律

想维持树的整洁,方法就是:在git push之前,先git fetch,再git rebase。

git fetch origin master
git rebase origin/master
git push

或者

git pull --rebase origin master

只要你把变基命令当作是在推送前清理提交使之整洁的工具,并且只在从未推送至共用仓库的提交上执行变基命令,就不会有事。 假如在那些已经被推送至共用仓库的提交上执行变基命令,并因此丢弃了一些别人的开发所基于的提交,那你就有大麻烦了,你的同事也会因此鄙视你。

如果你或你的同事在某些情形下决意要这么做,请一定要通知每个人执行 git pull –rebase 命令,这样尽管不能避免伤痛,但能有所缓解。

  • 绝对不要在公共(远程分支)上rebase,也就是说,如果没有必要就不要在github merge的时候选择rebase,而是用上述的办法,在本地自己的分支推送前rebase
  • 绝对不可以在公共分支上reset,也不要用–force
  • 单独功能的多次提交要学会合并提交,保持提交的简洁。
  • 提交message尽量能概括修改内容。

【Git】Ubuntu升级Git版本

问题描述

在使用Ubuntu自带的Git进行提交的时候出现错误

Please upgrade your git client.

用apt-get命令升级git时,提示Git已经是最新版本

$ sudo apt-get install git

Reading package lists... Done
Building dependency tree
Reading state information... Done
git is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded. 

但是我在官网上看的Git版本大于我的Git版本,所以需要更新Git的版本库

解决方法

要获得最新版本的Git,需要在Ubuntu中添加Git的维护者团队PPA(归档包)到软件源列表,然后更新源列表并升级Git

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install -y git

然后查看Git版本

git --version

实用的升级安装方法php,Nginx,mysql,zabbix等

升级版本编译安装当然Ok,依赖问题处理起来非常之繁琐,现在直接通过apt源来升级版本非常简便,下面我们来拿php做个升级实验

1. 添加下面两行到/etc/apt/sources.list,并将jessie替换为自己所使用的版本名称:

deb http://mirrors.ustc.edu.cn/dotdeb jessie all
deb-src http://mirrors.ustc.edu.cn/dotdeb jessie all

2. 可选项:

如果你想在Debian Squeeze上安装PHP5.4的话,再添加下面这两行:

deb http://mirrors.ustc.edu.cn/dotdeb squeeze-php54 all
deb-src http://mirrors.ustc.edu.cn/dotdeb squeeze-php54 all

如果你想在Debian Wheezy上安装未启用Zend Thread Safety的PHP5.6的话,再添加下面这两行:

deb http://mirrors.ustc.edu.cn/dotdeb wheezy-php56 all
deb-src http://mirrors.ustc.edu.cn/dotdeb wheezy-php56 all

如果你想在Debian Wheezy上安装启用Zend Thread Safety的PHP5.6的话,再添加下面这两行:

deb http://mirrors.ustc.edu.cn/dotdeb wheezy-php56-zts all
deb-src http://mirrors.ustc.edu.cn/dotdeb wheezy-php56-zts all

如果你想在Debian Wheezy上安装PHP5.5的话,再添加下面这两行:

deb http://mirrors.ustc.edu.cn/dotdeb wheezy-php55 all
deb-src http://mirrors.ustc.edu.cn/dotdeb wheezy-php55 all

3. 然后导入合适的GnuPG key

wget https://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -

4. 运行

apt-get update

升级php例子:

升级前

一系列操作

401 2017-10-21 09:25:26 echo “deb http://packages.dotdeb.org wheezy-php56 all” >> /etc/apt/sources.list.d/dotdeb.list
402 2017-10-21 09:25:32 echo “deb-src http://packages.dotdeb.org wheezy-php56 all” >> /etc/apt/sources.list.d/dotdeb.list
403 2017-10-21 09:25:39 wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add –
405 2017-10-21 09:26:17 dpkg -l |grep php
413 2017-10-21 09:28:30 for pkg in `dpkg -l |grep php |awk ‘{print $2}’`;do dpkg -P $pkg; done
425 2017-10-21 09:29:28 aptitude update
426 2017-10-21 09:29:46 aptitude install php5-fpm php5-cgi php5-cli php5-curl php5-gd php5-mcrypt php5-mysql php5-memcache php5-xmlrpc php5-dev libapache2-mod-php5

然后看看升级后的版本

未分类

ok升级完成,类似nginx等都可以参考这个方法。

zabbix 创建自定义监控项

1、打开zabbix_agentd.conf中自定义监控项

[root@abcopenstack script]# tailf -10 /usr/local/etc/zabbix_agentd.conf
UnsafeUserParameters=1
Include=/usr/local/etc/zabbix_agentd.userparams.conf #链接自定义监控项的路径

2、创建自定义监控项文件(监控项的名称要有zabbix web界面一致)

未分类

[root@abcopenstack script]# vim /usr/local/etc/zabbix_agentd.userparams.conf
UserParameter=check_link,/bin/bash /usr/local/etc/script/check_link.sh

3、所定义的脚本需要定义为可执行权限

[root@abcopenstack script]# chmod 755 check_link.sh
[root@abcopenstack script]# ll
total 4
-rwxr-xr-x 1 root root 95 Oct 13 14:33 check_link.sh

4、重启zabbix_agentd

5、使用zabbix_get测试自定义的监控项是否能获取数据

[root@abcopenstack script]# zabbix_get -s 127.0.0.1 -p 10050 -k check_link

6、zabbix web 界面添加监控项

6.1 点击监控项

未分类

6.2 创建监控项

未分类

7、定义监控项图像

未分类

8、查看图像

未分类

Zabbix图形中文字体显示方块处理

原因很简单,图形显示用的字体是dejavu,不支持中文。

怎么办?先理清逻辑。

zabbix配置文件(/usr/share/zabbix/include/defines.inc.php)里,定义的字体叫做graphfont.ttf,然后一路软链接到DejaVuSans.ttf,如下:

/usr/share/zabbix/graphfont.ttf -> /etc/alternatives/zabbix-web-font -> /usr/share/fonts/dejavu/DejaVuSans.ttf

那么,修改掉最后一层软连接的目标字体就可以了。执行类似下面的命令就可以了。

yum install google-noto-sans-simplified-chinese-fonts.noarch -y
mv /etc/alternatives/zabbix-web-font /etc/alternatives/zabbix-web-font_bak 
ln -s /usr/share/fonts/google-noto/NotoSansSC-Regular.otf /etc/alternatives/zabbix-web-font

我的环境是Zabbix 3.4和CentOS7,其他版本的,就按照这个思路,修改字体包或者路径即可。

zabbix自动截图留档_python版

一、背景

每个DB Server都有zabbix监控,除了异常情况的报警信息外,也会在日检、周检、月检等工作中用到zabbix的监控数据,对zabbix监控数据会做两种处理:1 数据分析(环比分析、最大值、最小值及平均值分析);2 主要检测项目折线图留档(为啥需要留档呢,因为zabbix监控过多服务器,监控数据仅保留半年到1年间)。

关于 数据分析类的,已嵌入 日检邮件报告跟 月度报告 中,而 zabbix 监控图留档 一直没实现自动化,每个月都是人工取截图。刚好最近遇到 国庆db报告跟9月数据库报告,需要各种截图留档,然后触发了写个小脚本来自动下载 zabbix的监控图。

二、写个小脚本

2.1 获取图片url

首先打开日常的zabbix监控图页面,点击 F12,然后点击,这个时候选中页面中的折线图,就可以看到 对应的HTML代码,最后点击对应的html代码右键 copy下图片的链接地址,即可知道 zabbix的监控图 的url。

未分类

根据获取的url如下:

http://company.moniter.com/chart.php?period=2592000&stime=20170901000000&itemids%5B0%5D=32571&type=0&updateProfile=1&profileIdx=web.item.graph&profileIdx2=32571&width=1778&sid=341eb79599119b85&screenid=&curtime=1508809467171

这里边有几个参数说明下

  • stime 是监控的开始时间按照 ‘%Y%m%d%H%M%S’ 的时间格式

  • period 是监控图的时长,从 stime开始要展示 多少秒 的监控数据

  • itemid[0] 是 监控项目在zabbix 数据库的 itemid 号

    • 这个如何查呢?首先根据 host表格,找到监控服务器的hostid,然后根据 items表格找到对应的监控id

    • select i.hostid,itemid,i.name,key_,i.description from items i join hosts h on i.hostid=h.hostid where h.name = ‘hostname’;

  • curtime这里可以不填写,但是注意 stime 加上 period秒数后,不要超过当前查询时间即可

  • width 为图片的长度

根据需要,仅保留4个参数,这里注意 stime 加上 period秒数后,不要超过当前查询时间 ,简化后的url如下(把zabbix部署的域名或者网址IP替换掉 company.moniter.com):

http://company.moniter.com/chart.php?period=2592000&stime=20170901000000&itemids[0]=32571&width=1778

2.2 脚步及测试

小脚本实现的功能是:根据批量的itemid,自动下载图片到本地目录,并且重命名图片名称。

代码实现如下:

# -*- coding: utf-8 -*-
__author__ = 'xinysu'
__date__ = '2017/10/12 14:38'
import sys
import datetime
import http.cookiejar, urllib.request, urllib
from lxml import etree
import requests
class ZabbixChart(object):
    def __init__(self, name, password):
        url="http://company.monitor.com/index.php";
        self.url = url
        self.name = name
        self.password = password
        cookiejar = http.cookiejar.CookieJar()
        urlOpener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar))
        values = {"name": self.name, 'password': self.password, 'autologin': 1, "enter": 'Sign in'}
        data = urllib.parse.urlencode(values).encode(encoding='UTF8')
        request = urllib.request.Request(url, data)
        try:
            urlOpener.open(request, timeout=10)
            self.urlOpener = urlOpener
        except urllib.request.HTTPError as e:
            print(e)
    def download_chart(self, image_dir,itemids,stime,etime):
        # 此url是获取图片是的,请注意饼图的URL 和此URL不一样,请仔细观察!
        url="http://company.monitor.com/chart.php";
        # 折线图的大小
        url_par={}
        url_par={"width":1778, "height":300,"itemids":itemids}
        # 开始日期、结束日期从str转换为datetime
        stime = datetime.datetime.strptime(stime, "%Y-%m-%d")
        etime=datetime.datetime.strptime(etime, "%Y-%m-%d")
        # 计算period
        diff_sec = etime - stime
        period = diff_sec.days*24*3600 + diff_sec.seconds
        url_par["period"] = period
        # stime转换str
        stime = stime.strftime('%Y%m%d%H%M%S')
        url_par["stime"] = stime
        key = url_par.keys()
        data = urllib.parse.urlencode(url_par).encode(encoding='UTF8')
        request = urllib.request.Request(url, data)
        url = self.urlOpener.open(request)
        image = url.read()
        html = requests.get('http://company.monitor.com/history.php?action=showgraph&itemids[]={}'.format(itemids)).text
        page = etree.HTML(html)
        hostname_itemname = page.xpath('//div[@class="header-title"]/h1/text()')[0].split(':')
        hostname = hostname_itemname[0]
        hostname_itemname.pop(0)
        itemname = '_'.join(hostname_itemname).replace('/','_')
        imagename = "{}{}_{}_{}_({}).png".format(image_dir,hostname,stime,etime.strftime('%Y%m%d%H%M%S'),itemname)
        f = open(imagename, 'wb')
        f.write(image)

根据写好的类,输入zabbix的登录帐号、监控图的起始跟结束时间、本地存放图片目录、itemid的list,运行后如下:

# 登陆URL
username = "xinysu"
password = "passwd"

# 图片的参数,该字典至少传入graphid
stime = "2017-09-01"
etime = "2017-10-01"

# 用于图片存放的目录
image_dir = "E:\03 WORK\03 work_sql\201709"

#运行
b = ZabbixChart(username, password)
item_list =(35295,35328,38080,37992,38102,38014,35059,35022,42765,35024,35028,35035,35036,35044,35045,35046,35047,38248,36369,36370,36371,36372)
for i in item_list:
    itemids = i
    b.download_chart(image_dir,itemids,stime,etime)

随便输入的itemid 测试下载,实际需要根据监控需要过滤itemid,下载后在文件夹中显示如下:

未分类

未分类

Zabbix 3.2.6 自定义端口监控(Oracle)

一、背景

在现实的环境中,我们多多少少有些服务需要监控,但是zabbix自带的监控模板不存在,就需要我们自己进行配置,我们的主要方法也是监控这些服务的端口状态来确定服务是否正常运行。

我们今天主要通过判断Oracle的端口状态来监控服务是否正常,它的端口是1521。

二、配置

1、模板创建

为了简化操作,我们这里直接创建模板,不必每台机器单独去创建item以及trigger。

未分类

2、创建item

未分类

3、创建trigger

未分类

4、图标制作

有兴趣的可以制作一下图表,因为我没有兴趣,我这里就不写了。

5、给主机添加模板

这一步我也不再展示了,添加模板大家都会了。

三、验证

因为我的Action是默认的,只要出问题就会报警,这里不再展示,可以查看我其他的博文,我们停掉或者恢复数据库的监听端口,查看报警信息。

我这里是微信报警,关于微信报警的设置可以去查看我相关的博文。

未分类

Zabbix(5)通过JMX监控Tomcat

Zabbix监控tomcat主要使用的是zabbix的zabbix-java-gateway。从Zabbix 2.0开始,内置了监控JMX的功能,叫做“Zabbix Java Gateway”,在Zabbix Server和Zabbix Proxy上启动名为“Zabbix Java Gateway”的进程,当需要获取JMX数据时,Zabbix Server会“问”JMX Gateway,然后JMX Gateway根据JMX管理API去查询需要的数据。在使用时,Java程序不需要在代码中新增任何东西,只需要在启动的时候加上一些JVM参数,使得它可以支持使用端口监控JMX。JMX的全称是Java Management Extensions,即Java管理扩展。Java程序会开放一些端口,用来获取运行状况。

一、安装jmx服务器

1、安装jdk

下载JDK: http://www.oracle.com/technetwork/java/archive-139210.html

配置环境变量: http://islocal.cc/2017/09/27/JDK%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E9%85%8D%E7%BD%AE/

2、安装jmx服务

yum -y install zabbix-java-gateway

3、配置jmx服务

egrep -v '#|^$' /etc/zabbix/zabbix_java_gateway.conf
LISTEN_IP="0.0.0.0"
LISTEN_PORT=10052
PID_FILE="/var/run/zabbix/zabbix_java.pid"
START_POLLERS=5
TIMEOUT=3
systemctl start zabbix-java-gateway
systemctl enable zabbix-java-gateway

4、修改zabbix server配置

添加以下三行,这里配置的StartJavaPollers值要小于之前java_gateway中的START_POLLERS

tail -n 3 /etc/zabbix/zabbix_server.conf 
JavaGateway=127.0.0.1
JavaGatewayPort=10052     
StartJavaPollers=3

修改zabbix_server.conf后重启服务

systemctl restart zabbix-server

二、Tomcat配置修改

1、修改配置文件

Windows下tomcat在F:deployapache-tomcat-8.5.20-OUbincatalina.bat中set “CURRENT_DIR=%cd%”下添加以下内容

set CATALINA_OPTS=-Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

2、测试JMX

下载以下两个jar包放在tomcat lib目录下。

下载cmdline-jmxclient-0.10.3.jar

http://crawler.archive.org/cmdline-jmxclient/cmdline-jmxclient-0.10.3.jar

下载catalina-jmx-remote.jar

https://archive.apache.org/dist/tomcat/tomcat-7/v7.0.77/bin/extras/catalina-jmx-remote.jar

F:apache-tomcat-7.0.70(zabbix)lib>java -jar cmdline-jmxclient-0.10.3.jar - 192.168.6.124:12345 java.lang:type=Memory NonHeapMemoryUsage
10/10/2017 16:31:57 +0800 org.archive.jmx.Client NonHeapMemoryUsage:
committed: 24838144
init: 12746752
max: 100663296
used: 24806392

三、在zabbix web页面中添加JMX端口

1、导入模板

zabbix自带的”Template App Generic Java JMX”和”Template App Apache Tomcat JMX”模板很多都获取不到数据,从网上找了个模板,监控项不多,但是都是很实用的。

未分类

未分类

2、添加JMX端口

jmx的端口一定要与在catalina.bat下配置的jmxremote.port一样

未分类

3、关联模板

未分类

4、查看图形

未分类