欢乐颂

欢乐女神圣洁美丽
灿烂光芒照大地!
我们心中充满热情
来到你的圣殿里!
你的力量能使人们
消除一切分歧,
在你光辉照耀下面
四海之内皆成兄弟。

清明无锡游记录

记一下,否则就忘记了。

清明后一天,坐火车去无锡。

上次去无锡还是一九九零年,那个时候有可能成为一个无锡人,造化弄人,擦肩而过。

中午到无锡,先地铁到清名桥,吃了午饭,在一家中规中矩的餐馆,有烤鸭,有萝卜干,都很可口,还便宜。

下午去无锡博物馆。东区几层楼的动手区很棒,小朋友可以亲自动手玩玩,了解环境、地理、物理、人体构造……总的来说比上海自然博物馆好。

还去4D影院看了《羽龙》动画片,所谓的4D是会有喷雾,椅子也会配合场景动一动,感觉有人在后面踢你。小孩子还是可能害怕。总的来说寓教于乐,十几分钟也不拖沓,另外免费的,值得。

西区就是人文区了。有一个沙盘,清朝街景,有各种店铺,各种人物走在路上,还有人在运河边洗衣服,淘米。主街上有一队人阵仗很大的摆过来,队前还有华盖,估计是皇上南巡吧。

晚上和网友路人甲在一起吃饭,在座的还有她已经十几岁的女儿。我和女孩儿谈得倒是投机,网友啊,手机啊,情商不高的男生啊,王者荣耀啊,什么都还可以谈。临分别,还给女孩儿出了个小帖士,去读傅雷的《世界美术二十讲》,一班主任是美术老师,二是班主任建议不要读活人的书,也算是有的放矢,投其所好。

饭后路人甲还给安排了运河游船活动,短短一段运河之旅,我想到了杭州武林门到拱宸桥段的运河水上巴士。同样的运河,不同样的风物。下船后我们又在南长街上逛回住处。街上有小摊也有食肆,简直是河坊街和高银街的合体。有趣的一个事情,公共厕所的男女比重失调,男厕有时会划归女厕,门口有社区阿姨把守。

第二天早饭时候听隔壁桌在说鼋头渚的花已经被前两天的雨水打光了,交通又不方便,我们就放弃了去那的念头。叫了一辆滴滴快车我们就到了惠山古镇。那里有三个景点是连在一起的,寄畅园、天下第二泉和惠山寺。我们跟卖门票的说我们只去寄畅园,人家说里面是通的,要去就一起去。好吧,一起一起。

寄畅园又叫秦园,占地十五亩,好大。里面有各种假山乱石,还有亭台楼阁。别的不说,墙上的书刻就一定花了很多人力物力。我看着那些好看的行书草书,真是喜欢得不得了。当然,我已经不会天真地以为这些是这里原创的了,在杭州的胡雪岩故居我还震惊的发现苏东坡的寒食帖。

天下第二泉的泉眼已经变成了许愿池,满满的铺了一层硬币。纪念品商店的老板对好奇的游客讲述着瞎子阿炳的故事。里面还有一个小院子,据说在颐和园里有一个园子就是照搬这个的,里面有不少乾隆皇帝的御书。

还有朝房。看来惠山真是好地方,康乾二帝六次巡幸到此。文武百官在这里也就有了落脚的朝房。

下午回到南禅寺一带,吃了穆桂英美食,在茶叶一条街上逛一路,又到三凤桥买了面筋塞肉和排骨。走累了就在那边坐下,晚上吃了饭就火车回家了。

美好的无锡之行,感谢天气,感谢路人甲。下次还要再来,要去鼋头渚,要去拈花湾,想想应该会多住两天吧。

作为一个经验丰富的团队怎么办?

最近听到一个讲演,其中有一个部分讲到如果团队年纪大了该怎样发展下去,现在我记录一下。

经常有人问我们和H有什么区别,对吧?我们跟W团队有什么区别?我来讲讲我的看法。首先啊就是说,我们不再是一个年轻的团队。假设我们去跟W比,和H比,据说我们的平均年龄已经超过他们八岁九岁十岁。我们也有比较资深的,也有比较年轻的。从平均年龄来说我们已经超过八岁以上,到底是八岁九岁还是十岁我们不知道,估计差不多就是这个级别。我们和他们比的时候,我们不说把自己说成一个老年人团队,我们说我们是一个经验丰富的团队。而且我们是要往这个方向去的。

