Was ist der einfachste Weg, eine einzelne Datei festzuschreiben und zu pushen, während andere Änderungen in Ruhe gelassen werden?


72

Ich bin relativ neu bei Mercurial und mein Team probiert es gerade als Ersatz für Subversion aus.

Wie kann ich eine einzelne Datei festschreiben und in ein anderes Repository übertragen, während andere Änderungen in meinem Arbeitsverzeichnis nicht festgeschrieben werden (oder zumindest nicht in das andere Repository übertragen werden)?

Dies geschieht bei Datenbankmigrationen. Wir möchten die Migration auf die Quellcodeverwaltung übertragen, damit ein DBA sie anzeigen und bearbeiten kann, während wir an den Codeänderungen arbeiten, die mit dieser Datenbankmigration einhergehen. Die Änderungen sind noch nicht fertig, daher möchten wir nicht alle herausschieben.

In Subversion würde ich einfach tun:

svn add my_migration.sql  
# commit only the migration, but not the other files I'm working on
svn commit -m "migration notes" my_mygration.sql

und vor Ort weiterarbeiten.

Dies funktioniert mit mercurial nicht, wenn ich es in das andere Repository verschiebe. Wenn es Änderungen gibt, die ich nicht heruntergezogen habe, möchte ich, dass ich sie herunterziehe, zusammenführe und diese Zusammenführung festschreibe das Repository. Commits nach einer Zusammenführung ermöglichen es Ihnen nicht, Dateien wegzulassen, sodass Sie gezwungen sind, alles in Ihrem lokalen Repository festzuschreiben.

Das Einfachste, was ich herausfinden kann, ist, die Datei in mein lokales Repository zu übertragen, mein lokales Repository zu klonen, neue Änderungen aus dem tatsächlichen Repository abzurufen, sie zusammenzuführen und diese Zusammenführung festzuschreiben, und meine Änderungen zu verschieben.

hg add my_migration.sql 
hg commit -m "migration notes" my_migration.sql 
cd ..
hg clone project project-clone
cd project-clone
hg fetch http://hg/project
hg push  http://hg/project

Das funktioniert, aber es scheint, als würde mir etwas Einfacheres fehlen, eine Möglichkeit, mercurial anzuweisen, die Dateien, die sich bereits in meinem Arbeitsverzeichnis befinden, zu ignorieren. Führen Sie einfach die Zusammenführung durch und senden Sie die Dateien mit. Ich vermute, dass Quecksilber-Warteschlangen dies können, aber ich bin noch nicht ganz fertig.


1
Dies ist eine Funktion, die ich in Git sehr schätze (ich benutze sie die ganze Zeit) und die es mir schwer machen würde zu wechseln ...
Jared Forsyth

12
So würde ich jetzt eigentlich nicht vorgehen, da ich viel mehr über hg gelernt habe. Jetzt würde ich die Änderungen lokal festschreiben, auf die vorherige Version zurück aktualisieren und dort meine Änderungen vornehmen und "hg push --rev". nur den aktuellen Zweig herauszustupsen. Aktualisieren Sie dann wieder auf die andere Arbeit und fahren Sie dort fort. Wenn ich mich entschließen würde, diese Arbeit nicht mehr zu wollen, würde ich sie einfach "ausziehen". Viel einfacher und Sie müssen sich keine Gedanken über abgelehnte Dateien machen. Alles wird nachverfolgt und befindet sich in der Quellcodeverwaltung.
Ted Naleid

Antworten:


31

Es gibt eine Mercurial-Funktion, die Shelve- und Unhelve-Befehle implementiert, mit denen Sie auf interaktive Weise Änderungen festlegen können, die bis zu einem späteren Zeitpunkt gespeichert werden sollen : Shelve .

Dann können Sie hg shelveund hg unshelveÄnderungen vorübergehend speichern. Sie können auf der Ebene "Patch Hunk" arbeiten, um die Gegenstände auszuwählen, die aufbewahrt werden sollen. Es schien keine Datei zu speichern, die zum Hinzufügen aufgelistet war, sondern nur Dateien, die sich bereits im Repo mit Änderungen befanden.

Es ist in Mercurial als "Erweiterung" enthalten, was nur bedeutet, dass Sie es in Ihrer hg-Konfigurationsdatei aktivieren müssen.


Hinweise für wirklich alte Versionen von Mercurial (bevor das Regal aufgenommen wurde - dies ist nicht mehr erforderlich):

Ich habe keine großartigen Installationsanweisungen mit etwas Googeln gesehen, also hier die kombinierten Dinge, die ich verwendet habe, um es zum Laufen zu bringen:

Erhalten Sie es mit:

hg clone http://freehg.org/u/tksoh/hgshelve/ hgshelve

