Як я можу надіслати поправки на віддалений сховище Git?


662

Коли я трохи працював зі своїм вихідним кодом, я зробив свою звичайну річ, а потім перейшов до віддаленого сховища. Але потім я помітив, що забув організувати свій імпорт у вихідному коді. Тож я виконую команду поправки, щоб замінити попередній комітет:

> git commit --amend

На жаль, комісія не може бути повернута назад у сховище. Він відкидається так:

> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

Що я повинен зробити? (Я можу отримати доступ до віддаленого сховища.)


Що робити, якщо мій --імен був лише змінити повідомлення про фіксацію? Будь-який спосіб відредагувати останнє повідомлення про фіксацію самостійно, якщо воно вже було натиснене на віддалений? Я зробив це на Github і отримав те саме повідомлення про не швидкий перемогу вперед. Тоді я застосував рішення нижче, але злиття просто додало більше повідомлень про фіксацію зверху ..

7
@faB: Я думаю, що це FAQ. Повідомлення про фіксацію хеширується разом з фіксацією, тому його зміна змінює revid (хеш). Якщо це не ясно: ні, ви не можете. IIRC може зберігати інформацію про позадіапазонну інформацію в нотатках (тому ви можете коментувати існуючі комісії, не змінюючи їх). Щоб позначити конкретні
комісії

1
Ви незабаром (git1.8.5, Q4 2013) зможете зробити git push -forceбільш ретельно .
VonC

3
Ось стиль ковбоя. Не дізнайтеся більше і не шукайте способів скасувати попередню зміну git. Просто додайте код заповнювача, я маю на увазі, Додати коментар, очистити трохи коду або просто додати кілька тире-тире тире .... Тепер зробіть справжню фіксацію та натисніть її на віддалений. Готово!
nehem

@ user58777 Якщо ваш -amend полягав лише в тому, щоб змінити повідомлення про фіксацію, і ви з цього часу не зробили жодних додаткових локальних комісій, ви можете скинути свою локальну гілку до віддаленої комісії, яку ви натиснули перед зміною повідомлення про фіксацію.
Скотт Ахтен

Відповіді:


504

Я насправді одного разу підштовхнув до --forceі .gitсховище, і мене знущали Лінуса ВЕЛИКОГО ЧАСУ . Взагалі це створить багато проблем для інших людей. Проста відповідь - «Не роби цього».

