He estado usando Perforce durante varios años. Me gustaría cambiar para usar git para mi código personal, pero todos los tutoriales de git que he visto asumen que eres un control de fuente completo n00b (lo que los hace increíblemente tediosos) o que estás acostumbrado svn (que no soy).
Conozco p4 y también entiendo la idea detrás de un sistema de control de fuente distribuido (así que no necesito un argumento de venta, gracias). Lo que me gustaría es una tabla de traducción del comando p4 a comandos git equivalentes, así como los comandos "no se puede vivir sin" que no tienen equivalente p4.
Como sospecho que cada usuario de p4 usa un subconjunto diferente de p4, estas son algunas de las cosas que hago regularmente en p4 que me gustaría poder hacer en git que no son inmediatamente obvias en los documentos que he visto :
- cree varias listas de cambios pendientes en un solo cliente. (
p4 change
) - editar una lista de cambios pendiente. (también
p4 change
) - ver una lista de todas mis listas de cambios pendientes (
p4 changes -s pending
) - lista de todos los archivos modificados en mi cliente (
p4 opened
) o en una lista de cambios pendiente (p4 describe
) - ver una diferencia de una lista de cambios pendiente (uso un script de envoltura para esto que usa
p4 diff
yp4 describe
) - para un archivo determinado, vea qué listas de cambios enviadas afectaron qué líneas (
p4 annotate
) - para un archivo dado, vea una lista de las descripciones de las listas de cambios que afectaron al archivo (
p4 log
) - enviar una lista de cambios pendiente (
p4 submit -c
) - abortar una lista de cambios pendiente (
p4 revert
)
Muchos de estos giran en torno a "listas de cambios". "lista de cambios" es la terminología p4. ¿Cuál es el término equivalente de git?
Parece que las ramas podrían ser lo que usan los usuarios de git en lugar de lo que p4 llama listas de cambios. Un poco confuso, ya que p4 también tiene algo llamado rama, aunque parecen ser conceptos vagamente relacionados. (Aunque siempre pensé que el concepto de rama de p4 era bastante extraño, es diferente una vez más del concepto clásico de RCS de una rama).
De todos modos ... no estoy seguro de cómo lograr lo que normalmente hago en las listas de cambios p4 con las ramas de git. En p4 puedo hacer algo como esto:
$ p4 edit a.txt
$ p4 change a.txt
Change 12345 created.
En este punto, tengo una lista de cambios que contiene un.txt. Puedo editar la descripción y seguir trabajando sin enviar la lista de cambios. Además, si resulta que necesito realizar algunos cambios en algunos otros archivos, como por ejemplo, una corrección de errores en alguna otra capa del código, puedo hacerlo en el mismo cliente:
$ p4 edit z.txt
$ p4 change z.txt
Change 12346 created.
Ahora tengo dos listas de cambios separadas en el mismo cliente. Puedo trabajar en ellos simultáneamente y no necesito hacer nada para "cambiar entre ellos". Cuando llegue el momento de comprometerse, puedo enviarlos por separado:
$ p4 submit -c 12346 # this will submit the changes to z.txt
$ p4 submit -c 12345 # this will submit the changes to a.txt
No puedo encontrar la forma de replicar esto en git. De mis experimentos, no parece que git add
esté asociado con la rama actual. Por lo que puedo decir, cuando git commit
voy a confirmar todos los archivos que hice, git add
sin importar en qué rama estaba en ese momento:
$ git init
Initialized empty Git repository in /home/laurence/git-playground/.git/
$ ls
a.txt w.txt z.txt
$ git add -A .
$ git commit
Initial commit.
3 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 a.txt
create mode 100644 w.txt
create mode 100644 z.txt
$ vi a.txt z.txt
2 files to edit
$ git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: a.txt
# modified: z.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git branch aardvark
$ git checkout aardvark
M a.txt
M z.txt
Switched to branch 'aardvark'
$ git add a.txt
$ git checkout master
M a.txt
M z.txt
Switched to branch 'master'
$ git branch zebra
$ git checkout zebra
M a.txt
M z.txt
Switched to branch 'zebra'
$ git add z.txt
$ git status
# On branch zebra
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a.txt
# modified: z.txt
#
$ git checkout aardvark
M a.txt
M z.txt
Switched to branch 'aardvark'
$ git status
# On branch aardvark
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a.txt
# modified: z.txt
En este ejemplo, las ramas de oso hormiguero y cebra parecen contener exactamente el mismo conjunto de cambios y, según el resultado git status
, parece que hacer una confirmación en cualquiera de ellas tendrá el mismo efecto. ¿Estoy haciendo algo mal?
Respuestas:
No he usado forzosamente mucho, por lo que esta puede no ser exactamente una traducción 1: 1. Por otra parte, los sistemas de control de código fuente distribuidos como git y mercurial tienen un flujo de trabajo diferente de todos modos, por lo que realmente no hay (y no debería haber) una traducción 1: 1. De todos modos, aquí va:
Cree varias listas de cambios pendientes -> Utilice ramas en su lugar. En git, las ramas son ligeras y rápidas, tardan menos de un segundo en crearse y normalmente menos de dos segundos en fusionarse. No tenga miedo de ramificar y rebase a menudo.
O hazlo todo en una sola línea:
Vea una lista de todas las listas de cambios pendientes -> Dado que el equivalente a varias listas de cambios pendientes son múltiples ramas, simplemente vea las ramas:
Si también desea ver las ramas remotas:
Se considera una buena práctica eliminar inmediatamente una rama después de una fusión exitosa para que no tenga que hacer un seguimiento de qué rama está pendiente de fusionarse y cuáles ya se fusionaron.
Enumere todos los archivos modificados -> Para una única "lista de cambios" pendiente en una rama específica, git tiene un concepto de índice o caché. Para confirmar un cambio, primero debe agregar archivos a este índice. Esto le permite seleccionar manualmente qué grupo de archivos representa un único cambio o ignorar los archivos irrelevantes. Para ver el estado de los archivos que se agregan o no a este índice, simplemente haga lo siguiente:
Ver una diferencia de una lista de cambios pendiente -> Hay dos partes en esto. Primero para ver una diferencia entre el directorio de trabajo y el índice:
Pero si desea saber la diferencia entre lo que está escribiendo ahora y la última confirmación, entonces realmente está pidiendo una diferencia entre el directorio de trabajo + índice y el HEAD:
Para un archivo dado, vea qué listas de cambios enviadas afectaron qué líneas -> Esto es fácil:
o incluso mejor, si se encuentra en un entorno de ventanas:
Git gui tarda más en analizar el archivo (fue escrito en tcl en lugar de C) pero tiene muchas características interesantes, incluida la capacidad de "viajar en el tiempo" al pasado haciendo clic en un ID de confirmación. Solo desearía que implementaran una función para "viajar en el tiempo" al futuro para poder averiguar cómo se resolverá finalmente un error determinado ;-)
Para un archivo dado, vea una lista de las descripciones de las listas de cambios que afectaron al archivo -> también es fácil:
Pero git log es una herramienta mucho más poderosa que esta. De hecho, la mayoría de mis scripts personales se combinan con git log para leer el repositorio. Lea la página del manual.
Envíe una lista de cambios pendiente -> También es fácil:
Vea mi respuesta a una pregunta anterior para ver mi flujo de trabajo típico de git: Aprender Git. Necesito saber si estoy en el camino correcto
Si sigue el flujo de trabajo que describí, encontrará herramientas como gitk mucho más valiosas, ya que le permite ver claramente los grupos de cambios.
Respuesta adicional:
Git es muy flexible y hay varias formas de hacer lo que describe. Lo que debe recordar es comenzar siempre una nueva rama para cada función en la que esté trabajando. Esto significa que la rama maestra no se toca, por lo que siempre puede volver a ella para corregir errores. Trabajar en git one casi siempre debería comenzar con:
Ahora puede editar el archivo a.txt. Para trabajar simultáneamente en otra función, haga lo siguiente:
Ahora puede editar el archivo z.txt. Para volver a un.txt:
Pero espera, hay cambios en new-feature-z y git no te permitirá cambiar de rama. En este punto, tiene dos opciones. El primero es el más simple, confirma todos los cambios en la rama actual:
Esto es lo que recomiendo. Pero si realmente no está listo para enviar el código, puede guardarlo temporalmente:
Ahora puede cambiar a la rama new-feature-a. Para volver al código en el que estaba trabajando, simplemente saque el alijo:
Cuando todo esté hecho, vuelva a fusionar todos los cambios en el maestro:
Debido a que las fusiones son tan rápidas y fáciles (fáciles porque los conflictos son muy raros y la resolución de conflictos, cuando ocurre uno, no es demasiado difícil) usamos ramas en git para todo.
Aquí hay otro ejemplo de un uso común de ramas en git que no ve en otras herramientas de control de código fuente (excepto quizás mercurial):
¿Necesita seguir cambiando sus archivos de configuración para reflejar su entorno de desarrollo? Luego usa una rama:
Ahora edite sus archivos de configuración en su editor favorito y luego realice los cambios:
Ahora, cada nueva rama puede comenzar desde la rama dev-config en lugar de la maestra:
Una vez que haya terminado, elimine las ediciones en dev-config de new-feature-branch usando la rebase interactiva:
Elimine las confirmaciones que no desea y luego guárdelas. Ahora tiene una rama limpia sin ediciones de configuración personalizadas. Es hora de volver a fusionarse con el maestro:
Cabe señalar que la eliminación de ediciones
git rebase -i
incluso funciona cuando todos los cambios ocurren en el mismo archivo. Git recuerda los cambios, no el contenido del archivo *.* nota: en realidad, técnicamente no es del todo cierto, pero como usuario eso es lo que se siente
Más respuesta adicional:
Entonces, a partir de sus comentarios, parece que desea que existan dos ramas simultáneamente para que pueda probar cómo funciona el código combinado. Bueno, esta es una buena forma de ilustrar el poder y la flexibilidad de las sucursales.
Primero, unas palabras sobre la implicación de la ramificación barata y el historial modificable en su flujo de trabajo. Cuando usaba CVS y SVN, siempre era un poco reacio a comprometerme. Eso es porque cometer un código inestable inevitablemente arruinaría el código de trabajo de otras personas. Pero con git perdí ese miedo. Eso es porque en git otras personas no obtendrán mis cambios hasta que los fusione para dominarlos. Así que ahora me encuentro cometiendo código cada 5 líneas que escribo. No necesitas una previsión perfecta para comprometerte. Solo necesita cambiar su forma de pensar: commit-to-branch == add-to-changeset, merge-to-master == commit-changeset.
Entonces, volvamos a los ejemplos. Así es como lo haría yo. Digamos que tienes una rama
new-feature-z
y quieres probarlanew-feature-a
. Simplemente crearía una nueva rama para probarlo:Ahora puedes probar. Si necesita modificar algo para que feature-z funcione con feature-a, hágalo. Si es así, puede fusionar los cambios en la rama correspondiente. Úselo
git rebase -i
para eliminar los cambios irrelevantes de la combinación.Alternativamente, también puede usar git rebase para cambiar temporalmente la base de new-feature-z para que apunte a new-feature-a:
Ahora se modifica el historial de la rama para que new-feature-z se base en new-feature-a en lugar de master. Ahora puedes probar. Cualquier cambio cometido en esta rama pertenecerá a la rama new-feature-z. Si necesita modificar new-feature-a, simplemente cambie de nuevo a ella y la rebase para obtener los nuevos cambios:
Cuando haya terminado, simplemente vuelva a establecer la base en el maestro para eliminar los cambios de la nueva función a:
No tenga miedo de comenzar una nueva rama. No tenga miedo de comenzar una rama desechable. No tenga miedo de tirar ramas. Y dado que fusionar == enviar y confirmar == agregar al conjunto de cambios, no tenga miedo de comprometerse a menudo. Recuerde, la confirmación es la herramienta de deshacer definitiva de un desarrollador.
Ah, y otra cosa, en git las ramas eliminadas todavía existen en su repositorio. Entonces, si ha eliminado accidentalmente algo que luego se da cuenta de que es útil después de todo, siempre puede recuperarlo buscando en el historial. Así que no tengas miedo de tirar ramas.
fuente
No tengo suficiente experiencia en p4 para producir una hoja de trucos real, pero hay al menos algunas similitudes a las que recurrir. Un "conjunto de cambios" p4 es un "compromiso" de git.
Los cambios en su espacio de trabajo local se agregan al "índice" con
git add
, y el índice luego se confirmagit commit
. Entonces, el índice es su lista de cambios pendiente, para todos los efectos.Observa los cambios con
git diff
ygit status
, dondegit diff
generalmente muestra los cambios entre el espacio de trabajo y el índice, perogit diff --cached
muestra los cambios entre el índice y el repositorio (= su lista de cambios pendiente).Para obtener información más detallada, recomiendo http://progit.org/book/ . Dado que conoce el control de versiones en general, probablemente pueda leer mucho y extraer la información específica de git ...
fuente
Sufro como tú con la falta del concepto de "lista de cambios" que no es exactamente lo mismo que las ramas de git.
Escribiría un pequeño script que creará un archivo de lista de cambios con la lista de archivos en esa lista de cambios.
Otro comando para enviar solo una determinada lista de cambios simplemente llamando a git commit -a @ change_list_contents.txt y luego "git commit"
Espero que ayude, Elias
fuente
Existe una alternativa más ligera en git que podría formar parte de su flujo de trabajo; usando el área de preparación de git.
A menudo solo hago cambios y luego los envío como varias confirmaciones (por ejemplo, agrego declaraciones de depuración, refactorización, realmente corrijo un error). En lugar de configurar sus listas de cambios forzosamente, luego hacer cambios y luego enviarlos, puede simplemente hacer sus cambios y luego elegir cómo enviarlos (opcionalmente usando el área de preparación de git).
Puede confirmar archivos particulares desde la línea de comando con:
O preparar explícitamente los archivos primero:
git gui te permitirá seleccionar líneas o trozos desde dentro de los archivos para crear una confirmación en el área de preparación. Esto es muy útil si tiene cambios en un archivo que desea que estén en diferentes confirmaciones. Haber pasado de git a forzosamente y esto es algo que realmente extraño.
Hay una pequeña advertencia a tener en cuenta con este flujo de trabajo. Si realiza los cambios A y B en un archivo, pruebe el archivo, luego confirme A, entonces no ha probado esa confirmación (independientemente de B).
fuente
Esto no responde específicamente a su pregunta, pero no sé si sabe que una versión de force para 2 usuarios y 5 espacios de trabajo se puede descargar y utilizar gratuitamente desde el sitio web de force .
De esta forma puede utilizar forzosamente en casa para sus proyectos personales si lo desea. La única molestia son los 5 espacios de trabajo que pueden ser un poco limitantes, pero es bastante increíble tenerlos necesariamente disponibles para uso doméstico.
fuente
Habiendo usado tanto Perforce como git de manera bastante extensa, solo hay una forma que puedo ver para acercarme a las listas de cambios de Perforce con git.
Lo primero que hay que entender es que para implementar correctamente esta funcionalidad en git de tal manera que no sea un kluge completo, por ejemplo, intentar calzarlo en ramas, requeriría el siguiente cambio: git requeriría múltiples áreas de preparación para una sola rama .
Las listas de cambios de Perforce permiten un flujo de trabajo que simplemente no tiene equivalente en git. Considere el siguiente flujo de trabajo:
Si intenta hacer esto usando ramas en git, terminará con dos ramas, una de las cuales tiene los cambios en el archivo
A
, la otra tiene los cambios en el archivoB
, pero no hay un lugar donde pueda ver los cambios en ambos archivosA
yB
en al mismo tiempo.La aproximación más cercana que puedo ver es a utilizar
git add . -p
y luego usar las'a'
y'd'
sub-comandos para seleccionar o rechazar archivos enteros. Sin embargo, eso no es exactamente lo mismo, y la diferencia aquí proviene de una disparidad fundamental en el modus operandi general de los dos sistemas.Git (y subversion, no es que importe para esta discusión) permiten cambiar un archivo sin decirle a nadie sobre esto antes de tiempo. Simplemente cambia un archivo y luego deja que git lo solucione todo cuando confirmes los cambios. Perforce requiere que usted revise activamente un archivo antes de que se permitan los cambios, y es por esta razón que las listas de cambios deben existir. En esencia, Perforce requiere que agregue un archivo al índice antes de cambiarlo. De ahí la necesidad de múltiples listas de cambios en Perforce, y también la razón por la que git no tiene equivalente. Simplemente no los necesita.
fuente
Con Git 2.27 (Q2 2020), "
git p4
" aprendí cuatro nuevos ganchos y también "--no-verify
" la opción de omitirlos (y el "p4-pre-submit
" gancho existente ).Consulte la confirmación 1ec4a0a , la confirmación 38ecf75 , la confirmación cd1e0dc (14 de febrero de 2020) y la confirmación 4935c45 , la confirmación aa8b766 , la confirmación 9f59ca4 , la confirmación 6b602a2 (11 de febrero de 2020) de Ben Keene (
seraphire
) .(Combinado por Junio C Hamano -
gitster
- en el compromiso 5f2ec21 , 22 de abril de 2020)Antes de Git 2.28 (tercer trimestre de 2020),
--prepare-p4-only
se supone que la opción " " se detiene después de reproducir un conjunto de cambios, pero continúa (¿por error?)Consulte la confirmación 2dfdd70 (12 de mayo de 2020) de Ben Keene (
seraphire
) .(Combinado por Junio C Hamano -
gitster
- en el compromiso 7a8fec9 , 02 de junio de 2020)fuente