记一次Django数据迁移Bug

Django的Model是按照每次的migrations管理(即app下的migrations包)的。每次更新Model之后,都需要先运行python manage.py makemigrations进行生成migration,这些migrations中记录了数据库的变更,然后用python manage.py migrate应用这些更改。

随着项目的增大,migrations也越来越多,每次新的migration都是基于前一次的,也就是说,每次更改数据库,都要把所有的migration走一遍。导致执行migrate的时候速度很慢。比如我们公司的仓库,每次migrate需要二十多分钟。大哥说可以删掉所有的migrations,重新生成,然后用migrate –fake命令“假装执行”,这样做一次,后面的操作都变快了。

今天,我想在自己的项目上用这个方法,于是照着大哥的方法做了遍。本地没有任何问题,做好之后,去服务器操作。结果挂了。服务器的错误如下:

试过很多办法,甚至把本地的数据库都删掉,也无济于事。

其中的一个尝试让我发现,服务器revert回去,先执行makemigrations,服务器没问题,然后git拉到本地,本地竟然出现了同样的问题。

尼玛,坑爹呢这是。

我打开migrations文件,看了看有个叫做('auth', '0008_auto_20160710_0926')的依赖,本地找不到。在项目里面全局搜了一下,也没搜到这个文件。

migrations-git-diff

最后用pycharm全局搜了一下,找到了…… 从pycharm的颜色可以看出,这并不是在项目中的一个文件,而是site-package的文件,竟然也有migrations,好坑啊……

从git diff可以看出,主要是文件名字的结尾不同。django生成migrations文件的明明规则是 次数+内容+时间的。这个不同得从我管理项目的方式说起。我觉得migrations文件不是项目代码的一部分(不是自动生成的),所以将migrations文件夹放到了gitignore中。每次更新数据库,本地做本地的migrations,服务器做服务器的。这样,就造成时间不同,本地是09:26,服务器是10:04. 两个文件名字不一样……所以有了上文的冲突。

比较好的解决方法是:用git连migrations一起管理着,服务器只执行migrate。说不定什么时候我们还需要手动修改生成的migrations呢!

瞎忙活了一下午,给我的教训是……不要手忙脚乱,认真看报错的信息,慢慢推理吧!慌什么呢!

教训2:还是实践让人学习啊,应该用git管理migrations而不是教给django去生成就行了。

 

网络攻防课程科创小组报告

本文是学院要求写的科创报告,用来换学分的。大部分内容都是在凑字数。

大一的时候,参加了一个校内科创小组。

说到这个科创小组,其实我一开始参加的不是网络攻防小组的,是个教PS的。第一节课,讲课的那个学长讲到一个地方卡住了,然后我上去讲的。讲完那节课我就再也没去过。

后来我就换到了这个网络攻防小组,但是还是什么都没有学到。最大的收获,就是认识了顾天宇学长,成为了好朋友,三年以来,在计算机、读书和一些想法上有很多交流。

想来,那时候刚进入大学,很多事情都比较迷茫,比如是不是应该听辅导员的话大一不要买笔记本电脑,买什么样的笔记本电脑,如果制作一个个人博客,怎么学编程,等等。顾天宇学长在这些方面给我的影响都很多。也是从那时候起,开始用wordpress写东西,开始学习用mac,linux。

刚进入大学,我认为自己是对编程有很强的兴趣的。但是上了几节课,我发现并不是这样,自己不喜欢上课。不喜欢老师在上面讲的东西,学了一段时间,也不过是在命令行写个简单的循环判断。和顾天宇学长的交流,让我知道了很多在校内绝对接触不到的东西,让我知道,这个世界上的语言不只有C++和Java,还有很多丰富多彩的编程语言和工具,有不同优势的语言。

顾天宇学长送给我很多书。印象比较深的,一本《黑客,计算机革命的英雄》,从这本书中,我认识了很多像卡马克式的人物,我也想成为这样的人,拥有他们的能力,如果对世界什么不好,自己就有能力去修改它们。让我更加坚定自己的梦想。另外,顾天宇学长还送给我过很多别的书,《程序员的数学》之类的,还有一本《Objective-C教程》,但是那时苹果正好新开发布会发布了swift编程语言,这本书让我直接扔垃圾桶里了。除此之外,他还有很多不舍得送给我的,但是给我做了推荐,我去买来看,收获颇多。

后来,学长好像看了《葵花宝典》《计算机程序的构造与解释》,走火入魔沉迷lisp不能自拔。我也有学SICP的计划,但是看了第一章之后,就好久没再看了。这本书确实是好书,光是第一章,就让我学到不少东西,以后要看完。