假设我们和H有合作的竞争,我们和W有合作的竞争,这种竞争就是我们要和他们的做法要不一样的。就是说我们不再和他们拼低成本。中国已经不是低成本了,上海已经不是低成本了。上海、北京已经不是低成本地方了。就是说,上海和北京能开公司的,就是有一定实力才能开得出来的。你看看上海的房价,对吧?各种成本。而且中央政府和上海政府把上海定义成金融方面发展的,亚洲金融中心。金融中心就是玩钱的,玩钱必然成本高。我们已经不是低成本的国家了,也不是低成本的site了。我记得刚开始我们和法国人做,他们说我们的成本是法国人的五分之一,六分之一。那现在我们是法国人成本的二分之一,到二分之一这种差别呢在成本上面很多时候会忽略掉,就是说很多时候做决策的时候我不再以成本作为一个很好的参考点。往往现在W的成本是我们的二分之一。他们的人力成本是极具优势的。所以说我们还听到说W的团队还在增长,这很正常的,因为他们还在吃人口红利。中国的红利在过去的二十年吃完了。

上海北京成为高成本的城市,同时呢刚才说从年龄结构来说我们又比他们年长。所以我们的路和他们走的路是不一样的。年轻团队,我指的是平均,他们年轻团队是可以犯错误,因为他们犯错误是可以用时间来解决。那对于我们年长团队和经验比较丰富的团队来说,我们要走的那条路是尽量避免犯错误,一次做对。我们不能去跟他们走一样的路。他们可以犯错误然后用加班十六个小时来解决这个问题。我们不能走这条路。我们要做的是让自己成为一个稳定的团队。

这个“稳定”指的是我们deliver出去的feature质量是非常高的,然后我们在处理项目的时候是很少犯错误甚至是不犯错误的。这样呢我们从单位时间工作效率来说我们要做得极高。有时候谈效率的时候别忘了是一种“伪效率”。什么叫伪效率呢?你一天工作十六个小时出来的一些东西和一天八小时出来的东西是不一样的。这个时候你如果论天谈效率这是不对的。因为有的团队他可以长时间地一天干十几个小时,我指的是平均。但是我们不是这种情况。对于我们来说,我们后面走的那条路是让自己成为一个技术能力稳定,deliver效率稳定。所以我们做事情的时候要以稳定、稳健输出的一个模式去做。这里面大家要正确理解哦,稳定不是慢。

稳定不是慢,而是说一次做对。这非常关键,这跟以前的时候那个项目理念是一样的。就是说一次做对,即便稍微做得慢,效率是最高的。这个就扯得远一点了,这和我们年龄结构也有点关系。我们都有孩子上小学了,也有上初中的。你做作业做错了,第二天订正还是要花很多时间。一次做对嘛,时间全省了嘛,一个道理。我不是说不许大家犯错误,而是说尽量的少犯错误。这样稳定的输出叫我们效率都很高。这个效率和输出不是建立在时间,不能建立在时间,比如我投多少时间进去,而是说我不犯错误,或者少犯错误,让我们的输出是非常稳定的,输出效率非常高。

我希望,这是对我们很高的要求。我们平时的持续的集成,deliver的时候,非常的认真仔细,符合流程,每个checkpoint,我们进一步完善DOD的过程。这是一连串的动作,稳定高效的输出是一连串的动作,稳定不是慢哦,稳定最终的结果是快。

我们要在这个环境里面,生存也好,竞争也好,发展得更好也好,我们要跟别人走的路是不一样的。我们的参考团队是德国。德国这个研发中心,当然我们还没有老到他们的程度,他们好像平均五十多了。但是这个是他们已经走过了一条路嘛,我们去看他们,他们的表现。德国人,其实,每次你跟他说快快快,他会快吗?不快的。但是他给你一个是一个,给你一个是一个。就是往这个方向去。我可能在commit的时候我不会非常激进,但是我一旦commit我很好的做到,质量非常高,效率非常高。我不是说用我先说行,然后用大量的加班去做到,不是,不是这条路。我们走的不是这条路,我们要往德国那一套发展。我们的能力是要持续提升的,每个人。技术能力,管理能力,各方面,团队沟通。然后呢,我们的输出是很稳定的。

我们有时候有些bug什么,哎呀,这个地方不小心。这个要避免。有些是技术能力,或是太复杂,有些scenario我想不到,这有的,很正常。因为现场太复杂了,我在设计的时候就是想不到的。我只有出去吃了亏,回来,哦,知道了,这地方要补一个。那这种呢叫持续学习。另一个呢,这个地方少写一个,哎呀,我失误了,这种是要避免掉的。这种在我们的工作中还是有的,不是很多,还是有的。我们要去避免这种失误或者错误。比如说不小心引起的,不在意引起的,这个呢,你说大了跟职业化有关,跟态度有关,但是这里边太复杂了我们不去说了。我们给出去的deliver,不管是feature还是bugfix的deliver,是稳定的,而且是高效的。尽量少犯错误,甚至不犯错误。这是我们要走的一条路,而且呢,我们自己个人能力团队能力要持续提升。我们要合理的安排自己的工作时间,我们要通过学习,互相学习,各种sharing,lesson learned,各种模式让自己团队不断提升,这是符合我们团队特性的一条路。

