Mejores prácticas
Restaurar un proyecto de Git cuando CODESYS se ha bloqueado al editar el proyecto
Según qué operación CODESYS se bloqueó anteriormente, tiene las siguientes opciones de recuperación:
Normalmente, puede volver a abrir el proyecto después de un bloqueo. CODESYS Git restaura el último estado del proyecto guardado internamente y vuelve a escribir el contenido del proyecto en el repositorio de proyectos de Git. Este mecanismo de "almacenamiento fallido" trata el proyecto como una fuente de datos "maestra". Si el proyecto falla durante un proceso de fusión, no debe guardar inmediatamente después de volver a abrir antes de continuar trabajando, sino descartar todos los cambios primero (git reset --hard). Puedes hacer esto en el Ver estado y reservas El comando Descartar todos los cambios usar.
En caso de que ya no sea posible abrir con éxito el proyecto después del bloqueo (por ejemplo, porque archivos completamente incompatibles terminaron en el almacenamiento del proyecto), tiene la siguiente opción para una recuperación: Vuelva a cargar completamente el proyecto desde el repositorio. Para más información, ver: Reconstruir el proyecto desde el repositorio
Transferir un proyecto desde CODESYS SVN a CODESYS Git
Le recomendamos encarecidamente que no elimine los repositorios SVN después de transferir con éxito los proyectos a GIT para poder acceder a ellos si es necesario.
Sugerencia
En CODESYS Git la versión 1.4.0.0 y posteriores, estará disponible una interfaz de secuencias de comandos para transferir un proyecto desde CODESYS SVN a CODESYS Git.
Importante
El comando Git git-svn
no se puede usar para transferir CODESYSproyectos de CODESYS SVN para CODESYS Git porque CODESYS Git usa el .json
formato de archivo, a diferencia del formato de archivo binario de CODESYS SVN.
En CODESYS Git, un repositorio de Git solo puede administrar uno CODESYS proyecto. Porque un repositorio SVN puede contener varios CODESYS proyectos, se debe crear un repositorio Git independiente para cada proyecto de un repositorio SVN al transferirlo a CODESYS Git.
Se recomienda transferir los proyectos individuales de un repositorio SVN a los repositorios de CODESYS Git proyecto por proyecto.
No se recomienda dividir un repositorio SVN en varios repositorios SVN porque esto puede causar problemas más adelante.
Las ramas y las etiquetas existen tanto en SVN como en GIT, pero están diseñadas de forma diferente en estos dos sistemas. Una transferencia con el
git-svn
el comando no es posible porque este comando no se puede usar en CODESYS Git (véase más arriba).Por lo tanto, nos limitamos a transferir el tronco SVN a una rama de Git (por defecto «Master» o «Main»). Si es necesario, las etiquetas SVN se pueden añadir manualmente como etiquetas de Git
En este procedimiento, la versión más reciente del CODESYS el proyecto se archiva por primera vez en CODESYS SVN. Luego se desconecta la conexión a SVN y se abre un repositorio de Git CODESYS Git se inicializa para el proyecto. La desventaja de este procedimiento es que se pierde el historial del proyecto porque solo se transfiere a Git la última revisión de SVN
Requerimientos: CODESYS SVN y CODESYS Git están instalados en CODESYS. Mediante el Herramientas → Personaliza comando, el Compromiso completado se ha agregado el comando al Integración con Git categoría de comando en Git menú.
Abra el CODESYS proyecto que ha guardado en el repositorio SVN.
Haga clic Proyecto → SVN → Finalizar compra.
Se ha revisado la última revisión del proyecto.
Haga clic Proyecto → SVN → Desconectar el proyecto de SVN.
Cree una nueva carpeta vacía en el directorio de archivos local de su ordenador.
En CODESYS, haga clic Git → Inicializar el repositorio de Git y selecciona la carpeta vacía creada en el paso anterior del cuadro de diálogo.
Haga clic Git → Compromiso completo.
El proyecto ahora está almacenado en el repositorio local de Git y se puede enviar a un repositorio remoto si es necesario.
En este procedimiento, cada revisión de SVN se transfiere manualmente en una confirmación de Git.
Requerimientos: CODESYS SVN y CODESYS Git están instalados en CODESYS. Mediante el Herramientas → Personaliza comando, el Compromiso completado se ha agregado el comando al Integración con Git categoría de comando en Git menú.
Crea un nuevo proyecto vacío en CODESYS y asígnele un nombre, por ejemplo,
Main Project
.Haga clic Git → Inicializar el repositorio de Git.
Haga clic Git → Compromiso completo.
Haga clic Git → Comprometerse para ejecutar una confirmación vacía. En el Comprometa cambios por etapas cuadro de diálogo, seleccione Permitir confirmación vacía opción.
Cierre este proyecto.
Haga clic Proyecto → SVN → Finalizar compra para ver la revisión deseada del proyecto almacenada en SVN.
Haga clic Proyecto → SVN → Desconectar el proyecto de SVN. En el cuadro de diálogo siguiente, mantenga la opción predeterminada y haga clic OK.
Guarda el proyecto.
Haga clic Git → Inicializar el repositorio de Git y selecciona una carpeta vacía en el directorio de archivos (ejemplo: Temperatura).
Haga clic Git → Compromiso completo.
Guarde el proyecto y ciérrelo.
El
*.project
puede eliminar el archivo de este proyecto. El repositorio de GitTemp
del proyecto no debe borrarse bajo ninguna circunstancia.Abra el
Main Project
proyecto de nuevo.Haga clic Git → Controles remotos para abrir el Mandos a distancia ver.
En el Controles remotos ver, hacer clic Agregar. En el Añadir nuevo mando a distancia cuadro de diálogo, especifique la URL del repositorio de Git
Temp
y especificar, por ejemplo,Temp_Remote
como el Nombre de alias.Seleccione este mando a distancia agregado y haga clic Recuperar.
Haga clic Git → Sucursales para abrir el Ramas de Git vista.
Seleccione la rama maestro/principal de
Main
, haga clic Rastrear sucursal. En el Rastrea una sucursal remota cuadro de diálogo, seleccione la rama maestro/principal delTemp_Remote
remoto que se agregó en el paso 14.Ejecuta una extracción en la rama maestro/principal del repositorio de Git Principal haciendo clic Tire con opciones en el Ramas de Git ver y seleccionar el Usa «de ellos» para los conflictos opción como Fusionar la estrategia de conflictos en el Git Pull Master cuadro de diálogo. La opción predeterminada para Estrategia de avance rápido no debe cambiarse.
Ahora haga clic Git -→ Compromiso completo. en el Realice cambios por etapas y no por etapas cuadro de diálogo, seleccione el Modificar la confirmación opción.
La revisión del proyecto SVN que se revisó al principio de esta guía ahora está almacenada en el repositorio de Git. Principal como compromiso.
En el Controles remotos vea, seleccione el
Temp
remoto y haga clic Eliminar.Guarde el
Main Project
proyecta y ciérralo.Eliminar el repositorio de Git
Temp
desde tu directorio de archivos.Si quieres transferir otra revisión del proyecto SVN al repositorio de Git, sigue estas instrucciones del paso 6 para la siguiente revisión que desees del proyecto SVN.
Transferir un proyecto SVN a Git con secuencias de comandos
Requisito: CODESYS Git versión >= 1.4.0.0
Las siguientes plantillas de script para la transferencia se muestran a continuación:
1. Guión para transferir un proyecto desde CODESYS SVN para CODESYS Git
2. Secuencia de comandos para comprobar si se ha creado o no una confirmación de Git correspondiente para cada revisión de SVN durante la transferencia
No se realizan cambios en el repositorio SVN.
Ambos scripts están pensados como plantillas que debe adaptar a los requisitos respectivos.
Guión para la transferencia de un proyecto SVN
El script transfiere todas las revisiones SVN del enlace troncal de un CODESYS SVN proyecto a la rama «maestra» de un CODESYS Git proyecto.
import os import shutil import logging """ --- inputs --- """ # URL of the SVN project you want to migrate # only migrate a single project at a time if you have multiple in your SVN repo SVN_REPO_URL = 'svn://your.svnserver.com/trunk/CodesysProjectNr1' # Starts migration at this svn revision STARTING_REVISION = 0 # Directory of the new project with the git repository NEW_PROJECT_DIR = 'C:/CodesysProjects/CodesysProjectNr1' # Name of the new project NEW_PROJECT_NAME = 'CodesysProjectNr1' # Is the project a library (otherwise will be checked out as a project) IS_LIBRARY = False # Path to the local git repository of the new project NEW_PROJECT_REPO_DIR = 'C:/CodesysProjects/CodesysProjectNr1/repo' # Path to an EMPTY temporary folder (doesn't have to exist) that can be deleted TEMP_PATH = 'C:/CodesysProjects/CodesysProjectNr1/temp' # Author of the git commits AUTHOR_NAME = 'Author Name' # E-mail address of the git commits AUTHOR_EMAIL = 'Author.Name@e-mail.com' # Name of the branch that should contain the history # Can't be named 'master' TARGET_BRANCH_NAME = 'develop' # Initial commit messages on the master branch and the target branch IC_MSG_MASTER = 'master: Initial commit.' IC_MSG_TARGET_BRANCH = 'develop: Initial commit.' # Removes the newly created project and its repository if the migration fails REMOVE_MAIN_PROJECT_ON_FAILURE = True def get_git_commit_msg(svn_log): """ Returns the commit messages that will be seen in the resulting git history Can be customized to ones demands. *svn_log* see: https://content.helpme-codesys.com/en/ScriptingEngine/ScriptSubversion.html#ScriptSubversion.LogInfo """ return 'SVN revision %d: %s' % (svn_log.revision, svn_log.message) """ --- migration script --- """ # Type extension of the project (.project / .library) PROJECT_FILE_TYPE_EXTENSION = '.library' if IS_LIBRARY else '.project' # Path to your new Git project NEW_MAIN_PROJECT_PATH = os.path.join(NEW_PROJECT_DIR, NEW_PROJECT_NAME + PROJECT_FILE_TYPE_EXTENSION) # Name of the temporarily added remote TEMP_REMOTE_NAME = 'remote1' # Temporary commit message will be overwritten/amended (put what u like) TEMP_COMMIT_MSG = 'TEMP COMMIT: This will be overwritten' def create_git_project(): """ 1. Creates a new project at *NEW_MAIN_PROJECT_PATH* 2. Initializes it in git with the repository at *NEW_PROJECT_REPO_DIR* 3. Makes an initial commit with the message *IC_MSG_MASTER* 4. Creates and switches to the target branch *TARGET_BRANCH_NAME* 5. Makes an initial commit on the target branch with the message *IC_MSG_TARGET_BRANCH* 6. Saves and closes the project """ git_project = projects.create(NEW_MAIN_PROJECT_PATH) git_project.git.init(NEW_PROJECT_REPO_DIR) git_project.git.commit_complete(IC_MSG_MASTER, AUTHOR_NAME, AUTHOR_EMAIL) git_project, git_branch = git_project.git.branch_copy(TARGET_BRANCH_NAME, checkout=True) git_project.git.commit_complete(IC_MSG_TARGET_BRANCH, AUTHOR_NAME, AUTHOR_EMAIL, bAllowEmptyCommits=True) git_project.save() git_project.close() def remove_all_children(project): """ Removes all objects that can be removed from the project *project* """ children = project.get_children(recursive=True) for child in children: try: child.remove() except Exception as ex: if not 'Object reference not set to an instance of an object.' == str(ex): logging.error(ex) def create_git_repo_from_svn_revision(svn_log): """ 1. Checks out a project from the SVN server *SVN_REPO_URL* 2. Disconnects it from SVN 3. Initiates it in git with the repository at *repo_dir* 4. Makes a commit with the message *commit_message* 4.1 See "get_git_commit_msg" to customize the commit message 5. Saves and closes the project 6. Returns the path of the project and path of the repository """ project_path = os.path.join(TEMP_PATH, 'revision_' + str(svn_log.revision) + PROJECT_FILE_TYPE_EXTENSION) repo_dir = os.path.join(TEMP_PATH, 'repo_' + str(svn_log.revision)) commit_message = get_git_commit_msg(svn_log) temp_project_name = 'revision_%d' % svn_log.revision svn_project = svn.checkout(SVN_REPO_URL, TEMP_PATH, temp_project_name, svn_log.revision, as_library=IS_LIBRARY) svn_project.svn.disconnect() svn_project.git.init(repo_dir) svn_project.git.commit_complete(commit_message, AUTHOR_NAME, AUTHOR_EMAIL) svn_project.save() svn_project.close() return project_path, repo_dir def magic_git_pull(project, temp_repo_path, svn_log): """ 1. Removes everything from the *project* (to insure svn revision and git commit match exactly) 2. Pulls from the repo at *repo_path* 4. Commits the changes with the commit message *commit_message* 5. Saves and closes the project """ remove_all_children(project) # Temp commit for fake git merge --squash project.git.commit_complete(TEMP_COMMIT_MSG, AUTHOR_NAME, AUTHOR_EMAIL, bAllowEmptyCommits=True) project.git.remote_add(TEMP_REMOTE_NAME, temp_repo_path) project.git.fetch(TEMP_REMOTE_NAME) project.git.branch_track('refs/remotes/%s/master' % TEMP_REMOTE_NAME, TARGET_BRANCH_NAME) pull_options = git.get_pull_options() pull_options.fast_forward_strategy = GitFastForwardStrategy.NoFastForward pull_options.resolve_file_conflict_strategy = GitResolveFileConflictStrategy.Theirs project, merge_result = project.git.pull(AUTHOR_NAME, AUTHOR_EMAIL, pull_options) commit_message = get_git_commit_msg(svn_log) project.git.commit_complete(commit_message, AUTHOR_NAME, AUTHOR_EMAIL, bAllowEmptyCommits=True, bAmendCommit=True) project.git.branch_unset_upstream() project.git.remote_remove(TEMP_REMOTE_NAME) project.save() project.close() def remove_repo(project_path): try: project = projects.open(project_path) project.git.de_init(True) project.close() except: pass def remove_temp_project(project_path): """ Opens the project at *project_path* and deinitializes its git repository This needs to be done because the script can't delete the repository with "shutil.rmtree" Removes the rest of the contents int the folder at *TEMP_PATH* Removes the temporary .project/.library files and their associated files """ remove_repo(project_path) try: shutil.rmtree(TEMP_PATH) os.makedirs(TEMP_PATH) except Exception as e: logging.error('Failed to delete %s. Reason: %s' % (TEMP_PATH, e)) def main(): if projects.primary is not None: projects.primary.close() create_git_project() # get the list of all revision of SVN_REPO_URL # oldest to newest # starting at revision STARTING_REVISION + 1 svn_logs = list(reversed(svn.get_log(SVN_REPO_URL))) svn_logs_to_migrate = [log for log in svn_logs if STARTING_REVISION <= log.revision] assert svn_logs_to_migrate, ('Nothing to migrate. STARTING_REVISION is greater than the newest ' 'revision in %s') % SVN_REPO_URL system.prompt_answers['LossOfDataWarning2'] = PromptResult.Yes no_project_root_dir_amount = 0 try: for svn_log in svn_logs_to_migrate: try: temp_project_path, temp_git_repo_path = create_git_repo_from_svn_revision(svn_log) # pull to your main Git project git_project = projects.open(NEW_MAIN_PROJECT_PATH) magic_git_pull(git_project, temp_git_repo_path, svn_log) # can be omitted if enough storage space is available (big performance increase) # if omitted the folder at "TEMP_PATH" needs to be deleted manually # needed storage space = (project file size + project git repository size) * revisions # example: 255.16 MB = (1.6 KB + 2.55 MB) * 100 remove_temp_project(temp_project_path) except ValueError as ve: # Early svn revisions often do not contain a codesys project if ('The URL %s is not a project root directory.' % SVN_REPO_URL) == str(ve): no_project_root_dir_amount += 1 if no_project_root_dir_amount < len(svn_logs_to_migrate): logging.info(ve) continue logging.critical(ve) raise except: if REMOVE_MAIN_PROJECT_ON_FAILURE: remove_repo(NEW_MAIN_PROJECT_PATH) for file in os.listdir(NEW_PROJECT_DIR): if file.startswith(NEW_PROJECT_NAME): os.remove(os.path.join(NEW_PROJECT_DIR, file)) raise finally: system.prompt_answers.clear() if __name__ == '__main__': main()
Secuencia de comandos para comprobar el resultado de la transferencia
El siguiente script realiza las siguientes comprobaciones:
Comprueba si hay o no una confirmación de Git correspondiente en el CODESYS Git proyecto después de la transferencia para cada revisión SVN del enlace troncal de un CODESYS SVN proyecto
Compruebe si el CODESYS proyecto de una revisión de SVN y el CODESYS el proyecto de la confirmación de Git correspondiente son idénticos
La comparación de un CODESYS el proyecto se basa en la CODESYSentorno de desarrollo donde se realizan la transferencia y la verificación.
Nota
El método habitual de creación de scripts compare_to()
en CODESYS no se comporta como se esperaba en este contexto. Por este motivo, se utiliza una solución alternativa en el script
import os import logging """ --- inputs --- """ # URL of the SVN project you want to check the migration for SVN_REPO_URL = 'svn://your.svnserver.com/trunk/CodesysProjectNr1' # Directory of the project with git repository to check PROJECT_DIR = 'C:/CodesysProjects/CodesysProjectNr1' # Name of the project to check PROJECT_NAME = 'CodesysProjectNr1' # Is the project a library (otherwise will be checked out as a project) IS_LIBRARY = False # Path to an EMPTY temporary folder (doesn't have to exist) that can be deleted TEMP_PATH = 'C:/CodesysProjects/CodesysProjectNr1/temp' # Name of the branch that should be checked TARGET_BRANCH_NAME = 'develop' """ --- check script --- """ # Type extension of the project (.project / .library) PROJECT_FILE_TYPE_EXTENSION = '.library' if IS_LIBRARY else '.project' # Path to your new Git project MAIN_PROJECT_PATH = os.path.join(PROJECT_DIR, PROJECT_NAME + PROJECT_FILE_TYPE_EXTENSION) def get_revision_from_commit_msg(msg): """ filters out the revision number from the commit message *msg* migrated SVN commits in git: git commit = 'SVN revision *revision number*: *svn commit message*' if your migrated svn commits in git are different this possibly won't work """ s_num = '' for c in msg: if c.isdigit(): s_num = s_num + c if ':' == c: break return int(s_num) def compare_changed_objects_workaround(changed_objects): """ Compares the changed objects in the *changed_objects* list by comparing their content Returns True if the objects are identical (not changed) """ for changed_object in changed_objects: if changed_object.left_object is None: return False if changed_object.right_object is None: return False if not changed_object.left_object.textual_declaration.text == changed_object.right_object.textual_declaration.text: logging.error('Compared objects are not the same:') logging.error('left: %s/%s' % (changed_object.left_object.parent.get_name(), changed_object.left_object.get_name())) logging.error(changed_object.left_object.textual_declaration.text) logging.error('right: %s/%s' % (changed_object.right_object.parent.get_name(), changed_object.right_object.get_name())) logging.error(changed_object.right_object.textual_declaration.text) logging.error('diff: ' + str(changed_object.differences)) logging.error('-----------------------------------------------------') return False return True def compare_projects(project_one, project_two): """ Compares two projects Returns True if they are identical """ comparison_result = project_one.compare_to(project_two, flags=ComparisonFlags.IGNORE_PROPERTIES) changed_objects = list(comparison_result.get_changed_objects()) if 0 == len(changed_objects): return True else: return compare_changed_objects_workaround(changed_objects) def main(): system.prompt_handling = PromptHandling.LogSimplePrompts if projects.primary is not None: projects.primary.close() git_project = projects.open(MAIN_PROJECT_PATH) git_project, git_branch = git_project.git.checkout(TARGET_BRANCH_NAME, force=True) git_logs = list(reversed(list(git_project.git.log()))) system.prompt_answers['LossOfDataWarning2'] = PromptResult.Yes checks_done = 0 try: for git_log in git_logs: if 'SVN revision ' in git_log.message_string: git_project, git_null_branch = git_project.git.checkout(git_log.sha_string) revision = get_revision_from_commit_msg(git_log.message_string) temp_project = svn.checkout(SVN_REPO_URL, TEMP_PATH, 'revision_' + str(revision), revision, as_library=IS_LIBRARY ,as_primary_project=False) if not compare_projects(git_project, temp_project): prompt_message = ("Revision %d does not equal it's corresponding git commit. " "Do you want to continue?") % revision logging.error(prompt_message) prompt_result = system.ui.prompt(prompt_message, PromptChoice.YesNo, PromptResult.No) if PromptResult.No == prompt_result: temp_project.close() break checks_done += 1 temp_project.close() finally: system.prompt_answers.clear() git_project, git_branch = git_project.git.checkout(TARGET_BRANCH_NAME) git_project.close() if checks_done: system.ui.prompt('Done', PromptChoice.OK, PromptResult.OK) else: error_msg = 'No migrated commits found. If you have custom commit messages change this script accordingly.' logging.error(error_msg) raise Exception(error_msg) if __name__ == '__main__': main()