Procedure consigliate
Ripristino di un progetto Git quando CODESYS si è bloccato durante la modifica del progetto
A seconda dell'operazione CODESYS si è bloccato in precedenza, sono disponibili le seguenti opzioni per il ripristino:
Normalmente è possibile riaprire il progetto dopo un arresto anomalo. CODESYS Git ripristina l'ultimo stato del progetto salvato internamente e riscrive il contenuto del progetto nell'archivio del progetto Git. Questo meccanismo di «failsave» considera il progetto come una fonte di dati «master». Se il progetto si è bloccato durante un'operazione di unione, non dovresti salvare immediatamente prima di continuare a lavorare dopo la riapertura, ma prima scartare tutte le modifiche (git reset --hard). Per fare ciò, puoi usare Annulla tutte le modifiche comando in Stato e messa in scena vista.
Nel caso in cui non sia più possibile aprire correttamente il progetto dopo il crash (ad esempio perché nella memoria del progetto sono finiti file completamente incompatibili), hai la seguente possibilità di ripristino: Ricaricare completamente il progetto dal repository. Per ulteriori informazioni, vedere: Ricostruisci il progetto dal repository
Trasferimento di un progetto da CODESYS SVN a CODESYS Git
Ti consigliamo vivamente di non eliminare i repository SVN dopo aver trasferito con successo i progetti su GIT in modo da poter comunque accedervi se necessario.
Suggerimento
Nel CODESYS Git nella versione 1.4.0.0 e successive, sarà disponibile un'interfaccia di scripting per il trasferimento di un progetto da CODESYS SVN a CODESYS Git.
Importante
Il comando Git git-svn
non può essere utilizzato per il trasferimento CODESYSprogetti da CODESYS SVN a CODESYS Git perché CODESYS Git utilizza il .json
formato di file, a differenza del formato di file binario di CODESYS SVN.
Nel CODESYS Git, un repository Git può gestirne solo uno CODESYS progetto. Perché un repository SVN può contenere CODESYS progetti, è necessario creare un repository Git separato per ogni progetto in un repository SVN durante il trasferimento a CODESYS Git.
Si consiglia di trasferire i singoli progetti di un repository SVN nei repository di CODESYS Git progetto per progetto.
Non è consigliabile suddividere un repository SVN in più repository SVN perché ciò può causare problemi in seguito.
I rami e i tag esistono sia in SVN che in GIT, ma sono progettati in modo diverso in questi due sistemi. Un trasferimento con
git-svn
il comando non è possibile perché questo comando non può essere utilizzato in CODESYS Git (vedi sopra).Pertanto, ci limitiamo a trasferire il trunk SVN su un ramo Git (di default «Master» o «Main»). Se necessario, i tag SVN possono essere aggiunti manualmente come tag
In questa procedura, l'ultima versione di CODESYS il progetto viene prima archiviato CODESYS SVN. Quindi la connessione a SVN viene disconnessa e viene creato un repository Git CODESYS Git viene inizializzato per il progetto. Lo svantaggio di questa procedura è che la cronologia del progetto viene persa perché solo l'ultima revisione SVN viene
Requisiti: CODESYS SVN e CODESYS Git sono installati in CODESYS. Per mezzo del Utensili → Personalizza comando, Commit completo il comando è stato aggiunto a Integrazione con Git categoria di comando in Git menu.
Aprire il CODESYS progetto che avete salvato nel repository SVN.
Clicca Progetto → SVN → Pagamento.
L'ultima revisione del progetto è stata sottoposta a verifica.
Clicca Progetto → SVN → Disconnetti il progetto da SVN.
Crea una nuova cartella vuota nella directory locale dei file del tuo computer.
Nel CODESYS, fai clic Regalo → Inizializza il repository Git e seleziona la cartella vuota creata nel passaggio precedente nella finestra di dialogo.
Clicca Git → Impegno completo.
Il progetto è ora archiviato nel repository Git locale e può essere inviato a un repository remoto, se necessario.
In questa procedura, ogni singola revisione SVN viene trasferita manualmente in un commit Git.
Requisiti: CODESYS SVN e CODESYS Git sono installati in CODESYS. Per mezzo del Utensili → Personalizza comando, Commit completo il comando è stato aggiunto a Integrazione con Git categoria di comando in Git menu.
Crea un nuovo progetto vuoto in CODESYS e assegnagli un nome, ad esempio
Main Project
.Clicca Git → Inizializza il repository Git.
Clicca Git → Impegno completo.
Clicca Git → Commettere per eseguire un commit vuoto. Effettua modifiche graduali finestra di dialogo, seleziona Consenti un commit vuoto opzione.
Chiudi questo progetto.
Clicca Progetto → SVN → Pagamento per verificare la revisione desiderata del progetto archiviata in SVN.
Clicca Progetto → SVN → Disconnetti il progetto da SVN. Nella finestra di dialogo successiva, mantieni l'opzione predefinita e fai clic OK.
Salva il progetto.
Clicca Git → Inizializza il repository Git e seleziona una cartella vuota nella directory dei file (esempio: Temperatura).
Clicca Git → Impegno completo.
Salvate il progetto e chiudetelo.
Le
*.project
il file di questo progetto può essere eliminato. Il repository GitTemp
del progetto non deve essere cancellato in nessun caso.Aprire il
Main Project
di nuovo progetto.Clicca Git → Telecomandi per aprire il Telecomandi vista.
Nel Telecomandi visualizza, fai clic Aggiungi. Aggiungi un nuovo telecomando finestra di dialogo, specifica l'URL del repository Git
Temp
e specificare, ad esempio,Temp_Remote
era il Nome alias.Seleziona questo telecomando aggiunto e fai clic su Recupera.
Clicca Git → Filiali per aprire il Filiali Git vista.
Seleziona il master/ramo principale di
Main
, fai clic Tieni traccia della filiale. Tieni traccia della filiale remota finestra di dialogo, seleziona il ramo master/principale delTemp_Remote
telecomando che è stato aggiunto nel passaggio 14.Esegui un pull sul ramo master/main del repository Git Principale facendo clic Estrai con opzioni nel Filiali Git visualizza e seleziona Usa «loro» per i conflitti opzione come Strategia di unione dei conflitti nel Git Pull Master dialogo. L'opzione predefinita per Strategia Fast Forward non dovrebbe essere cambiato.
Ora fai clic Git -→ Impegno completo. nel Effettua modifiche graduali e non graduali finestra di dialogo, seleziona il Modifica commit opzione.
La revisione del progetto SVN che è stata verificata all'inizio di questa guida è ora archiviata nel repository Git Principale come impegno.
Nel Telecomandi visualizza, seleziona
Temp
remoto e fai clic Rimuovi.Salva il
Main Project
progetto e chiudilo.Rimuovi il repository Git
Temp
dalla tua cartella dei file.Se desideri trasferire un'altra revisione del progetto SVN nel repository Git, segui queste istruzioni del passaggio 6 per la successiva revisione desiderata del progetto SVN.
Trasferimento di un progetto SVN su Git con script
Requisito: CODESYS Git versione >= 1.4.0.0
Di seguito sono visualizzati i seguenti modelli di script per il trasferimento:
1. Script per il trasferimento di un progetto CODESYS SVN a CODESYS Git
2. Script per verificare se è stato creato o meno un commit Git corrispondente per ogni revisione SVN durante il trasferimento
Non viene apportata alcuna modifica al repository SVN.
Entrambi gli script sono intesi come modelli che è necessario adattare ai rispettivi requisiti.
Script per il trasferimento di un progetto SVN
Lo script trasferisce tutte le revisioni SVN del trunk di un CODESYS SVN progetto al ramo «master» di a CODESYS Git progetto.
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()
Script per la verifica del risultato del trasferimento
Il seguente script esegue i seguenti controlli:
Controlla se c'è o meno un commit Git corrispondente nel CODESYS Git progetto dopo il trasferimento per ogni revisione SVN del trunk di a CODESYS SVN progetto
Controlla se il CODESYS progetto di una revisione SVN e il CODESYS il progetto del commit Git corrispondente sono identici
Il confronto di un CODESYS il progetto si basa sul CODESYSambiente di sviluppo in cui vengono eseguiti il trasferimento e la verifica.
Nota
Il solito metodo di scripting compare_to()
nel CODESYS non si comporta come previsto in questo contesto. Per questo motivo, nello script viene utilizzata una soluzione alternativa
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()