Практическое использование git reset --soft? - PullRequest
114 голосов
/ 05 марта 2011

Я работаю с Git чуть более месяца.Действительно, я впервые использовал сброс только вчера, но программный сброс все еще не имеет для меня особого смысла.

Я понимаю, что могу использовать программный сброс, чтобы редактировать коммит без изменения индекса илирабочий каталог, как я бы с git commit --amend.

Эти две команды действительно одинаковы (reset --soft против commit --amend)?Есть ли основания использовать одно или другое на практике?И что более важно, есть ли другие варианты использования reset --soft помимо внесения изменений в коммит?

Ответы [ 11 ]

97 голосов
/ 05 марта 2011

git reset - это перемещение HEAD, и, как правило, ветвь ref .
Вопрос: а как насчет рабочего дерева и индекса?
При использовании с --soft, перемещается HEAD, чаще всего обновляется ссылка на ветку, и только HEAD.
Это отличается от commit --amend как:

  • это не создает новый коммит.
  • он может фактически перемещать HEAD к любому коммиту (поскольку commit --amend - это всего лишь , а не перемещение HEAD, при этом позволяя повторить текущий коммит)

Только что нашел этот пример объединения:

  • классическое слияние
  • объединение поддеревьев

все в один (осьминог, так как объединено более двух веток) совершить слияние.

Томас "wereHamster" Карнекки объясняет в своей статье "Слияние поддеревьев осьминога" :

  • Стратегия слияния поддеревьев может использоваться, если вы хотите слить один проект в подкаталог другого проекта и впоследствии поддерживать подпроект в актуальном состоянии. Это альтернатива подмодулям git.
  • Стратегия слияния осьминога может использоваться для слияния трех или более веток. Обычная стратегия может объединять только две ветви, и если вы попытаетесь объединить больше, git автоматически вернется к стратегии осьминога.

Проблема в том, что вы можете выбрать только одну стратегию. Но я хотел объединить их, чтобы получить чистую историю, в которой весь репозиторий атомарно обновляется до новой версии.

У меня есть суперпроект, назовем его projectA, и подпроект projectB, который я слил в подкаталог projectA.

(это часть слияния поддерева)

Я также поддерживаю несколько локальных коммитов.
ProjectA регулярно обновляется, projectB имеет новую версию каждые пару дней или недель и обычно зависит от конкретной версии projectA.

Когда я решаю обновить оба проекта, я не просто извлекаю из projectA и projectB , так как это создаст два коммита для атомарного обновления всего проекта .
Вместо этого я создаю один коммит слияния, который объединяет projectA, projectB и мои локальные коммиты .
Сложность в том, что это слияние осьминога (три головы), , но projectB необходимо объединить со стратегией поддеревьев . Вот что я делаю:

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

Здесь автор использовал reset --hard, а затем read-tree, чтобы восстановить то, что первые два слияния сделали с рабочим деревом и индексом, но здесь reset --soft может помочь:
Как мне повторить те два слияния , которые сработали, то есть мое рабочее дерево и индекс в порядке, но без необходимости записывать эти два коммита?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

Теперь мы можем возобновить решение Томаса:

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit

Итак, каждый раз:

  • вы довольны тем, что вы в итоге (с точки зрения рабочего дерева и индекса)
  • Вы не удовлетворены всеми коммитами, которые потребовали вас, чтобы попасть туда:

git reset --soft - это ответ.

32 голосов
/ 03 октября 2014

Вариант использования - объединение серии локальных коммитов

"Упс. Эти три коммита могут быть только одним."

Итак, отмените последние 3 (или любые другие) коммиты (не затрагивая ни индекс, ни рабочий каталог). Затем зафиксируйте все изменения как один.

1007 * Е.Г. * > git add -A; git commit -m "Start here." > git add -A; git commit -m "One" > git add -A; git commit -m "Two" > git add -A' git commit -m "Three" > git log --oneline --graph -4 --decorate > * da883dc (HEAD, master) Three > * 92d3eb7 Two > * c6e82d3 One > * e1e8042 Start here. > git reset --soft HEAD~3 > git log --oneline --graph -1 --decorate > * e1e8042 Start here. Теперь все ваши изменения сохранены и готовы к принятию как единое целое. Краткие ответы на ваши вопросы

Действительно ли эти две команды одинаковы (reset --soft против commit --amend)?

  • Нет.

Есть ли основания использовать одно или другое на практике?

  • commit --amend для добавления / rm файлов с самого последнего коммита или для изменения его сообщения.
  • reset --soft <commit> для объединения нескольких последовательных коммитов в новый.

И что более важно, есть ли другие варианты использования reset --soft помимо внесения изменений в коммит?

  • Смотрите другие ответы:)
16 голосов
/ 06 марта 2011

Я использую его, чтобы изменить не только последний коммит.

Допустим, я допустил ошибку в коммите А, а затем совершил коммит B. Теперь я могу только изменить Б.Я делаю git reset --soft HEAD^^, исправляю и повторно фиксирую A, а затем повторно фиксирую B.

