在git中使用Python打补丁包


有时候, 我们写完一个项目需要对其进行打包. 打完成包非常简单, 我们可以使用git archive这个命令. 但是有时候我们需要对项目的一些特殊文件进行过滤. 这个时候, 可能会说这些文件可以放在.gitingore中. 我需要告诉的时, 在开发项目的时候, 有些文件也需要在git仓中, 以方便其他小组的人使用. 另一种情况, 我们需要打一个差异包出来, 如果没有任何特殊要求, 可以直接使用tar zxvf xxx-patch.tar.gz `git diff –name-only`进行打包. 但是你这个仓中含有很多个submodule时候, 使用这种方法, 会遇到一个很不幸的事, 不管这个子模块修改了一个, 还是多个文件, 他都会将这个子模块全部打包进去. 因此, 我们需要一个好的打包工具, 解决以上问题. 目前我是采用python + pygit2的方式. 同时你系统环境中要有git.

1. 获取git仓中tags列表

pygit2有一个已知的bug, 你给你的项目打tag, 如果打tag时候没有加上message. pygit2是无法读取到的.
读取git仓中的tag非常的简单. 代码如下

def get_tags(self):
 self.tags = [];
 print "=== Parsing package version";
 data = self.repo.listall_references();

 for item in data:
  ref = self.repo.lookup_reference(item);
  if (ref.type == pygit2.GIT_OBJ_COMMIT):
   oid = ref.oid;
   ref_obj = self.repo[oid];
   if isinstance(ref_obj, pygit2.Tag):
    self.tags.append(ref_obj);
   else:
    continue;
 self.tags.sort(lambda x,y: cmp(y.tagger.time, x.tagger.time));

获取tag之后, 我们可以使用tag下属性timer, 根据时间先后次序进行排序. 这样你想取最后一个tag作为目标进行打包 只要self.tags[0](倒序)就能直接获取到. 同样你需要获取两个版本的差异. 只要git diff tag[0]..tag[1]

2. Diff的一些参数

git diff提供了非常多的功能. 前面一直提高的–name-only 只显示更新的文件
–name-status 显示更新的文件以及状态
–diff-filter=[A|C|D|M|R|T|U|X|B] diff过滤显示. A:增加, D:删除, M:修改, C: 复制, R: 重命名, T 更改, U 未合并, X 未知, B Broken

3.获得submodule的差异

这里通过git diff获得submodule的差异内容. 在git中, submodule的diff内容就是两个sha1的hash值. 我就是利用这一点. 提取两个函数值, 然后在使用git diff命令,提取出子模块的更新列表.代码如下:

def get_submodule_diff_files_list(self, submodule_dir, submodule, git_str):
 diff_info = git_str[0].strip().split();
 #find -Subproject
 pre_subproject_position = diff_info.index('-Subproject')
 pre_subproject_version_position = pre_subproject_position + 2; #手动偏移2位
 pre_version_hash = diff_info[pre_subproject_version_position];
 #find +Subproject
 last_subproject_position = diff_info.index('+Subproject');
 last_subproject_version_position = last_subproject_position + 2;
 last_version_hash = diff_info[last_subproject_version_position];

 update_list = []

 if (pre_version_hash and last_version_hash):
  tfiles = git("diff", last_version_hash, pre_version_hash, "--diff-filter=A,C,M,T", "--name-only", cwd=submodule_dir)[0];
  tfiles = tfiles.strip().split();
  update_list = [os.path.join(submodule,f) for f in tfiles];
 else:
  update_list.append(submodule)

 return update_list;

4. 完成代码示例

Leave a Comment

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.