Die einzige Datei (derzeit) im Projekt ist die Datei hgshelve.py.

Ändern Sie ~ / .hgrc, um die Regalerweiterung hinzuzufügen, und zeigen Sie auf die Stelle, an der Sie das Repo geklont haben:

[extensions] 
hgshelve=/Users/ted/Documents/workspace/hgshelve/hgshelve.py

40

Es ist fast 2 Jahre her, seit ich diese Frage ursprünglich gestellt habe. Ich würde es jetzt anders machen (wie ich in einem Kommentar über der obigen Frage erwähnt habe). Was ich jetzt tun würde, wäre, stattdessen meine Änderungen an der einen Datei in meinem lokalen Repo festzuschreiben (Sie können die Erweiterung hg record verwenden, um nur Teile einer Datei festzuschreiben):

hg commit -m "commit message" filename

Dann einfach rausschieben.

hg push

Wenn es einen Konflikt gibt, weil andere Änderungen am Repo vorgenommen wurden, die ich zuerst zusammenführen muss, würde ich auf die übergeordnete Revision aktualisieren (angezeigt mit "hg parent -r.", Wenn Sie nicht wissen, was es ist), verpflichten Sie sich Meine anderen Änderungen dort, also habe ich 2 Köpfe. Kehren Sie dann zum ursprünglichen Festschreiben einzelner Dateien zurück und ziehen Sie die Änderungen in diese Version. Dann schieben Sie die Änderungen mit heraus

hg push --rev .

Nur die einzelne Datei und die Zusammenführung dieser Revision herausdrücken. Dann können Sie die beiden Köpfe zusammenführen, die Sie lokal haben.

Auf diese Weise werden das mq-Zeug und das Potenzial für abgelehnte Hunks beseitigt und alles wird durch die Quellcodeverwaltung verfolgt. Sie können Revisionen auch deaktivieren, wenn Sie später entscheiden, dass Sie sie nicht möchten.


1
Das klingt gut. Ich fange an zu kreuzen, wenn ich irgendwo in der Nähe von Mercurial einen Buchstaben 'q' sehe. Sie können von Steve Loshs "hg nudge"
Tom Anderson

Die Verwendung von Phasen (im heutigen Mercurial) würde dies noch einfacher machen. Es wäre nicht erforderlich, --revmit Push anzugeben , nur um zu vermeiden, dass das Falsche gedrückt wird.
UuDdLrLrSs

10

tl; dr: Meine ursprüngliche Erklärung sieht kompliziert aus, aber ich hoffe, sie erklärt vollständig, wie man eine Patch-Warteschlange verwendet. Hier ist die Kurzversion:

$ hg qnew -m "migration notes" -f migration my_migration.sql
$ hg qnew -f working-code
# make some changes to your code
$ hg qrefresh # update the patch with the changes you just made
$ hg qfinish -a # turn all the applied patches into normal hg commits

Mercurial Queues machen solche Dinge zum Kinderspiel und ermöglichen eine komplexere Manipulation von Änderungssätzen. Es lohnt sich zu lernen.

In dieser Situation möchten Sie wahrscheinlich zuerst speichern, was sich in Ihrem aktuellen Verzeichnis befindet, bevor Sie die Änderungen abrufen:

# create a patch called migration containing your migration
$ hg qnew -m "migration notes" -f migration.patch my_migration.sql
$ hg qseries -v # the current state of the patch queue, A means applied
0 A migration.patch
$ hg qnew -f working-code.patch # put the rest of the code in a patch
$ hg qseries -v
0 A migration.patch
1 A working-code.patch

Lassen Sie uns nun einige zusätzliche Arbeiten am Arbeitscode durchführen. Ich werde weiter machen, qseriesnur um explizit zu sein, aber sobald Sie ein mentales Modell von Patch-Warteschlangen erstellt haben, müssen Sie nicht mehr auf die Liste schauen.

$ hg qtop # show the patch we're currently editing
working-code.patch
$ ...hack, hack, hack...
$ hg diff # show the changes that have not been incorporated into the patch
blah, blah
$ hg qrefresh # update the patch with the changes you just made
$ hg qdiff # show the top patch's diff

Da Ihre gesamte Arbeit jetzt in der Patch-Warteschlange gespeichert ist, können Sie diese Änderungen übernehmen und wiederherstellen, nachdem Sie die Remote-Änderungen übernommen haben. Normalerweise müssen Sie nur alle Patches entfernen hg qpop -a. Um den Effekt auf die Patch-Warteschlange zu zeigen, werde ich sie einzeln entfernen.

$ hg qpop # unapply the top patch, U means unapplied
$ hg qseries -v
0 A migration.patch
1 U working-code.patch
$ hg qtop
migration.patch
$ hg qpop
$ hg qseries -v
0 U migration.patch
1 U working-code.patch

