Як я можу надіслати поправки на віддалений сховище 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.