Я бачу, що інші дали рецепт зробити так чи інакше, тому я не повторюю їх тут. Але ось порада вийти з ситуації після того, як ви видалили змінену комісію з --force (або + master).

  1. Використовуйте git reflogдля пошуку старої комісії, яку ви внесли до поправок (зателефонуйте old, і ми зателефонуємо до нового зобов'язання, яке ви створили шляхом внесення змін new).
  2. Створіть злиття між oldі new, записавши дерево new, як git checkout new && git merge -s ours old.
  3. З’єднайте це з вашим господарем git merge master
  4. Оновіть свого майстра результатом за допомогою git push . HEAD:master
  5. Висуньте результат.

Тоді люди , які були невдалими досить , щоб засновують свою роботу на Комміт ви стерті зміни і змушуючи поштовх буде побачити в результаті злиття буде бачити , що ви віддаєте перевагу newбільш old. Їх пізніше злиття не буде бачити конфлікти між oldі newщо в результаті вашого змінює, тому вони не повинні страждати.


17
Я дуже добре знаю, що станеться, коли ти змусиш натиснути поправлене зобов’язання (знищивши історію). На щастя, я був єдиним розробником проекту з віддаленим репо на мережевому диску, тому це було не так вже й багато. Я ніколи не думав про об'єднання поправки на поправку, тож я підтримаю це.
Спіке

61
У нашій компанії ми досить регулярно натискаємо на особливі галузі, розроблені фізичними особами.
Ondra Žižka

2
Лаяння від Лінуса було тому, що ви стирали історію з можливістю сили, а не тому, що не повинні цього робити. Рішення GabrielleV працює відмінно, оскільки це не змінює історію.
користувач411279

2
Будь ласка, оскільки автор (гітстер) цієї відповіді, здається, вже не існує, хтось може допомогти уточнити пункт № 1: знайти старий документ. Якщо у вас немає резервної копії, де б ви її знайшли? Зміни та натискання не призвело б до його знищення? Можливо, він має на увазі отримати його від друга / співпрацівника, який все ще має його в дереві?
Доктор Беко

2
Д-р Бреко, ви можете використовувати його git reflogдля пошуку
Simon Zyx

269

Ви бачите функцію безпеки Git. Git відмовляється від оновлення віддаленої гілки з вашою гілкою, оскільки фіксація голови вашої філії не є прямим нащадком поточної комісії голови гілки, на яку ви натискаєте.

Якби це не так, то двоє людей, що натискають на одне сховище приблизно в один і той же час, не знали б, що в цей же час приходить нова фіксація, і хто натиснув останній, втратить роботу попереднього штовхача без жодного з вони усвідомлюючи це.

Якщо ви знаєте, що ви єдина особа, яка натискає, і ви хочете натиснути поправлену команду або натиснути на команду, яка повертає гілку, ви можете «змусити» Git оновити віддалену гілку за допомогою -fперемикача.

git push -f origin master

Навіть це може не спрацювати, оскільки Git дозволяє віддаленим сховищам відмовлятися від нешвидкісних форвардних натискань у віддаленому кінці за допомогою змінної конфігурації receive.denynonfastforwards. У такому випадку причина відхилення виглядатиме так (зверніть увагу на "віддалену відхилену" частину):

 ! [remote rejected] master -> master (non-fast forward)

Щоб обійти це, вам потрібно змінити конфігурацію віддаленого сховища або, як брудний хак, ви можете видалити та відтворити гілку таким чином:

git push origin :master
git push origin master

Взагалі останній параметр git pushвикористовує формат <local_ref>:<remote_ref>, де local_refє ім'я гілки в локальному сховищі і remote_refє ім'ям гілки на віддаленому сховищі. Ця командна пара використовує дві скорочення. :masterмає null local_ref, що означає натиснути нульову гілку на віддалену сторону master, тобто видалити віддалену гілку. Ім'я гілки без жодного :способу натискати локальну гілку з вказаним іменем до віддаленої гілки з тим самим іменем. masterв цій ситуації коротко master:master.


2
це не спрацювало з github, воно дало мені таке повідомлення: [віддалений відхилений] майстер (видалення поточної гілки заборонено)
вхід

Я не хотів змушувати натискати (що я знав, що вирішить проблему), але зараз я думаю, що у мене немає вибору.
віданг

1
Це єдине рішення, яке працювало на моє репо, яке розміщувалося з монтажем.
Джастін

1
вилучення віддаленої ведучої гілки звільнить місце у віддаленому репо?
Mr_and_Mrs_D

1
@Mr_and_Mrs_D: Не одразу, але після git gcзакінчення терміну відмови, старі об’єкти будуть обрізані. Ніхто, хто клонує сховище, не отримає об'єктів, які вже недоступні, як тільки гілка буде оновлена.
CB Bailey

211

Швидкий скандал: Той факт, що тут ніхто не опублікував просту відповідь, свідчить про відчайдушну неприязнь користувачів, яку демонструє Git CLI.

У будь-якому випадку, "очевидний" спосіб зробити це, якщо припустити, що ви не намагалися натиснути, - це потягнути першим. Це тягне за собою зміну, яку ви внесли до поправок (і тому більше не маєте), щоб мати її знову.

Після того, як ви вирішите будь-які конфлікти, ви можете натиснути знову.

Тому:

git pull

Якщо у вас виникають помилки при витягуванні, можливо, у вашій локальній сховищі репозиторію щось не так (у розділі гілки .git / config помилковий перелік).

І після

git push

Можливо, ви отримаєте додаткову комісію з темою, яка розповість про "Тривіальне злиття".


2
Так, я писав про це, див stackoverflow.com/questions/253055 / ... ;)
Spoike

10
Це насправді не працює, як я очікував. Це створює два нові коміти. Той, що є реплікою старого, але із внесеними змінами. І одна фіксація злиття з порожньою різницею. І все-таки залишаючи стару комісію незмінною, виявляючи можливі чутливі дані, які я намагався внести зміни. Я вірю git push -fчи git resetце єдиний шлях сюди.
thnee

40
Хоча технічно відповідає на проблему, він насправді не вирішує проблему. Як ви вже говорили, це призведе до додаткових зобов'язань, але головна причина, коли люди змінюють зобов’язання - це уникати створення нового. Тож якби плакат дотримувався ваших вказівок, він не отримав бажаного результату. Було б так само сенс не змінювати зобов'язання в першу чергу.
Ден Джонс

102

Коротка відповідь: Не надсилайте змінені зобов’язання на публічне репо.