结合城市成本,结合年龄特征,稳定输出,是我们要走的一条路。

卡桑德拉

公司的希腊同事开发了一套小系统,用来预测代码出错的几率,取名叫卡桑德拉(Cassandra)。我有点觉得不吉利,毕竟她说实话,但是由于阿波罗的关系,世人都不相信她。

维基百科的词条是这里。稍微摘录一下词条。

出身背景

卡珊德拉别名为亚历珊德拉(Alexandra)。荷马(Homer)史诗《伊利亚特》(Iliad)说她美似金色的阿佛洛狄忒(Aphrodite),是特洛伊国王普里阿摩斯(Priam)最美丽的女儿,[1]是王后赫卡柏(Hecuba)的第三个女儿。欧里庇德斯(Euripides)的《特洛伊妇女》(The Trojan women)说她是阿波罗(Apollo)的祭司。[2]

预言能力

荷马诗注释家引传说卡珊德拉与赫勒诺斯(Helenus)为双生。其家在阿波罗‧提漠布里俄斯(Thymbraean)神庙祭祀庆祝,家人沾醉径去,将卡珊德拉与赫勒诺斯留在神庙。家人次日清醒,始至神庙寻找,见有神蛇以舌为二子洗耳,遂大惊叫,蛇潜入桂树枝间不见,卡珊德拉与赫勒诺斯遂得以预见未来。[3]

预言能力来源另一种说法为阿波罗的赐予。

神明诅咒

阿波罗诅咒卡珊德拉的理由,古希腊、罗马著作中有不同说法:

1.卡珊德拉在阿波罗神庙玩耍,玩累便睡着了。阿波罗试图拥抱卡珊德拉却遭到反抗,遂使她的预言不被相信,见于许癸努斯(Hyginus)的《神话指南》(Fabulae)。[4]

2.阿波罗多洛斯(Apollodorus)《书库》(The library)提及“阿波隆(阿波罗其它译名)想要与卡珊德拉交会,应许教给她占卜术,她学会了,可是不和他交会,于是阿波隆夺去了她占卜的使人信用的力量。”(周作人译)[5]

3.埃斯库罗斯阿伽门农》,依照罗念生译本,卡珊德拉允诺委身阿波罗却又使他失望,此后再也没有人相信她。[6]但在其他译本,“他是个摔角手,恩情往我身上喷。”(吕健忠译)“他将我扭抱,把我摔倒,吐喘甜蜜的欲火”(陈中梅译)[7]“他与我扭斗,同时他兴奋喘息。”(刘毓秀译)[8]似曾有肌肤之亲,后文提及决裂的原因是因为卡珊德拉承诺要为他生下子嗣却出言不果。中研院研究员李奭学先生〈长夜后的黎明--试论《奥勒斯提亚》的一则主题故事〉一文以圣婚概念解释剧中阿波罗与卡珊德拉间的纠葛。[9]

在劫难逃

王后赫卡柏怀帕里斯(Paris)时,梦见特洛伊陷于火海,普里阿摩斯与前妻之子埃萨科斯(Aesacus)释梦,预言帕里斯将导致特洛伊的覆灭。帕里斯遂被弃于伊达山,幸得牧人将之抚养成人。许癸努斯神话指南》描述帕里斯钟爱的一头牛被带走作为一场葬礼上的竞技的奖励品,帕里斯为夺回这头牛参与了竞技,赢得一切,甚至战胜自己的兄弟,得伊福彼斯(Deiphobus)发怒并袭击他,帕里斯窜至宙斯神坛,卡珊德拉预言宣称帕里斯是她的弟弟,普里阿摩斯认出他,帕里斯遂回归。

不和女神

忒提斯(Thetis)与珀琉斯(Peleus)的婚礼,未邀约不和女神厄里斯(Eris),厄里斯遂在婚礼上投下一颗金苹果,说给最美丽的,阿佛洛狄忒赫拉(Hera)与雅典娜(Athena)争夺金苹果,宙斯命赫尔墨斯(Hermes)带她们前往伊达山请帕里斯裁决,三名女神各允给以报酬,帕里斯最终将金苹果判给阿佛洛狄忒,因为阿佛洛狄忒承诺赐予他最美丽的女人,亦即海伦(Helen)。

祸国红颜

