GitPython: get list de confirmaciones remotas aún no aplicadas

Estoy escribiendo un script de Python para get una list de confirmaciones que están a punto de ser aplicadas por una operación de git pull . La excelente biblioteca de GitPython es una gran base para comenzar, pero el funcionamiento interno sutil de git me está matando. Ahora, esto es lo que tengo en este momento (versión simplificada y anotada):

 repo = git.Repo(path) # get the local repo local_commit = repo.commit() # latest local commit remote = git.remote.Remote(repo, 'origin') # remote repo info = remote.fetch()[0] # fetch changes remote_commit = info.commit # latest remote commit if local_commit.hexsha == remote_commit.hexsha: # local is updated; end return # for every remote commit while remote_commit.hexsha != local_commit.hexsha: authors.append(remote_commit.author.email) # note the author remote_commit = remote_commit.parents[0] # navigate up to the parent 

Esencialmente obtiene los autores de todos los commits que se aplicarán en el próximo git pull . Esto está funcionando bien, pero tiene los siguientes problemas:

  • Cuando la confirmación local está delante del control remoto, mi código solo imprime todos los commits a la primera.
  • Una confirmación remota puede tener más de un padre y la confirmación local puede ser el segundo padre. Esto significa que mi código nunca encontrará la confirmación local en el repository remoto.

Puedo tratar con repositorys remotos detrás del local: simplemente busque en la otra dirección (local a remota) al mismo time, el código se vuelve complicado pero funciona. Pero este último problema me está matando: ahora necesito navegar un tree (potencialmente ilimitado) para encontrar una coincidencia para el compromiso local. Esto no es solo teórico: mi último cambio fue una fusión de repos que presenta este mismo problema, por lo que mi script no funciona.

Obtener una list orderada de commits en el repository remoto, como lo hace repo.iter_commits() para un Repo local, sería de gran ayuda. Pero no he encontrado en la documentation cómo hacerlo. ¿Puedo get un object Repo para el repository remoto?

¿Hay algún otro enfoque que pueda llevarme allí, y estoy usando un martillo para clavar tornillos?

Me di count de que el tree de compromisos siempre era así: un compromiso tiene dos padres y ambos padres tienen el mismo padre. Esto significa que el primer compromiso tiene dos padres pero solo un abuelo.

Por lo tanto, no fue demasiado difícil escribir un iterador personalizado para revisar las confirmaciones, incluidos los treees divergentes. Se parece a esto:

 def repo_changes(commit): "Iterator over repository changes starting with the given commit." number = 0 next_parent = None yield commit # return the first commit itself while len(commit.parents) > 0: # iterate same_parent(commit.parents) # check only one grandparent for parent in commit.parents: # go over all parents yield parent # return each parent next_parent = parent # for the next iteration commit = next_parent # start again 

La function same_parent() cuando hay dos padres y más de un abuelo. Ahora es una cuestión simple iterar sobre las confirmaciones no fusionadas:

 for commit in repo_changes(remote_commit): if commit.hexsha == local_commit.hexsha: return authors.append(remote_commit.author.email) 

He dejado algunos detalles para mayor claridad. Nunca devuelvo más de un número preestablecido de confirmaciones (20 en mi caso), para evitar ir al final del informe. También compruebo de antemano que el repository local no está por delante del repository remoto. ¡Aparte de eso, está funcionando genial! Ahora puedo alertar a todos los autores de commit que sus cambios se están fusionando.