Enviar una solicitud de extracción en GitHub solo para la última confirmación

280

Bifurqué un proyecto en github y estoy haciendo cambios con éxito a mi maestro local y presionando para que se origine en github. Quiero enviar una solicitud de extracción, pero solo quiero incluir la última confirmación. La interfaz de usuario de solicitud de extracción en github.com muestra las últimas 9 confirmaciones y no sé cómo filtrar eso.

¿Estaba tratando de entender si debería crear una nueva sucursal local, verificar eso y de alguna manera restablecer o cambiar la base a upstream? Luego, ¿aplico mi último commit de mi maestro por id a la nueva sucursal local y lo uso para la solicitud de extracción?

Estoy tratando de entender bien los conceptos y encontrar las líneas de comando correctas para hacer lo que necesito.

Kevin Hakanson
fuente
¿Y qué sucede si haces una solicitud de extracción con todos los otros commits? ¿Pensé que git es lo suficientemente inteligente como para ignorar (o aprobar) las confirmaciones que ya realizó?
jayarjo
3
Presumiblemente, el upstream aún no ha aceptado, o no quiere, los compromisos que intervienen.
Michael Scott Cuthbert
@jayarjo Por ejemplo, hice otros cambios que no quiero enviar en sentido ascendente. Los cambios en git ignoran el repositorio principal no serán necesarios, por ejemplo. Nada fácil con git.
Martin
Relacionado: Algunos buenos detalles sobre cómo las solicitudes de extracción son diferentes en Git (el software) y GitHub (el servicio web)
RBT

Respuestas:

302

Básicamente, debe crear una nueva sucursal y seleccionar los commits que desea agregar.

Nota: es posible que los necesite antes de los comandos de pago / selección de cereza

git remote add upstream <git repository>

git remote update

git checkout -b <new-branch-name> upstream/master

git cherry-pick <SHA hash of commit>

git push origin <new-branch-name>

Luego, verá una <new-branch-name>rama en github, cambiará a ella y podrá enviar la solicitud de extracción con los cambios que desee.

Kevin Hakanson
fuente
32
También necesito git remote add upstream <git repository>y git remote updateantes de ejecutar git checkout -b upstream upstream / master.
plainjimbo
66
Esto funciona, pero no es como se supone que debe hacerlo, porque ahora su rama ascendente y ascendente / maestra son diferentes y siempre serán diferentes si fusionar su solicitud de extracción no es lo primero que hace. Por esa razón, debería preferir hacer stackoverflow.com/a/5256304/1904815 .
JonnyJD
2
Para elaborar: Este no es un problema técnico, sino lógico. Cuando desee hacer algo con el flujo ascendente (como fusionarse desde allí) debe agregar una rama "flujo ascendente real" o restablecer su flujo ascendente (sin dejar rama local para su solicitud de extracción de cambios adicionales).
JonnyJD
15
¿Por qué demonios necesito una rama adicional, solo para crear un RP para una sola línea de código modificada? ¿Alguien en github pensó esto?
CodeManX
2
@ JonHanna No ... ¿por qué tienes que fusionar una rama? ¿Por qué no puedes fusionar un commit?
Kevin Krumwiede
57

Cree una nueva rama a partir de la última confirmación, que también está en el repositorio de origen:

git branch new-branch origin/master
git checkout new-branch

Luego, use git cherry-pickpara obtener la confirmación única para la que desea la solicitud de extracción. Si se llama a la rama con esta confirmación featurey la confirmación que desea es la última confirmación en esta rama, esto será

git cherry-pick feature

Suponiendo que este parche se aplica sin conflicto, ahora tiene una rama para la cual puede hacer su solicitud de extracción.

En un segundo paso, ahora debe decidir qué hacer con su featuresucursal. Si aún no ha publicado sus cambios en esta rama, el mejor procedimiento es probablemente volver a crear esta rama en una nueva rama (y eliminar la última confirmación, si esto no se hace automáticamente git rebase).

Lars Noschinski
fuente
Recibo este mensaje después de la selección de cerezas. no se agrega nada para confirmar, pero los archivos no rastreados están presentes (use "git add" para rastrear). Todo está en mi maestro, pero necesito hacer mi rama desde la parte superior.
Kevin Hakanson
55
Si featureya está comprometido origin/master, no sucede nada durante cherry-pick. La nueva rama debe ser de upstream/master(es decir, la respuesta de Kevin Hakanson)
ohho
26