奥维德(Ovid)的《女英雄书信集》(Heroides)描述帕里斯远航至希腊之前,卡珊德拉预言这场航行将会带来大火。[10]达瑞斯•佛里癸俄斯(Dares Phrygius)的《特洛伊的沦陷》(The Fall of Troy)描述当卡珊德拉见到海伦时,她开始预言曾说过的收容海伦的恶果,直至普里阿摩斯下令将她带走并囚禁。[11]

十年鏖战

荷马伊利亚特》说俄斯鲁俄纽斯(Othruoneus)想娶卡珊德拉为妻而参战,后死于伊多墨纽斯(Idomeneus)之手;狄克提斯(Dictys Cretensis)说欧律皮罗斯(Eurypylus)是名杰出的战士,普里阿摩斯曾用很多礼物拉拢他,最后通过承诺让卡珊德拉与他联姻而赢得他的支持。荷马奥德赛》(Odyssey)中欧律皮罗斯死于涅俄普托勒摩斯(Neoptolemus)之手,奥德修斯(Odysseus)说欧律皮罗斯骁莽,是自己见过的最英俊的男子,仅次于卓著的门农(Memnon);[12]维吉尔(Virgil)《埃涅阿斯纪》(Aeneid)说科罗厄布斯(Coroebus)因为疯狂热烈地爱上卡珊德拉,作为普里阿摩斯未来的女婿,率领军队来支援特洛伊[13]

干城之死

荷马伊利亚特》中,普里阿摩斯赎回赫克托尔(Hector)尸体时,卡珊德拉站在城墙上,首先看见父亲还有兄长,呼唤特洛伊的男女迎接赫克托尔

木马屠城

希腊人十年鏖战,始终未能攻下特洛伊奥德修斯遂献策木马计。卡珊德拉与拉奥孔(Laocoon)都说木马内有一支军队,但他们的警告不被特洛伊人接受。

国破家亡

按照风俗,神庙不可被冒犯,木马屠城时特洛伊王室女性多藏匿于神坛。卡珊德拉藏身雅典娜神庙,她的遭遇有不同说法:阿波罗多洛斯书库》提及小埃阿斯把她强污,雅典娜的木像仰望着天;欧里庇得斯特洛伊妇女》则写小埃阿斯将她强行拉出神庙,并提及卡珊德拉仍为清白之躯。维吉尔埃涅阿斯纪》说科罗厄布斯为了营救卡珊德拉被佩涅勒乌斯杀死在雅典娜的神坛前。

希腊人分配战利品之后,昆图斯(Quintus SMYRNAEUS)《续荷马史诗》(Posthomerica)描述特洛伊妇女惊叹地看着卡珊德拉,忆及她关于毁灭的预言;但是面对她们的眼泪,卡珊德拉唯有充满怨恨的嘲笑,带着对故土毁灭的悲痛。[14]欧里庇得斯特洛伊妇女》当中,卡珊德拉提及只要洛克西阿斯阿波罗的别名)在,阿伽门农娶了她将比海伦的婚姻对他更有害,以隐晦的语言说这场婚姻将引起杀母之斗与阿特柔斯(Atreus)家族的衰败,并预述赫卡柏奥德修斯的结局。卡珊德拉为阿伽门农所得,奥维德爱经》(Ars Amatoria)说阿伽门农做了他俘虏的俘虏,[15]欧里庇得斯赫卡柏》歌唱队提及阿伽门农因卡珊德拉试图保全波吕克塞娜(Polyxena)的性命。[16]

赴死如归

阿伽门农之妻克吕泰涅斯特拉恨丈夫为求顺风献祭他们的女儿伊菲革涅亚(Iphigeneia),伙同情夫埃癸斯托斯(Aegisthus)密谋要杀害阿伽门农,卡珊德拉预见阿伽门农与自己至迈锡尼后必遭不测,隐忍不言。荷马奥德赛》提及她与阿伽门农在王宫的大厅中同时遇害;埃斯库罗斯阿伽门农》一剧,阿伽门农克吕泰涅斯特拉入内沐浴,卡珊德拉单独留在屋外,追述过往(包括帕里斯带来死亡的婚礼、特洛伊的覆灭还有阿特柔斯家族的罪孽),并预言阿伽门农与自己的死还有复仇者的复仇,最后请求歌唱队在自己死后见证复仇者的复仇,自己的话必不落空;塞涅加(Seneca)的《阿伽门农》以卡珊德拉与克吕泰涅斯特拉的对话完结:[17]

还有一本10 1/2章世界史 也提起了卡桑德拉,还有那个译制片卡桑德拉大桥

2017年效率工具回顾

(一)整个2017年我都在用一本无印良品的月周历本,A6的。

原本以为A6的太小了,写不了多少字。后来发现大小正正好。

每天提纲携领的写几条,足够到年底做回顾的。

