Можете ли вы когда-нибудь отменить коммит, кроме самого последнего, без создания конфликта? - PullRequest
3 голосов
/ 24 марта 2019

Примечание: бот stackoverflow считает вопрос субъективным, но он очень фактический - я не спрашиваю мнения здесь!

Допустим, у меня есть только одна ветвь, и история моих коммитов такова: A- B - C - D

Если я нажимаю на C в графическом интерфейсе (например, GitKraken или Git для Windows) и выполняю команду «отменить фиксацию», я получаю сообщение о конфликте файлов.

Два вопроса:

  1. Это потому, что возврат «отменяет» изменения, сделанные в C, и GIT теперь привязан к B и D, которые изменяют файл различными несовместимыми способами?в этом ли причина?

  2. Если да, значит ли это, что вы можете отменить только самый последний коммит?Можете ли вы когда-нибудь отменить коммит, кроме самого последнего, без создания конфликта?

ОБНОВЛЕНИЕ : редактирование вопроса после очень полезных разъяснений от @RomainValeri.Я думаю, что я делал слишком много путаницы между возвратом и сбросом.В приведенном ниже примере выполнение

git revert B

заставляет ветку переходить с

A-B-C-D

на

A-B-C-D-E

Если B был единственным коммитом, которыйизменил file2.txt, и B не сделал никаких других изменений в других файлах, тогда новый коммит E, созданный после возврата, сохранит все изменения, сделанные в C и D, но НЕ внесенные в B. Это правильно?

Это потому, что технически возврат означает отмену, отмену любых изменений коммита - это правильно?

Также: допустим, что У меня есть только один файл в моемрабочий каталог.Если B - единственный коммит, который изменяет функцию fun1 () в моем файле, , в то время как все другие коммиты изменяют другие функции в том же файле, тогда возврат B, скорее всего, вызовет конфликт , потому чтоgit мыслит с точки зрения строк в файле, а не с точки зрения функций в файле.Это правильно?

Итак, скажем, что B изменяет fun1 (), C изменяет fun2 () и D меняет fun3 ().Затем я понимаю, что изменения, сделанные в B в fun1 (), неверны, и мне нужно отменить их. Если все эти функции находятся в одном файле, есть ли способ отменить изменения в B при сохранении изменений в C и D?

Если вместо этого каждая из этих 3 функцийв отдельном файле гораздо проще отменить изменения одного коммита, не затрагивая другие, верно?

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

Ответы [ 2 ]

6 голосов
/ 24 марта 2019

Краткий ответ: Вы могли бы очень хорошо отменить данный коммит (даже старый) и не иметь конфликта.


Почемуэто так?

git revert создает новый коммит поверх текущего кончика дерева, не удаляет данный коммит,и не изменяет его каким-либо образом.

У вас возникает конфликт, когда в merge-base между коммитом, который вы создаете с помощью revert, и HEAD.

возникает что-то другое.

Попробуйте сами с этим

Тривиальный пример

Учитывая дерево репо,

Folder1
  file1.txt
  file2.txt
Folder2
  file3.txt

и последующую историю,

A---B---C---D << HEAD

где

A создает все файлы с их содержимым.
B изменяет file2.txt
C изменяет file1.txt и file3.txt
D дополнительно изменяет file1.txt

, тогда команда

git revert B

будет не создавать любой конфликт, просто новый новый коммит Eс новыми изменениями для file2.txt.

A---B---C---D---E << HEAD

Содержимое нового коммита, созданного git revert (добавлено после комментариев)

Изменения в E являются точными обратными изменениями, внесенными B.

С B следующим образом:

$ git show B
commit f3ba29d98c0998297126d686d03d33794cbc0f73
Author: Pythonista <some.name@some.isp>
Date:   Sun Mar 24 20:41:49 2019 +0100

    Some change

diff --git a/javascript/functions.js b/javascript/functions.js
index 543c9cb..5f166d3 100644
--- a/javascript/functions.js
+++ b/javascript/functions.js
@@ -3710,5 +3710,6 @@ function dumpLists(isMixted) {
 // end of process

 createTrigger(window, 'load', START_EVERYTHING);
+doStuff(param);

Вы получите E коммит, содержащий:

$ git show E
commit 2ff723970e81d64f3776c081a1f96242589774b6 (HEAD -> master)
Author: Pythonista <some.name@some.isp>
Date:   Sun Mar 24 20:42:33 2019 +0100

    Revert "Some change"

    This reverts commit f3ba29d98c0998297126d686d03d33794cbc0f73.

diff --git a/javascript/functions.js b/javascript/functions.js
index 5f166d3..543c9cb 100644
--- a/javascript/functions.js
+++ b/javascript/functions.js
@@ -3710,6 +3710,5 @@ function dumpLists(isMixted) {
 // end of process

 createTrigger(window, 'load', START_EVERYTHING);
-doStuff(param);

Помните + или - перед последней разницей, что означает «добавление» (+) и «удаление» (-).

1 голос
/ 04 апреля 2019

Почти все операции по созданию истории, кроме прямого коммита в Git, заканчиваются слиянием где-нибудь. Перебазирование, выбор вишни, возврат, копирование, слияние, конечно, все они сливаются, просто с выбранными базами слияния. Есть даже опция слияния при оформлении заказа, которая объединяется с использованием вашей текущей проверки в качестве основы, нового коммита в качестве подсказки и вашего рабочего дерева / индекса в качестве другой подсказки, и сливается с новым рабочим деревом / индексом, что может быть очень удобно.

Для возврата скажем A---B... * ... M master, а вы git revert B, git смотрит на изменения с B на A и на изменения с B на M, это ваше слияние. Если в двух наборах изменений были затронуты смежные или перекрывающиеся линии, шансы, которые некоторые люди должны исправить, стремительно повышают текст, поэтому Git отказывается делать это молча. В любом случае, тривиальные случаи занимают секунды.

...