Zu diesem Zeitpunkt ist es so, als ob sich in Ihrem Verzeichnis keine Änderungen befinden. Mach das hg fetch. Jetzt können Sie Ihre Patch-Warteschlangenänderungen wieder aktivieren und bei Konflikten zusammenführen. Dies ist konzeptionell etwas ähnlich zu Git's Rebase.

$ hg qpush # put the first patch back on
$ hg qseries -v
0 A migration.patch
1 U working-code.patch
$ hg qfinish -a # turn all the applied patches into normal hg commits
$ hg qseries -v
0 U working-code.patch
$ hg out
migration.patch commit info... blah, blah
$ hg push # push out your changes

Zu diesem Zeitpunkt haben Sie die Migration verschoben, während Sie Ihre anderen lokalen Änderungen beibehalten haben. Ihre anderen Änderungen befinden sich in einem Patch in der Warteschlange. Ich mache den größten Teil meiner persönlichen Entwicklung mithilfe einer Patch-Warteschlange, um meine Änderungen besser zu strukturieren. Wenn Sie die Patch-Warteschlange entfernen und zu einem normalen Stil zurückkehren möchten, müssen Sie Ihre Änderungen exportieren und in "normalem" Quecksilber erneut importieren.

$ hg qpush
$ hg qseries -v
0 A working-code.patch
$ hg export qtip > temp.diff
$ rm -r .hg/patches # get rid of mq from the repository entirely
$ hg import --no-commit temp.diff # apply the changes to the working directory
$ rm temp.diff

Ich bin sehr süchtig nach Patch-Warteschlangen für die Entwicklung und bin mqeine der schönsten Implementierungen da draußen. Die Fähigkeit, mehrere Änderungen gleichzeitig vorzunehmen, verbessert wirklich, wie konzentriert und sauber Ihre Commits sind. Es dauert eine Weile, bis man sich daran gewöhnt hat, aber es passt unglaublich gut zu einem DVCS-Workflow.


+1 für die Erklärung, aber das sieht sehr kompliziert aus. Vergleichen Sie es mit "git rebase -i", was keinerlei Gedanken oder Einrichtung erfordert, und ich kann immer noch nicht sehen, wie MQ eine praktikable Lösung für das Problem "ordentliches Patch-Set" ist (für Sterbliche!). Es scheint, dass Sie Ihren Workflow sowieso wirklich planen müssen.
Richq

20
Ich bin mir nicht sicher, ob ich einen 20-stufigen Prozess obskurer Befehlszeilen als "ein Kinderspiel" bezeichnen würde.
Crashworks

1
hehe, guter anruf. Ich habe die kurze, süße Antwort auf seine Lösung oben geschrieben.
Kobold

3

Eine weitere Option, wenn Sie sich nicht auf Erweiterungen verlassen möchten, besteht darin, einen Klon Ihres Upstream-Repositorys lokal zu speichern, den Sie nur für diese Art von Integrationsaufgaben verwenden.

In Ihrem Beispiel können Sie Ihre Änderung einfach in das Integrations- / Upstream-Repository ziehen / zusammenführen und direkt auf den Remote-Server übertragen.


2

Was ich im Allgemeinen benutze, ist das Festschreiben einer einzelnen Datei:

 hg commit -m "commit message" filename

Falls ich später einen Zusammenführungskonflikt habe und immer noch nicht bereit bin, meine Änderungen zu übernehmen, gehen Sie folgendermaßen vor:

1) Erstellen Sie eine Patch-Datei.

hg diff > changes.patch

2) Setzen Sie alle ausstehenden nicht festgeschriebenen Änderungen erst zurück, nachdem Sie Ihre Patch-Datei überprüft haben.

hg revert --all

3) Ziehen, aktualisieren und auf die neueste Version zusammenführen

hg pull -u
hg merge
hg commit -m "local merge"

4) Importieren Sie jetzt einfach Ihren Patch zurück und erhalten Sie Ihre Änderungen.

hg import --no-commit changes.patch

Denken Sie daran, das Flag -no-commit zu verwenden, um die Änderungen automatisch festzuschreiben.


1

Da Sie am einfachsten gesagt haben, verwende ich oft hg commit -i(--interactive), auch wenn ich ganze Dateien festschreibe. Mit können --interactiveSie einfach die gewünschten Dateien auswählen, anstatt deren gesamte Pfade in die Befehlszeile einzugeben. Als zusätzlichen Bonus können Sie sogar Chunks selektiv in die Dateien einschließen / ausschließen.

Und dann nur hg push, um das neu erstellte Commit voranzutreiben.

Ich habe hg commit --interactivein dieser Antwort weitere Details zur Verwendung angegeben : https://stackoverflow.com/a/47931672/255961

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.