再后来,学长突然消失了。跑到了瑞典学习了一年。让我第一次也有了出国的想法,于是他回来之后不久,我就去了德国。

很多地方,这些模仿都带给我了一些方法论类似的指导。从这样一个朋友身上,你可以看到生活中另一种可能,可以觉得很多离你很远的东西,其实就在眼前。不会畏惧尝试。就说这么多吧,再多的东西,我写了,你们也不懂。

网络攻防这个兴趣小组当时还有一个学长,姓李。这位学长非常耐心,我装MySQL数据库出问题,他耐心地跑到我宿舍给我调试,非常感激。不过后来就没联系了。大二的时候上体育课帮他喊了十几次到,再也没见到他人。他是个好人。

大学期间,让我一度怀疑上大学是不是个错误的决定。无休无止的生涯规划大赛,大学生生涯导航,看着同学们在台上说我以后要当XX,我对人生的计划XXX。政治课花的精力比计算机课都多,就是计算机课教的也都是十年前的东西。幸好,学院搞了个科创小组,让人激动!虽说什么都没学到,但是认识了气味相投的学长,让我知道自己还是正常的,也能在这种环境中思考和学习。现在我觉得,学习方面,别人能给的也就是个带进门的作用,真正要学到什么东西,还是得靠自己。要是不想学,学习的环境再好,别人再怎么逼,顶多也就是能逼你写完作业,又不能把知识塞进你的脑子里去。所以也就不怨学校的教育制度差、上的课质量不高、流于形式了。况且图书馆那么多书放着去读,已经够幸福的了。

所以说,现在想想,还是非常感激学院的这个项目的。这提供了学长和新生交流的平台,为志趣相投的人提供了相识的机会。我自己从中的收获也很大。真希望能一直办下去。这几年学生组织里我没发现一个办实事的,起码这个东西,还是本着学习的态度的。

 

Git免除每次都输入密码

每次通过git push或者fetch的时候,会被要求输入密码,很烦。通过在服务器加上自己的公钥,就不必再被要求密码验证了。

首先,公钥是针对SSH协议的,HTTPS协议方式的仓库是不可以使用这种方式的。所以第一步先看一下自己的仓库是不是用SSH协议的:查看.git/config文件。

如果是下面这样的格式,就是HTTPS协议的。

改成下面这样:

第二步,在服务器加上自己的ssh公钥。

一般,在~/.ssh/下会有一个 id_rsa.pub文件,通过下面这个命令将自己的公钥保存到服务器上,下一次,从这个服务器上的操作都不需要密码验证了(实际上,所有ssh操作都不需要再次输入密码了)。

如果仓库托管在github上。登录github之后在个人的settings有SSH and GPG keys选项,打开,上文中id_rsa.pub的内容复制过去就行了。

github-ssh-and-gpg-keys

如果没有id_rsa.pub,可以用ssh-keygen(这是ssh提供的)产生一个。

ssh-keygenid_rsa-pub

以后,github的仓库也不需要密码了。

参考:

  1. http://www.cnblogs.com/hanxi/archive/2012/07/31/2616628.html
  2. http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html
 

Git的几个技巧

作业,4个问题,记录一下。

一、你在一个分支工作,突然遇到紧急问题,要切换到另一个分支,但是当前的工作还没做完,没有ready-to-commit,如何暂时保存当前的工作内容?

Git建议,checkout分支时永远保持工作区的干净。首先,git commit是可以达到目的的,但是你可能还没有ready to commit,这样会弄乱commit log。网上有人说,可以add但不commit,工作完了再回来,内容还在。我试了一下,发现切换到新的分支,旧分支暂存的内容还存在。这样就算切换到了新的分区,工作也会受干扰。

addbutnocommit

这里,推荐的方法是git stash。

“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。

如果遇到紧急事件需要切换分支,使用git stash储藏当前分区,切换到别的分支工作,解决问题之后换到旧分区,使用git stash apply继续工作。

  • 储藏是全局的,你不仅可以在使用git stash的分支使用git stash apply,还可以在别的分区使用。(可能遇到冲突)
  • apply之后,储存并没有被删除(可以使用drop删除);使用pop命令可以“弹出”
  • 也可以在当前分支存储之后,继续在当前分支工作。如果以后要合并存储,建议以分支形式合并

参考:git-scm

二、如何merge一个commit,而不是整个分支?

问题描述:github的一个仓库更新了一个新的feature,我想在我的环境中用这个feature,但是不想merge之前所有的commit,可以只merge这一个commit吗?