Довга відповідь: Кілька команд Git, як-от git commit --amendі git rebaseнасправді переписати графік історії. Це добре, доки ви не опублікували свої зміни, але, як тільки ви це зробите, ви дійсно не повинні спілкуватися з історією, тому що якщо хтось уже отримав ваші зміни, то, коли вони спробують знову витягнути, вони можуть не вдатися . Замість того, щоб вносити зміни до комісії, слід просто зробити нове зобов’язання зі змінами.

Однак якщо ви дійсно дуже хочете надіслати змінену комісію, ви можете зробити так:

$ git push origin +master:master

Провідна +ознака змусить наштовхнутись, навіть якщо це не призведе до «швидкого переходу вперед». (Здійснення швидкого перемотування вперед відбувається, коли зміни, які ви натискаєте, є прямим нащадком змін, які вже є у публічному репо.)


5
Чим це відрізняється (краще чи гірше) від git push -f? Дякую!
Бентфорд

11
@bentford: Це в основному те саме, що і git push -f.
mipadi

54

Ось дуже простий і чистий спосіб змінити зміни після того, як ви вже зробили commit --amend:

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master

Що означає:

  • Скинути голову відділення до батьківської комісії.
  • Закладіть цю останню прихильність.
  • Примушуйте натискати на віддалений. У пульті тепер немає останньої передачі.
  • Поп ваш скриньку.
  • Здійснюйте чисто.
  • Натисніть на віддалений.

Не забудьте змінити "походження" та "майстер", якщо застосувати це до іншої гілки чи дистанційного.


3
2 зауваження: - не забудьте змінити назву філії, якщо ви працюєте над іншою - мені довелося скористатись, git addперш ніж взяти на себе зобов’язання включити зміни.
SylvainB

1
У Windows CMD, перша команда повинна бути екрановані: git reset --soft "HEAD^". Решта працює чудово.
Містер Містер

2
"дуже простий і чистий спосіб .." цит. Ця процедура включає примусовий поштовх. Зважаючи на всі вимоги у відповідях вище, я не впевнений, чи справді ця процедура є чистою.
Na13-c

24

Я вирішив це, відкинувши місцевий поправку та додавши нові зміни зверху:

# Rewind to commit before conflicting
git reset --soft HEAD~1

# Pull the remote version
git pull

# Add the new commit on top
git add ...
git commit
git push

2
Це найпростіша версія!
mknaf

Додавання чергового комітету "зміни" краще, ніж возитися з історією переписування. Я згоден з @mknaf
sdkks

8

У мене була така ж проблема.

  • Випадково внесені зміни до останнього зобов’язання, яке вже було натиснуто
  • Здійснено багато змін на місцях, здійснених десь п’ять разів
  • Спробував натиснути, отримав помилку, запанікував, злився віддаленим, отримав багато файлів, що не є моїми, штовхнув, не вдалося і т.д.

Як новачок Git, я вважав, що це закінчено FUBAR .

Рішення. Приблизно так, як @bara запропонував + створив локальну гілку резервного копіювання

# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>

# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad

# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"

# Switch back to the original branch
git checkout feature/1234

# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234

# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php

Можливо, це не швидке і чисте рішення, і я втратив історію (1 фіксування замість 5), але це врятувало робочий день.


6

Якщо ви не натиснули код на віддалену гілку (GitHub / Bitbucket), ви можете змінити повідомлення про фіксацію в командному рядку, як показано нижче.

 git commit --amend -m "Your new message"

Якщо ви працюєте в певній галузі, зробіть це:

git commit --amend -m "BRANCH-NAME: new message"

Якщо ви вже натиснули код з неправильним повідомленням, вам потрібно бути обережними під час зміни повідомлення. тобто після того, як ви зміните повідомлення про фіксацію та спробуєте натиснути його знову, у вас виникнуть проблеми. Щоб зробити його рівним, виконайте наступні дії.

Будь ласка, прочитайте всю відповідь, перш ніж це зробити

git commit --amend -m "BRANCH-NAME : your new message"

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

Важлива примітка. Якщо ви безпосередньо використовуєте натискання на силу, у вас можуть виникнути проблеми з кодом, які інші розробники працюють над тією ж гілкою. Отже, щоб уникнути цих конфліктів, вам потрібно витягнути код з вашого відділення, перш ніж натискати на силу :

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME

Це найкраща практика при зміні повідомлення про фіксацію, якщо воно вже було натиснуто.


1
Якщо у вашому останньому прикладі ви успішно зняли комісію, навіщо вам змушувати натискати? Чи не вистачить стандартного натискання? Спасибі
Томас

