<jupyter_start><jupyter_text>Para entrar no modo apresentação, execute a seguinte célula e pressione `-`<jupyter_code>%reload_ext slide<jupyter_output><empty_output><jupyter_text>GitEste notebook apresenta os seguintes tópicos:- [Git](Git)- [Exercício 9](Exerc%C3%ADcio-9)- [Pandas](Pandas)- [Exercício 10](Exerc%C3%ADcio-10) Outra fonte de informações de um repositório de software é o repositório do sistema de controle de versões.Pelo controle de versões, conseguimos ter acesso a todos os arquivos de todas as versões, todas as mensagens de commit, branches, e colaboradores.Nesta parte do minicurso, faremos a mineração dessas informações. No caso do Git, ao clonar um repositório, ficamos com uma cópia local do que está lá. Portanto, começamos a mineração com um clone e não precisamos de nenhum proxy.<jupyter_code>!git clone https://github.com/gems-uff/sapos<jupyter_output><empty_output><jupyter_text>Com o repositório clonado, podemos usar comandos do git para extrair informações.<jupyter_code>%cd sapos
!git branch -r<jupyter_output><empty_output><jupyter_text>Essas informações também podem ser obtidas para tratarmos usando variáveis do Python.A seguir tentamos descobrir qual é o commit de cada um desses branches.<jupyter_code>git_branch_output = !git branch -r
branches = [
    branch.strip().split(' ')[0].split('/')[1]
    for branch in git_branch_output
]
branches
branch_commit = {}
for branch in branches:
    __ = !git checkout $branch
    commit = !git show --pretty=format:"%h" --no-patch
    branch_commit[branch] = commit
__ = !git checkout master
branch_commit<jupyter_output><empty_output><jupyter_text>Usamos `__ = !...` para evitar a exibição do output do comando de sistema. O IPython imprime o output quando bang expressions são usadas isoladas e retorna o output quando elas são usadas em atribuições.Note que apenas o branch `reports` e `bugfixes` está em um commit diferente.    Exercício 9Faça a mesma operação para obter o código dos commits de tags e salve na variável `tag_commit`.<jupyter_code>tags = !git tag
...<jupyter_output><empty_output><jupyter_text>Agora vamos agrupar as tags por versões minor e ordenar as versões patch.<jupyter_code>from itertools import groupby
groups = groupby(tags, lambda x: x.rsplit(".", 1)[0])
minor_tags = {}
for minor, elements in groups:
    minor_tags[minor] = sorted(
        elements,
        key=lambda x: int(x.split('-')[0].split('.')[-1])
    )
minor_tags['4.3']<jupyter_output><empty_output><jupyter_text>Fazendo o mesmo para agrupar versões major.<jupyter_code>groups = groupby(minor_tags, lambda x: x.rsplit(".", 1)[0])
major_tags = {}
for major, elements in groups:
    major_tags[major] = sorted(
        elements,
        key=lambda x: int(x.split('-')[0].split('.')[-1])
    )
major_tags['4']<jupyter_output><empty_output><jupyter_text>Com isso, podemos escolher versões major (e.g., 3 e 4) e obter a última versão patch para cada minor delas.<jupyter_code>last_patch_for_v3v4 = {
    minor: minor_tags[minor][-1]
    for minor in major_tags['3'] + major_tags['4']
}
last_patch_for_v3v4<jupyter_output><empty_output><jupyter_text>Agora queremos ver a evolução de linhas de código para as versões selecionadas. Para isso, vamos percorrer o dicionário fazendo checkout de cada versão, carregar o número de linhas usando `cloc` e parsear o resultado para extrair as colunas para construir linhas de uma tabela.<jupyter_code>from collections import defaultdict
columns = {"id"}
rows = []

for minor, tag in last_patch_for_v3v4.items():
    __ = !git checkout $tag
    lines = !cloc .
    filtered_lines = lines[lines.index("-" * 79) + 3:]
    commit_result = defaultdict(int)
    commit_result["id"] = minor
    for line in filtered_lines:
        if not line.startswith("-"):
            split = line.split()
            language = split[0]
            commit_result[language + "_files"] = int(split[1])
            commit_result[language + "_blank"] = int(split[2])
            commit_result[language + "_comment"] = int(split[3])
            commit_result[language + "_code"] = int(split[4])
            columns |= {
                language + "_files", language + "_blank",
                language + "_comment", language + "_code"
            }
    rows.append(commit_result)<jupyter_output><empty_output><jupyter_text>PandasPodemos usar `pandas` para construir a tabela a partir da lista de dicionários.<jupyter_code>import pandas as pd
df = pd.DataFrame(rows)
df<jupyter_output><empty_output><jupyter_text>O `pandas` permite descrever a tabela com o método `.describe()`.<jupyter_code>df.describe()<jupyter_output><empty_output><jupyter_text>Além disso, é possível fazer seleções nos dados.<jupyter_code>df[df["Ruby_code"] > 25000]<jupyter_output><empty_output><jupyter_text>Exercício 10Selecione as versões que usam CoffeeScript e as versões que não usam XML.<jupyter_code>with_coffee = ...
with_coffee
without_xml = ...
without_xml<jupyter_output><empty_output><jupyter_text>Além de selecionar linhas, podemos selecionar colunas.<jupyter_code>columns = ['SUM:_files', 'SUM:_blank', 'SUM:_comment', 'SUM:_code']
ndf = df[columns]
ndf<jupyter_output><empty_output><jupyter_text>O `pandas` também oferece algumas funções que facilitam a geração de gráficos.<jupyter_code>%matplotlib inline
ndf.boxplot()
df.set_index("id")["Ruby_code"].plot()<jupyter_output><empty_output><jupyter_text>É possível aplicar operações em colunas e criar novas colunas.<jupyter_code>df.loc[:, "tag"] = df["id"].apply(lambda minor: last_patch_for_v3v4[minor])
df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10907457322551663, 'fraction_numerical': 0.008984725965858042, 'mean_word_length': 5.05, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 66, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '392205', 'license': 'MIT', 'n_tokens_mistral': 1991, 'n_tokens_neox': 1932, 'n_words': 514, 'path': '8.Git.ipynb', 'repo_name': 'jacsonrbinf/minicurso-mineracao-interativa', 'size': '5565'}