使用git cherry-pick

之后变成:

这样的merge,会在分支产生一个新的commit,log一样,id不一样。git把merge的这个提交当做是从HEAD过去的,也就是说,如果提交C中用到了提交B的一个函数,git并不会知道。

参考:http://stackoverflow.com/questions/880957/pull-all-commits-from-a-branch-push-specified-commits-to-another/881014#881014

三、如何撤销一次merge操作?

问题描述:现在有以下的情况,此时,C10是不小心合并的,我们不要合并tv/rebase-stat,需要re-merge这次merge。

unmerge1

第一种方法是,可以跳到C8,合并jk/post-checkout和db/push-cleanup。然后就变成了这样子:

unmerge2

这种做法的优点是,就和没有这次意外一样,所有的分支都能继续正常使用。缺点是:所有人都要执行这样的操作,而且如果已经发布merge,这么做就有困难。我讨厌这种做法,因为这是违背Git设计哲学的,所有的操作都应该向前,不能去修改历史。

另外,如果我们在不小心合并之后,进行了很多操作,“压住了”不小心的merge,如下图。如果使用第一种方法,就会丢掉后面的更新。

unmerge3

这里第二种方法,使用revert命令:

其中,参数1是parent的哪一条主线,一般是1,有可能是2.如果不确定,可以使用git show --format="%P" <SHA>查看。

就变成了这样:

unmerge4-1

这个做法,就好像git cherry-pick所有C8中的提交一样,撤销所有提交的更新。相当于,我做了新的工作,内容就是把C8的内容改了回去,大家都pull一下就好啦。

但是这个方法存在的问题是,git认为,C5 C6已经被正确merge了,把^C8当做是新的commit对待。上文说道,我们只是“不小心”merge的,这时如果merge jk/post-checkout分支,只会mergeC6之后的。

如果^C8之后有很多更新,如何保留这些更新,再入merge之前re-merge的分支内容,我还没有找到合适的方法。

参考:

四、刚刚的提交有错误,需要修改?

如果是commit写错了,想修改一下。使用git commit --amend,会打开编辑器,重新填写commit。关闭编辑器,新的log就覆盖掉了旧的,但是不会产生新的提交。但是id会变。

如果是有文件需要修改,直接做新的工作,将工作内容添加到暂存区,然后执行git commit --amend,新的工作内容会补到上一次提交中。

注意,如果已经发布,就不能用这个命令了。

 

小公司不等于小作坊

最近在两家差不多规模的公司实习,作为一个还没毕业的实习生,谈谈感受。

第一家公司是外包公司,业务是一些政府项目和外包项目,用的技术不会很深入,比如安卓开发用HBuilder写前端搞定,直播等功能用不同的SDK,也不会深入一个项目,基本上交付了就完事。第二家公司做平台,做了几年一直在开发此平台,代码也很庞大了(从github clone下来用了两个小时……)。以下简称外包公司和平台公司。

新员工培训方面。外包公司领导简单问了我一下情况,接下来的实习就是根据外包项目的需求让学习,第一天做了配置HBuilder和SpringMVC,第二天看安卓,第三天研究直播通话,第四天写个Ajax。可以说,一点东西都学不到。领导非常忙(为什么忙,下面提)。平台公司,我上班的第一天,领导发过来一个《Git分支管理指南》,一个《新员工快速成长计划》,拉近Github项目组,说你对着文档把环境搭起来,有问题找我。

沟通方面。外包公司靠喊,QQ,平台公司靠早会、邮件。外包公司喊的方式缺点是不容易控制大家的工作,基本上是老板想起来什么事情就喊一下布置,员工有什么事情也通过喊一下报告,另外这种“广播”的方式,很烦人,有些事情不关我事,又屏蔽不了,我估计用这种方式领导也比较容易焦头烂额。有个好处是,我现在就在上班时间写博客,没人知道。有一点我比较方案的是公司特别依赖QQ,文件在QQ传,任务也在QQ布置。这样做无法对应到个人,记录不好管理,话说不清楚。平台公司开早会,一般20分钟,开完之后一天干什么大家都知道了,一天中基本没人说话,领导有个配置文件需要发给我,都是用邮箱发的,工作效率非常高。不写日报,只有周六(暴露周六也上班也)晚上开周会总结。这样也有一点不好,大家的沟通比较少,我入职近两个月,没有同事的QQ、微信和电话,我估计除了我他们之间也不会常联系。某天在博客园偶尔看到以前一位同事的博客,说他自己离职的原因就是这个公司没有工程师文化,同事之间交流太少了,没有归属感。