Питання, яке задає Томас, насправді є дуже актуальним. Мені не потрібно було змушувати натискати після наступного потягу.
Na13-c

Будь ласка, не називайте це "найкращою практикою", тому що є спосіб --force
Farid

5

Якщо ви знаєте, що ніхто не стягнув вашу неоправлену комісію, скористайтеся --force-with-leaseопцієюgit push .

У TortoiseGit ви можете виконати те ж саме, що в параметрі "Натиснути ..." параметри "Примусити: може відкинути" та перевірити "відомі зміни".

Сила (може відкинути відомі зміни) дозволяє віддаленому сховищу прийняти безпечніший нешвидкий поштовх вперед. Це може призвести до втрати віддаленого сховища комісій; використовувати його обережно. Це може запобігти втраті невідомих змін від інших людей на пульті дистанційного керування. Він перевіряє, чи гілка сервера вказує на той самий фільтр, що і гілка віддаленого відстеження (відомі зміни). Якщо так, то буде здійснено силовий натиск. Інакше він буде відхилений. Оскільки у git немає тегів віддаленого відстеження, теги не можуть бути перезаписані за допомогою цієї опції.


4

Ви отримуєте цю помилку, оскільки в пульті Git вже є ці файли фіксації. Для цього вам потрібно змусити натиснути гілку:

git push -f origin branch_name

Також переконайтеся, що ви витягнули код віддалено, оскільки хтось інший у вашій команді, можливо, перейшов до тієї ж гілки.

git pull origin branch_name

Це один із випадків, коли нам доводиться змушувати натискати на віддалене місце.


Чому б ця відповідь не була поясненням основних коментарів, висунутих у попередніх відповідях?
Na13-c

2

Ось дуже простий і чистий спосіб змінити зміни після того, як ви вже зробили git add "your files"та git commit --amend:

git push origin master -f

або:

git push origin master --force

Я чую, що це погано, і я впевнений, що це так. Є (хороша) причина, коли git не зможе замовчуватись (і вимагають --force), я впевнений.
Рольф

1

Мені довелося виправити цю проблему, витягнувши з віддаленого репо і вирішуючи конфлікти злиття, які виникали, здійснювались, а потім підштовхувались. Але я відчуваю, що є кращий шлях.


Не зовсім. Проблема може полягати в тому, що ви не оновлювали локальну копію з віддаленого репо. Git не буде натискати на нього, тому що вам, можливо, доведеться мати справу з об'єднаннями вручну. У своїй іншій відповіді я маю команду (та пояснення), яка змусить натиснути, але будьте обережні, що може видалити зміни на пульті.
mipadi

1

Я просто продовжував робити те, що сказав мені Гіт. Тому:

  • Неможливо натиснути через змінену комісію.
  • Я роблю тяг, як було запропоновано.
  • Злиття не вдається. тому я виправляю це вручну.
  • Створіть нову комісію (з написом "злиття") та натисніть її.
  • Здається, працює!

Примітка. Змінений комітет був останнім.


1
Я б заперечував, якби у мене було більше репутаційних очок, тож я просто ввічливо запитаю тут, хто з вас страждав? Той, хто змінив? Той, хто витягнув і працював у відділенні зі зміненою комісією? До поправки чи після неї? Я просто очистив кожну мою модифікацію, тому що я вас зрозумів неправильно ... На щастя, було не так багато ...
Bartis Арон

1

Наступне працювало для мене, коли змінювався Автор і Комітет комітету.

git push -f origin master

Гіт був достатньо розумним, щоб зрозуміти, що це коміти з однакових дельт, які відрізняються лише в розділі метаінформації.

І місцеві, і віддалені голови вказували на питання, про які йдеться.



0

Ось, як я виправив правки в попередньому комітеті:

  1. Збережіть свою роботу поки що.
  2. Наразі приховайте зміни, якщо вони зроблені: git stash тепер ваша робоча копія чиста в стані останнього виконання.
  3. Внесіть зміни та виправлення.
  4. Внести зміни в режимі "зміни" :git commit --all --amend
  5. Ваш редактор підійде із запитом журналу повідомлення (за замовчуванням старе повідомлення журналу). Збережіть і вийдіть із редактора, коли ви цим задоволені.

    Нові зміни додаються до старого комітету. Побачте самі з git logіgit diff HEAD^

  6. Повторно застосуйте приховані зміни, якщо вони зроблені: git stash apply

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.