上一篇我的2017流水帐就完全是根据这个本子上记录的东西整理出来的。

2018年,我买了一本B6的,红封面的。想保持自己记录生活的好习惯。

(二)在工作上,我多多的使用了Trello这个工具。

这个看板工具可以跟踪手头的事情,也可以整理信息。

2017下半年以后我基本在实践一种给每周建立一个列表,

每天建一个卡片的工作流。

每个卡片里又针对“工作”和“在家”建立了清单。

我觉得这样可以大大的减轻用脑记录琐碎事的负担,也算是对大脑的一种解放。

Trello又是全平台的,在安卓和iOS上都有App,可以随时用起来。

2018年我会继续实践这种看板工作流。

(三)在头脑风暴方面,我还是喜欢在电脑上用XMind来画脑图。

手机上做脑图毕竟不方便。

画流程图我大大的使用了YED这个工具。德国人写的,很方便,还免费。

做笔记我用了为知笔记。已经给了钱,买了会员。

没有在线笔记本,感觉记不住那许多东西了。

(四)最后,最好的效率工具永远是纸笔。多写,多记,多画。

2017流水账

  • 一月
    • 在元旦的锐豪杯围棋赛中,Juha七盘五胜,成功晋级一级。
    • 迪卡侬弄了一台椭圆机,要锻炼身体啦。
    • 同事彬彬离职。
    • 爸妈红宝石婚家宴。
    • Stefan Rink到杭州来传道,说服中国这边用puppet配置测试环境。
    • 春节,大年初一去看了电影《大话天竺》,妈在电影院里睡着了。
    • 到大悦城坐摩天轮。来家过年的亲戚去东海大桥。
  • 二月
    • 跑了几次医院。
    • 买了一块2T的硬盘。
    • 按照往年惯例给江妹下载超级碗录像。
    • 小学开学。
    • 买了两本书,《笔记术》和《数据术》,都是日本人写的。
    • 同事给我留下的月流量5G的联通卡失效,买了一元一天五百兆流量卡。
    • 办公室换座位,新座位0712A,打印机边过道处。
  • 三月
    • 115上续费一个月。
    • 飘鹰健身卡到期,练习最后一次。
    • Juha拍照,申领新一期身份证。
    • 同学移民澳洲,告别宴。大雨,在中山公园附近日本料理。
  • 四月
    • 为了方便,买了一台佳能的打印机,喷墨的。
    • puppet的事情还是落在我头上,之前我只玩过玩具,这真的要进入生产环境了。
    • Juha参加小应氏杯,胜一场。
    • 肇嘉浜路医院边上谈了一次。
    • 115又续费一个月。
    • 秋霞带孩子们来上海。姐妹团聚。
    • Juha摔跤,休息三周。
  • 五月
    • 继续用puppet配置环境,已经可以规模化了。
    • Juha新身份证拿到。
    • 开始晚上在办公室加班生活,很晚才回住处。
    • 还掉居委会的轮椅,使用费20快,日均一元。
    • 出差到上海部门帮搭建puppet,一周时间。
    • 杭州Team Building,去汗蒸,吃两顿。很爽。
    • 百度会员买了个季卡,72块。
  • 六月
    • 配了新眼镜。
    • “无支持”会议。
    • 到杭州城里转一圈。
    • 去了一次海洋馆,家庭卡就到期了。
    • 开始玩ELK,想在开发环境中起作用。
    • 月底决定了转到上海的部门。
  • 七月
    • 暑假开始。
    • 佘山、朱家角游玩。
    • 衢州探亲。周末游览水亭街。
    • 杭州旅游四天。
    • 持续优化AutoHotKey脚本。
    • 出差在上海,为正式转移做准备。
  • 八月
    • 北京旅游一周,住前门富力。
    • 长城、故宫、牛街、德云社、天坛、北海;见小舅。
    • 在电脑上装luajit,现在已经想不起来缘由了。
    • 34周开始在上海工作。
    • 上海puppet重新部署。
  • 九月
    • 见青岛同事,问黄岛事。
    • 参加为期四天的Java培训。
    • 老付到上海传经一周。可以学习的东西很多很多。
  • 十月
    • 衢州三个孩子到上海过假期。
    • 115又续费一个月。
    • 参观自然博物馆。
    • 树莓派上机器人重新部署起来。
    • SCM向Git迁移启动会。
    • 新部门,新领导。
    • 为老付的项目做贡献,写Keyword,要写成递归的。
    • 男人四十。
  • 十一月
    • 到江湾体育场看三对三篮球赛。看见活的邱峻。
    • Juha封窝沟。
    • Juha学会骑自行车。
    • 为知笔记续费,买一送一。
    • 给家里装上监控。
    • Team Building,滨江森林公园烧烤,半天。看见了黄浦江和长江交界的地方。
    • 在大学参加git的培训,半天。觉得讲得一般,但是事后发现能讲好很难。
    • 见吕丰一家。
    • 修理iPhone 5S。没几天屏幕又碎了。
    • 看电影Coco,曲阳电影院。
  • 十二月
    • Juha开始篮球训练。
    • 着手解决netboot问题。
    • 周末到柚子的工作室玩一个。
    • 到天潼路吃好吃的东北菜。
    • 给部门做教室内的git培训,失败。需要总结的点有很多很多。
    • 和同学见面,交流软件开发流程。
    • 小超和Juha过生日。
    • 到杭州一天,和饭团吃饭;办公室里问问题。
    • 同学回沪,聚会吃饭唱K。