Terminé en una situación en la que había bifurcado un tenedor y quería enviar una solicitud de extracción al proyecto original.

Yo tenía:

  • proyecto_original
  • forked_project (creado a partir del proyecto original en SHA: 9685770)
  • my_fork (creado a partir del proyecto bifurcado en SHA: 207e29b)
  • un commit en mi fork (SHA: b67627b) que quería enviar al proyecto original

Para hacer esto, yo:

  1. creó una nueva sucursal del SHA donde se bifurcó el proyecto original
  2. sacó todo del proyecto original
  3. Cherry eligió la confirmación que quería enviar como solicitud de extracción
  4. empujó todo a github

Los comandos git eran algo como:

  1. git branch my-feature-request 9685770
  2. git checkout my-feature-request
  3. git pull https://github.com/original_project/original_project.git
  4. git cherry-pick b67627b
  5. git push origin my-feature-request

Luego elegí my-feature-request como la rama para mi solicitud de extracción del proyecto original.

John Naegle
fuente
6

Esto casi funcionó para mí:

git checkout -b upstream upstream/master

git cherry-pick <SHA hash of commit>

git push origin upstream

La única diferencia fue esta:

git push origin upstream:upstream

Necesitaba cambiar esa última línea para que git push hiciera la rama ascendente en mi repositorio de GitHub para poder hacer relaciones públicas a partir de ella.

hi_tech_lowlife
fuente
5

Ya había hecho la confirmación que quería poder aislar como una solicitud de extracción de nuevo en la rama actual.

Entonces revisé una nueva sucursal

git checkout -b isolated-pull

Y aquí es donde mi solución difiere de @Kevin Hakanson's , ya que necesito restablecer esta rama al lugar en la historia que quiero diferenciar de

git reset --hard [sha-to-diff-by]

Y seleccione el compromiso desde el que quiero crear una solicitud de extracción aislada

git cherry-pick [my-isolated-commit-sha]

Finalmente empujarlo hacia el control remoto

git push origin isolated-pull

Y tirar solicitud dat shi.

irbanana
fuente
1

La solución para crear una nueva rama (temporal), seleccionar y crear la solicitud de extracción para esa rama no me satisfizo. No quería cambiar mi repositorio para hacer un conjunto de confirmaciones disponibles, así que se me ocurrió la siguiente alternativa:

Primero cree archivos de parche para todos los commits de interés:

git format-patch -1 <sha>

Si el compromiso de interés es el último que puede usar HEADen su lugar <sha>.

Ahora, puede enviar los parches al responsable del repositorio de origen, que puede aplicarlos:

git branch new-branch <master or some older commit where the fork diverged>
git checkout new-branch

git am < <the patch>
...

git checkout master
git merge new-branch

Finalmente, esto debería verse igual que si una rama temporal se fusionara por una solicitud de extracción, pero sin tener esa rama adicional en el repositorio de fork.

Johannes Jendersie
fuente
0

Basado en la respuesta de @ kevin-hakanson, escribí este pequeño script bash para facilitar este proceso. Agregará el repositorio ascendente si aún no existe (solicitándole la URL) y luego solicitará tanto el nombre de la nueva rama para crear como la etiqueta / SHA del compromiso de selección de cereza en esa rama. Comprueba en qué rama o confirmación se encuentra actualmente y luego guarda los cambios para que pueda verificar la nueva rama. La estrategia de fusión mantiene los cambios del compromiso seleccionado. Después de empujar la nueva rama a origin(se supone que es el nombre de su repositorio remoto), la rama o confirmación en la que estaba antes se desprotege nuevamente y sus cambios anteriores salieron de la reserva.

if ! git remote | grep -q upstream; then
    read -p "Upstream git repo URL: " upstream
    git remote add upstream $upstream
    git remote update
fi

read -p "Feature branch name: " feature_branch
# note: giving "master" is the same as giving the SHA it points to
read -p "SHA of commit to put on branch: " sha

current_branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$current_branch" == "HEAD" ]; then
    # detached HEAD; just get the commit SHA
    current_branch=$(git rev-parse --short HEAD)
fi
git stash
git checkout -b $feature_branch upstream/master
git cherry-pick --strategy=recursive -X theirs $sha
git push origin $feature_branch
git checkout $current_branch
git stash pop

(Esto me ha funcionado en un par de pruebas simples, pero no soy un programador de bash o un experto en git, ¡así que avíseme si hay casos que me he perdido que podrían automatizarse mejor!)

Nathan
fuente