remota - git push
git comando para hacer una rama como otra (7)
Intento tomar una rama con cambios y traerla de vuelta para que sea idéntica a la corriente ascendente desde la que divergió. Los cambios son locales y se han enviado a github, por lo que ni git reset
ni git rebase
son realmente viables, ya que cambian el historial, lo cual es malo con una rama que ya se ha enviado.
También probé la git merge
con varias estrategias, pero ninguna de ellas deshace los cambios locales, es decir, si agregué un archivo, una fusión podría hacer que otros archivos vuelvan a estar en línea, pero aún tendré ese archivo que el anterior no no tiene.
Podría simplemente crear una nueva rama desde el inicio, pero realmente me gustaría una fusión que en términos de historial de revisión aplique todos los cambios para tomar mi rama y hacerla idéntica a la anterior, de modo que pueda impulsar ese cambio de forma segura sin historia de traición ¿Hay tal comando o serie de comandos?
Me parece que solo necesitas hacer:
$ git reset --hard origin/master
Si no hay ningún cambio para impulsar en sentido ascendente, y usted simplemente quiere que la rama ascendente sea su rama actual, esto hará eso. No es dañino hacer esto localmente, pero perderá cualquier cambio local ** que no haya sido empujado a dominar.
** En realidad, los cambios siguen vigentes si los ha confirmado localmente, ya que las confirmaciones aún se guardarán en su git reflog
, generalmente durante al menos 30 días.
Otra simulación para git merge -s theirs ref-to-be-merged
:
git merge --no-ff -s ours ref-to-be-merged # enforce a merge commit; content is still wrong
git reset --hard HEAD^2; git reset --soft HEAD@{1} # fix the content
git commit --amend
Una alternativa al doble reinicio sería aplicar el parche inverso:
git diff --binary ref-to-be-merged | git apply -R --index
Pesado, pero qué demonios, ¿qué puede salir mal?
- Mira la rama X que quieres que se parezca a la Y
- cp -r .git / tmp
- Mira la rama Y
- rm -rf .git && cp -r /tmp/.git.
- Comprometerse y empujar cualquier diferencia
- HECHO.
Podría fusionar su rama ascendente con su rama de desarrollo, con un controlador de combinación personalizado "keepTheirs" :
Ver "se necesita" git merge -s theirs
"- pero sé que no existe ".
En su caso, solo se requerirá un keepTheirs
y un script keepTheirs
como:
mv -f $3 $2
exit 0
git merge --strategy=theirs
Simulation # 1
Se muestra como una combinación, con el flujo ascendente como primer padre.
Jefromi menciona (en los comentarios) la merge -s ours
, al fusionar su trabajo en el Jefromi ascendente (o en una rama temporal comenzando desde el origen), y luego reenviar rápidamente su rama al resultado de esa combinación:
git checkout -b tmp origin/upstream
git merge -s ours downstream # ignoring all changes from downstream
git checkout downstream
git merge tmp # fast-forward to tmp HEAD
git branch -D tmp # deleting tmp
Esto tiene el beneficio de registrar el antecesor en sentido ascendente como primer padre, de modo que la fusión significa "absorber esta rama de tema desactualizada" en lugar de "destruir esta rama de tema y reemplazarla por la de flujo ascendente" .
(Editar 2011):
Este flujo de trabajo ha sido reportado en esta publicación del blog por el OP :
¿Por qué quiero esto de nuevo?
Siempre y cuando mi repositorio no tuviera nada que ver con la versión pública, todo estaba bien, pero como ahora quisiera tener la posibilidad de coloidal en WIP con otros miembros del equipo y colaboradores externos, quiero asegurarme de que mis sucursales públicas sean confiable para que otros se ramifiquen y se desconecten, es decir, que no haya más bases de datos reestablecidas y restablecer en cosas que he transferido a la copia de seguridad remota, ya que ahora está en GitHub y en público.
Entonces eso me deja con cómo debo proceder.
El 99% del tiempo, mi copia irá al maestro de nivel superior, por lo que quiero trabajar con mi maestro y avanzar en la fase ascendente la mayor parte del tiempo.
Pero de vez en cuando, lo que tengo enwip
quedará invalidado por lo que entra aguas arriba y abandonaré una parte de miwip
.
En ese punto, quiero volver a sincronizar a mi maestro con el flujo ascendente, pero no destruir ningún punto de compromiso en mi maestro enviado públicamente. Es decir, quiero una fusión con upstream que termine con el conjunto de cambios que hace que mi copia sea idéntica a la anterior .
Y eso es lo que segit merge --strategy=theirs
debería hacer.
git merge --strategy=theirs
Simulation # 2
Se muestra como una combinación, con el nuestro como el primer padre.
(propuesto por jcwenger )
git checkout -b tmp upstream
git merge -s ours thebranch # ignoring all changes from downstream
git checkout downstream
git merge --squash tmp # apply changes from tmp but not as merge.
git rev-parse upstream > .git/MERGE_HEAD #record upstream 2nd merge head
git commit -m "rebaselined thebranch from upstream" # make the commit.
git branch -D tmp # deleting tmp
git merge --strategy=theirs
Simulation # 3
Esta entrada del blog menciona :
git merge -s ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend
a veces desea hacer esto, y no porque tenga "basura" en su historial, sino quizás porque desea cambiar la línea de base para el desarrollo en un repositorio público donde debe evitarse el rebase .
git merge --strategy=theirs
Simulation # 4
(misma publicación en el blog)
Alternativamente, si desea mantener las ramas ascendentes locales rápidamente reenviables, un posible compromiso es trabajar con la comprensión de que para sid / inestable, la rama ascendente puede restablecerse o reajustarse ocasionalmente (en función de los eventos que finalmente están fuera de servicio). de su control en el lado del proyecto aguas arriba).
Esto no es un gran problema y trabajar con esa suposición significa que es fácil mantener la sucursal upstream local en un estado donde solo se necesitan actualizaciones rápidas.
git branch -m upstream-unstable upstream-unstable-save
git branch upstream-unstable upstream-remote/master
git merge -s ours upstream-unstable
git diff --binary ref-to-be-merged | git apply -R --index --exclude="debian/*"
git commit -F .git/COMMIT_EDITMSG --amend
git merge --strategy=theirs
Simulation # 5
(propuesto por Barak A. Pearlmutter ):
git checkout MINE
git merge --no-commit -s ours HERS
git rm -rf .
git checkout HERS -- .
git checkout MINE -- debian # or whatever, as appropriate
git gui # edit commit message & click commit button
git merge --strategy=theirs
Simulation # 6
(propuesto por el mismo Michael Gebetsroither ):
Michael Gebetsroither intervino, alegando que estaba "engañando";) y dio otra solución con los comandos de plomería de bajo nivel:
(No sería genial si no fuera posible con comandos de git only, todo en git con diff / patch / apply no es una solución real;).
# get the contents of another branch
git read-tree -u --reset <ID>
# selectivly merge subdirectories
# e.g superseed upstream source with that from another branch
git merge -s ours --no-commit other_upstream
git read-tree --reset -u other_upstream # or use --prefix=foo/
git checkout HEAD -- debian/
git checkout HEAD -- .gitignore
git commit -m ''superseed upstream source'' -a
Puedes hacer esto bastante fácilmente ahora:
$ git fetch origin
$ git merge origin/master -s recursive -Xtheirs
Esto hace que su repositorio local esté sincronizado con el origen y preserva el historial.
También hay una manera con poca ayuda del comando de fontanería: en mi humilde opinión, la más directa. Digamos que quiere emular "theirs" para el caso de 2 ramas:
head1=$(git show --pretty=format:"%H" -s foo)
head2=$(git show --pretty=format:"%H" -s bar)
tree=$(git show --pretty=format:"%T" -s bar)
newhead=$(git commit-tree $tree -p $head1 -p $head2 <<<"merge commit message")
git reset --hard $newhead
Esto combina un número arbitrario de cabezales (2 en el ejemplo anterior) utilizando el árbol de uno de ellos (barra en el ejemplo anterior, proporcionando el árbol ''theirs''), sin tener en cuenta los problemas de diff / file (commit-tree es un comando de bajo nivel, por lo que no se preocupa por eso). Tenga en cuenta que head puede ser solo 1 (tan equivalente a cherry-pick con "theirs").
Tenga en cuenta que la cabeza padre que se especifica primero, puede influir en algunas cosas (véase, por ejemplo, el primer padre del comando git-log), así que tenlo en cuenta.
En lugar de git-show, se puede usar cualquier otra cosa capaz de generar hash de compilación y de compilación, cualquiera que sea el que se use para analizar (cat-file, rev-list, ...). Puede seguir todo con el compromiso de git --mendar para embellecer interactivamente el mensaje de compromiso.
cambiar a la rama ascendente remota y hacer una git merge
con la estrategia de combinación establecida en la ours
.
git checkout origin/master
git merge dev --strategy=ours
git commit ...
git push
Toda la historia seguirá estando presente, pero tendrás una fusión adicional. Lo importante aquí es comenzar desde la versión en la que quieres estar y fusionar la ours
con la rama en la que github se encuentra actualmente.