Git 基础培训

12月14日的时候在部门内组织了一次Git的基础培训,效果不太好。

对于效果为什么不好,我觉得有一些原因。

  • PowerPoint的演示我用得太少。我借了一个投影仪,用了复制模式。按理说我笔记本的屏幕应该和幕布应该显示同样的内容,但是,PowerPoint在播放的时候在笔记本上显示的演讲者模式,幕布上就用不一样的分辨率显示观众内容。这个是我始料未及的。由于分辨率的改变导致观众内容非常模糊,所以在前半部分根本在和银幕做斗争。后来,我干脆不播放PPT,直接在Bash窗口里打我的命令,效果反而好些。
  • 准备的东西有点儿多,进程也编排得有点花哨。忽略了受众是常年用SVN,对分布式版本控制完全没有概念的。解释起来有一定的难度。应该拆成两个培训,可能效果会好一些。
  • 下次如果有机会再做这类的培训,我会选择Jupyter Notebook来做演示;或者写扁平风格的PPT来做,不要动画效果,朴实一些。

我准备的材料差不多是下面的这些。

0

Centralized VCS: designed with the intent that there is One True Source that is Blessed, and therefore Good.

Distributed VCS: systems are designed with the intent that one repository is as good as any other.

1 Git

Since 2005 created by Linus Torvalds

Installations

Linux: apt-get install git
Windows: Git for Windows(Git Bash)/TortoiseGit/SourceTree

Basic configurations

git config –global user.name “Your name”
git config –global user.email foo@bar.com
git config –global color.ui true

Commands

Basic Commands

  • init
  • add
  • commit
  • status
  • log
  • diff
  • show
  • mv
  • rm
  • reset

Branch Related Commands

  • branch
  • checkout
  • merge
  • rebase

Collaborating Commands

  • clone
  • fetch
  • push
  • pull

2 Basic Workflow

Like SVN

  • git init
  • git status
  • git add
  • git commit
  • git log
  • git diff
  • git tag

Branching

  • git branch
  • git checkout –b xxx
  • git merge xxx

Stashing

  • git stash
  • git stash apply
  • git stash pop
  • git stash drop
  • git stash list

3 Collaborating with Other Colleagues

GitLab or GitHub

Creating Repositories

Cloning others’ Repository

Collaborating Commands

4 Other Tips

I am so sorry that I have done these…

  • git checkout — files
  • git reset –hard/–soft

I can ignore the conflicts, using mine…

  • git checkout –ours/–theirs

I need one node, instead of whole branch

  • git cherry-pick

What have I done in this repo?

  • git reflog

Comprehensive logs

  • git log v2.5.. # commits since (not reachable from) v2.5
  • git log test..master # commits reachable from master but not test
  • git log master..test # commits reachable from test but not master
  • git log master…test # commits reachable from either test or master, but not both
  • git log –since=”2 weeks ago” # commits from the last 2 weeks
  • git log Makefile # commits that modify Makefile
  • git log –no-merges # dont show merge commit

Python 的 with 语句(2)

我们经常既想利用with语句的便利,又不想很麻烦的写一个类来实现__enter__() 和 __exit__()方法,有什么比较现成的办法呢?

Python的标准库里引入了contextlib 模块可以解决这个问题。contextlib 模块提供了装饰器contextmanager,使用这个,可以对已有的生成器函数或者对象进行包装,加入对上下文管理协议的支持,避免了专门编写上下文管理器来支持 with 语句。

contextmanager 用于对生成器函数进行装饰,生成器函数被装饰以后,返回的是一个上下文管理器,其 enter() 和 exit() 方法由 contextmanager 负责提供。被装饰的生成器函数只能产生一个值,否则会导致异常 RuntimeError,产生的值会赋值给 as 子句中的 target,如果使用了 as 子句的话。

from contextlib import contextmanager