Конечно, это не очень удобно для больших коммитов… но вы не должны делать большие коммиты в любом случае; -)

9 голосов
/ 24 сентября 2015

Другое потенциальное использование - это альтернатива краже (что не нравится некоторым, см., Например, https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-considered-harmful/).

Например, если я работаю над веткой и мне нужно срочно что-то исправить на мастере, я могу просто сделать:

git commit -am "In progress."

Затем оформите мастер и сделайте исправление. Когда я закончу, я возвращаюсь в свою ветку и делаю

git reset --soft HEAD~1

чтобы продолжить работу там, где я остановился.

6 голосов
/ 01 июля 2014

Одним из возможных вариантов использования будет, если вы хотите продолжить работу на другом компьютере.Это будет работать так:

  1. Оформить новую ветку с именем, похожим на тайник,

    git checkout -b <branchname>_stash
    
  2. Нажмите на ветку тайника вверх,

    git push -u origin <branchname>_stash
    
  3. Переключитесь на другой компьютер.

  4. Потяните вниз и ваш тайник, и существующие ветки,

    git checkout <branchname>_stash; git checkout <branchname>
    
  5. Вы должны быть в вашей существующей ветви сейчас.Объедините изменения из ветки-хранилища,

    git merge <branchname>_stash
    
  6. Мягко сбросьте существующую ветвь до 1 до объединения,

    git reset --soft HEAD^
    
  7. Удалите ветку тайника,

    git branch -d <branchname>_stash
    
  8. Также удалите ветку тайника из источника,

    git push origin :<branchname>_stash
    
  9. Продолжайте работать с изменениями, как если быты их спрятал нормально.

Думаю, в будущем GitHub и соавт.следует предлагать эту функцию «удаленного тайника» за меньшее количество шагов.

6 голосов
/ 05 марта 2011

Вы можете использовать git reset --soft, чтобы изменить версию, которую вы хотите иметь в качестве родительской для изменений, которые вы имеете в своем индексе и рабочем дереве. Случаи, когда это полезно, редки. Иногда вы можете решить, что изменения в вашем рабочем дереве должны принадлежать другой ветви. Или вы можете использовать это как простой способ свести несколько коммитов в один (аналогично сквошу / фолду).

См. Этот ответ VonC для практического примера: Сквош первых двух коммитов в Git?

5 голосов
/ 21 февраля 2016

Одним из практических применений является то, что если вы уже зафиксировали локальное репо (т. Е. Git commit -m), то вы можете отменить этот последний коммит, выполнив git reset --soft HEAD ~ 1

Также, насколько вам известно, если вы уже подготовили свои изменения (например, с помощью git add.), То вы можете отменить размещение, выполнив git reset --mixed HEAD или я обычно также только что использовалgit reset

наконец, git reset --hard стирает все, включая ваши локальные изменения.Глава ~ after сообщает вам, сколько человек совершает переход сверху.

5 голосов
/ 17 мая 2011

Отличная причина использовать git reset --soft <sha1> - это перемещать HEAD в голом репо.

Если вы попытаетесь использовать опцию --mixed или --hard, вы получите сообщение об ошибке, так как вы пытаетесь изменить работающее дерево и / или индекс, который не существует.

Примечание: вам нужно будет сделать это прямо из репо.

Примечание еще раз: вам нужно будет убедиться, что ветка, которую вы хотите сбросить в голом репо, является активной веткой. Если нет, следуйте ответу VonC о том, как обновить активную ветку в голом репо, если у вас есть прямой доступ к репо.

1 голос
/ 15 июля 2014

SourceTree - это графический интерфейс пользователя git, который имеет довольно удобный интерфейс для размещения именно тех битов, которые вам нужны.В нем нет ничего похожего для внесения поправок в правильную ревизию.

Так что git reset --soft HEAD~1 гораздо полезнее, чем commit --amend в этом сценарии.Я могу отменить фиксацию, вернуть все изменения обратно в область подготовки и возобновить настройку подготовленных битов с помощью SourceTree.

Действительно, мне кажется, что commit --amend является более избыточной командой из двух,но git это git и не уклоняется от подобных команд, которые делают немного разные вещи.

0 голосов
/ 23 января 2019

Еще один вариант использования - когда вы хотите заменить другую ветку своей в запросе на извлечение, например, предположим, что у вас есть программное обеспечение с функциями A, B, C в разработке.

Вы разрабатываете следующую версию, и вы:

  • Удалена функция B

  • Добавлена ​​функция D

В процессе разработки только что добавленные исправления для функции B.

Вы можете объединить разработку в следующую, но иногда это может быть грязно, но вы также можете использовать git reset --soft origin/develop и создать коммит с вашими изменениями, и ветвь будет объединена без конфликтов и сохранит ваши изменения.

Оказывается, git reset --soft - удобная команда. Лично я часто использую его для сжатия коммитов, которые не имеют «завершенной работы», например «WIP», поэтому, когда я открываю запрос на извлечение, все мои коммиты понятны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...