版本管理。外包公司用svn,所有人一条分支,log随便写,领导喊:“小王你那XXX做完了吗?做完了提交下,先更新再提交哦不然会冲突”。平台公司有一份分支管理文档, 所有人都要学习。官方repo只有master和release分支,tag使用严格规范,领导review所有pr,使用issues。原则是快速回退,灵活发布bugfix。我认为这两种都比较合理,外包公司项目多,生命周期短,不需要后期维护,所以采用员工学习成本低的方式合情合理,但是如果平台公司这么管理,就比较恐怖了……

绩效考核。作为实习生,不是特别了解。不过就目前看来,外包公司看老板心情。从我微信联系人的备注来看,已经有三分之一的员工被我打上了“马屁精”的tag。另外还要每天写日报,烦。平台公司,每周日上司群发大家的绩效,我不是很清楚机制,应该是根据工作量来的吧。

问题处理。作为很菜的实习生,肯定能遇到很多问题。上面说了外包公司的领导比价忙啦,所以遇到问题领导一般都会告诉你自己想办法解决,给你个大体思路,我经常埋头搞好几天,而且都是一些配置问题,查的多,试的多,自然解决的了,但是走了很多弯路。平台公司,第一天配置环境的时候遇到了几个问题,有几次领导直接在我电脑上调了一会帮我搞定。就这一会让我见识了调试的方法,怎么一口气写那么长的命令,和一些高效用Linux的习惯。

团队合作和技术。写到这里,想必大家都应该清楚了。外包公司基本上每个人都写Java,前端,爬虫啥的,虽然十几个开发专注点有侧重,但是不是很精通。团队之间的合作比较糟糕,有一个周,领导给我的任务是……改别人写的前端代码。别提多痛苦了,内嵌style,被覆盖无数次的css,表现良好代码却匪夷所思各种relative,absolute混乱。平台公司工作时间不长,暂不表。

个人感受。我现在兼职实习加起来有四份工作。去外包公司感觉很累,搬砖嘛……没啥技术含量,做的事情都是别人做了无数次的,想想第二天要上班愁得慌。去平台公司比较积极,虽然晚上8点才回来(糟,暴露996了),更累一点,但是学到东西不少,也不会感觉自己的时间浪费掉了,做的东西还是有价值的。

有一点体会就是,虽然外包公司大领导也整天在群里(注意是QQ群)强推用邮件交流,但是白说。我感觉领导的作用比较大,比如外包公司的领导写代码,我们叫他大哥,领导很忙,晚上十点多十一点多走,活在终端里的那种人,所以代码规范什么的,员工都听话。外公公司领导就是领导,一行代码不写。很多事情说了也白说。做事靠经验。

反正不看代码就是不行。我觉得好的领导是写代码的领导。

之前看到这篇博客,谈了大团队和小团队的区别:

small-group-vs-big-group

可以说,这两个公司是上面两种典型。但是我认为小公司不一定就不能有大公司的管理,管理得当,不仅可以保持小公司灵活,动作快,又不会陷入大公司反应迟钝的泥潭。

我的博客不会给我的雇主做广告,永远保持独立性,不会写任何软文性质的东西。两家公司都匿了名,普通读者也猜不到。不过我相信,外包公司永远在搬砖,平台公司总有一天大家都会听说的。

——读者止步——

至于为什么我去外包公司实习,妈的我要吐槽东华大学软件工程院脑残的实习制度了。学校分配实习公司(全他妈外包公司),不去没学分不能毕业,换实习不行,自己找实习不行。一天给85块钱。去找负责老师谈,老师这么说:

“我们这个实习啊,经过XXX会讨论的。”

“这是学院制度,不能换实习,就是这么规定的,我也没办法。”

“啊?谁规定的?我们开会决定的。这就是制度。”

“你知道嘛?你们还能选实习方向(并不能),人家专业硕士都不能选的,人家还要实习一年多。”

“你这么大了,要懂事。要体谅学校。”

“什么人身攻击?呵呵我从九几年开始教学还第一次有学生说我人身攻击,我的意思不是你不懂事,你怎么能说我人身攻击,我那么多学生都没说过我人身攻击。”

“不行啊不能换啊!我们跟企业有合作的(同谋?)好学生都自己找实习啊那都留下差学生企业不乐意啊(潜台词:找工作好坏不关我事,我要的是所有人都有实习经历,签掉三方合同)。”

这他妈都什么逻辑,什么都是制度。

狗屁东华。