@contextmanager
def demo():
    print '[Allocate resources]'
    print 'Code before yield-statement executes in __enter__'
    yield '*** contextmanager demo ***'
    print 'Code after yield-statement executes in __exit__'
    print '[Free resources]'

with demo() as value:
    print 'Assigned Value: %s' % value

例子的执行结果是:

[Allocate resources]
Code before yield-statement executes in __enter__
Assigned Value: *** contextmanager demo ***
Code after yield-statement executes in __exit__
[Free resources]

可以看到,生成器函数中 yield 之前的语句在 __enter__() 方法中执行,yield 之后的语句在 __exit__() 中执行,而 yield 产生的值赋给了 as 子句中的 value 变量。

需要注意的是,contextmanager 只是省略了 __enter__() / __exit__() 的编写,但并不负责实现资源的“获取”和“清理”工作;“获取”操作需要定义在 yield 语句之前,“清理”操作需要定义 yield 语句之后,这样 with 语句在执行 __enter__() / __exit__() 方法时会执行这些语句以获取/释放资源,即生成器函数中需要实现必要的逻辑控制,包括资源访问出现错误时抛出适当的异常。

贴一下contextmanager的实现。用的时候就当成一个修饰器(decorator)来用。

def contextmanager(func):
    """@contextmanager decorator.

    Typical usage:

        @contextmanager
        def some_generator(<arguments>):
            <setup>
            try:
                yield <value>
            finally:
                <cleanup>

    This makes this:

        with some_generator(<arguments>) as <variable>:
            <body>

    equivalent to this:

        <setup>
        try:
            <variable> = <value>
            <body>
        finally:
            <cleanup>

    """
    @wraps(func)
    def helper(*args, **kwds):
        return GeneratorContextManager(func(*args, **kwds))
    return helper

另外说一句。with 语句的管理上下文的能力在python中往往被定义成设计模式的一种。下面就是一个例子。其实就是实现上下文管理协议,但是名字叫ResourceAcquisitionIsInitialization(资源获取初始化)。只贴代码,不另外做解释了。

class Box(object):
    
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print("Box " + self.name + " Opened")
        return self

    def __exit__(self, exception_type, exception, traceback):
        all_none = all(
            arg is None for arg in [exception_type, exception, traceback]
            )
        if (not all_none):
            print("Exception: \"%s\" raised." %(str(exception)))
        print("Box Closed")
        print("")
        return all_none

#===============================================================
if (__name__ == "__main__"):
    with Box("tupperware") as simple_box:
        print("Nothing in " + simple_box.name)
    with Box("Pandora's") as pandoras_box:
        raise Exception("All the evils in the world")
    print("end")

-EOF-

Python 的 with 语句(1)

参考了 浅谈 Python 的 with 语句

最近组里在CoDe(Competence Development,能力培养)。花姐讲文件操作,例子里有如下的代码:

with open(r'demo.txt') as f:
    for line in f:
        print line
        # ...more code

语句很简单,就是把demo.txt文件打开,逐行打印出来。我感兴趣的是这里的with语句,这个用法很简洁,比下面的try … except 用法要少一些代码量。

f = open(r'demo.txt')
try:
    for line in f:
        print line
        # ...more code
finally:
    f.close()

可以看到,下面的这种用法代码稍微复杂一些,还涉及到了文件的关闭操作。而with语句是怎么避免了显性的关闭文件呢?更进一步,with这个语句是怎么实现的,它的目的和好处是什么呢?

对比着看,可以感觉到with做了一系列的操作,准备工作、用户代码、扫尾工作。准备工作就是打开文件并且返回文件句柄(是不是这么定义?),用户代码就是中间那一部分逐行打印。扫尾工作就是关闭文件。

再做一个类比。在用robotframework做自动化测试时,总会定义 suite setup 和 suite teardown,这就是保证测试的进入和退出都有一定的保护措施,进入时做准备,退出时打扫战场。Python 的 with 语句就是suite setup 和 suite teardown的作用,是Python 2.5以后引入的特性。

在Python 2.5里要通过

from __future__ import with_statement

才能使用with 语句,到了Python 2.6就可以直接用了,它从一个实验性的特性变成了内置的了。

直接了当说,with的原理是实现了一个上下文管理协议(Context Management Protocol),而这个协议的两个必要部分就是两个方法,__enter__() 和 __exit__(),任何支持该协议的对象要实现这两个方法。一目了然了吧,这两个方法可以对应robotframework里的suite setup 和 suite teardown

先看一个例子吧。

class DummyResource(object):
    def __init__(self, tag):
        self.tag = tag
        print 'Resource [%s]' % tag

    def __enter__(self):
        print '[Enter %s]: Allocate resource.' % self.tag
        return self	

    def __exit__(self, exc_type, exc_value, exc_tb):
        print '[Exit %s]: Free resource.' % self.tag
        if exc_tb is None:
            print '[Exit %s]: Exited without exception.' % self.tag
        else:
            print '[Exit %s]: Exited with exception raised.' % self.tag
            return False

这段代码我是从最顶上那个帖子里抄的。可以做一些说明。

  • 这是一个叫DummyResource的类,提供了__enter__() 和 __exit__()两个方法,说明这个类是可以用with语句来调用的。另外从类名我们可以感觉到,with语句的运用都是和资源相关的。什么是资源?文件,网络套接字,线程thread,等等这些都是资源。
  • __enter__()方法里,除了一句打印“山顶的朋友,我在这里”,就是一句返回语句:
class DummyResource(object):
    # ...
    def __enter__(self):
        print '[Enter %s]: Allocate resource.' % self.tag
        return self	
    # ...

返回了一个self!这是什么意思?就是把这个类的实例返回出去。这样

with context_expression [as target(s)]:
    with-body

中的as target(s)就可以得到这个值了。忘了说,target(s)之所以有或许复数,是因为__enter__()方法是可以返回多个值成为一个元组的。

  • __exit__() 是个更复杂的方法,用来定义退出时候的动作。在方法的定义中可以看到有额外的参数exc_type、exc_value 和 exc_tb。这三个都是和异常相关的。如果with语句包住的用户代码正常执行,那么这三个变量都是None;反之,如果出错了,可以简单通过exc_type来判断异常的类型,配合后面两个变量获得更多的异常信息,进一步做相应的处理。
  • __exit__()方法中更重要的是它的返回值。return False。False的意思是“我还没有处理完,我要把这个异常继续抛出去,你们外面的代码去抓住它继续处理吧”。如果心满意足的,或者心怀鬼胎的觉得已经处理完了,就返回个真值,外面的代码就不会知道有异常发生过。很多问题的根本原因就这么湮没了。:-(

结合这个类定义,看看实用的调用例子吧。
小乖乖:

with DummyResource('Normal'):
    print '[with-body] Run without exceptions.'

和不乖的:

with DummyResource('With-Exception'):
    print '[with-body] Run with exception.'
    raise Exception
    print '[with-body] Run with exception. Failed to finish statement-body!'

小乖乖的输出是这样的:

Resource [Normal]
[Enter Normal]: Allocate resource.
[with-body] Run without exceptions.
[Exit Normal]: Free resource.
[Exit Normal]: Exited without exception.

很好,按部就班,只要读得懂类代码就很容易看出这些输出。下面看一下“小淘气”的输出呢。

Resource [With-Exception]
[Enter With-Exception]: Allocate resource.
[with-body] Run with exception.
[Exit With-Exception]: Free resource.
[Exit With-Exception]: Exited with exception raised.

Traceback (most recent call last):
  File "G:/demo", line 20, in <module>
   raise Exception
Exception

除了读代码能看清的输出,还要说一两句。

  • 用户代码中是先抛出了异常后又打印了一句“[with-body] Run with exception. Failed to finish statement-body!”。在输出中这句没有打印。这说明了__exit__()方法是清道夫,你们用户代码怎么乱糟糟,你先跑,抛出异常了,就别接着往下走了,我留下来打扫战场。
  • 输出中的“Traceback (most recent call last):”一段是解释器抛出的异常,在__exit__()方法中的开关就是最后的那个返回否值。如果是返回真值,这段Traceback是不会输出的。

最后,说说最初的那个花姐举出来的例子。

with open(r'demo.txt') as f:
    for line in f:
        print line
        # ...more code

打开一个Python的IDE(我用的是Pycharm CE),可以点到open的定义,就是一句话。

def open(name, mode=None, buffering=None): # real signature unknown; restored from __doc__
    """
    open(name[, mode[, buffering]]) -> file object
    
    Open a file using the file() type, returns a file object.  This is the
    preferred way to open a file.  See file.__doc__ for further information.
    """
    return file('/dev/null')

仅仅返回一个file实例。继续点过去,就豁然开朗了。

class file(object):
     # ... some codes

    def __enter__(self): # real signature unknown; restored from __doc__
        """ __enter__() -> self. """
        return self

    def __exit__(self, *excinfo): # real signature unknown; restored from __doc__
        """ __exit__(*excinfo) -> None.  Closes the file. """
        pass
     # ... more codes

file 这个类 实现了__enter__()和__exit__()方法,那外面当然可以用with语句来建立文件操作的上下文。

其实实现上下文管理协议并不是每次都需要写一个类实现两个办法,还有其他的方法,会另开一篇写写。

-EOF-