Как мне перемещаться вперед и назад между коммитами в git?


107

Я делаю git bisectи после достижения проблемного коммита теперь пытаюсь сделать шаг вперед / назад, чтобы убедиться, что я нахожусь в правильном положении.

Я знаю, HEAD^как вернуться назад в истории, но есть ли еще один ярлык, который поможет мне двигаться вперед (к конкретному коммиту в будущем), например:

A - B - C(HEAD) - D - E - F

Я знаю , что моя цель F , и я хочу , чтобы перейти от C до D .


ПРИМЕЧАНИЕ: это не дубликат Git: как перемещаться между коммитами , мой вопрос немного отличается, и на него нет ответа.


1
stackoverflow.com/questions/2263674/… тоже может помочь.
VonC

git checkout -b new_branch HEAD~4чтобы вернуться на 4 коммита из HEAD, как в stackoverflow.com/a/4940090/911945
Антон Тарасенко

Ответы:


59

Я немного поэкспериментировал, и это, похоже, помогает перемещаться вперед ( редактировать : он хорошо работает только тогда, когда у вас есть линейная история без коммитов слияния):

git checkout $(git rev-list --topo-order HEAD..towards | tail -1)

где towardsSHA1 фиксации или тега.

Пояснение:

  • команда внутри $()означает: получить все коммиты между текущим HEADи towardsфиксацией (исключая HEAD) и отсортировать их в порядке приоритета (как в git logпо умолчанию - вместо хронологического порядка, который, как ни странно, по умолчанию rev-list), а затем взять последний ( tail), то есть тот, к которому мы хотим перейти.
  • это оценивается в подоболочке и передается git checkoutдля выполнения проверки.

Вы можете определить функцию, доступную как псевдоним ожидания параметра в вашем .profileфайле, чтобы перейти к конкретной фиксации:

# Go forward in Git commit hierarchy, towards particular commit 
# Usage:
#  gofwd v1.2.7
# Does nothing when the parameter is not specified.
gofwd() {
  git checkout $(git rev-list --topo-order HEAD.."$*" | tail -1)
}

# Go back in Git commit hierarchy
# Usage: 
#  goback
alias goback='git checkout HEAD~'

2
Движение вперед отлично работает с прямыми частями истории, но зацикливается при слиянии.
Костас

Да, на самом деле я не тестировал его на слияниях. Я постараюсь посмотреть в свободное время, но у меня временно мало стимула, так как мы договорились о строго линейной истории в нашем проекте;)
jakub.g

3
Отличный ответ! Изменено, чтобы автоматически указывать текущую ветку: stackoverflow.com/a/23172256/480608
Рейн Ревер

Это неверно. git logпоказывает коммиты в хронологическом порядке, по умолчанию так же, как rev-list, за исключением случая использования --graphфлага.
papiro

Довольно убедительное свидетельство того, что git слишком сложен. Для чего-то такого простого, как Undo или Redo, у нас есть сумасшедший список противоречивых ответов. И я даже не вдавался ни в один из связанных ответов. FWIW, я попробовал вариант этого с простым линейным набором коммитов и, наконец, просто сдался.
Snowcrash

49

Все, что вам нужно для ясного, а не отсоединенного состояния головки, - это сброс, а не проверка.

git reset HEAD@{1}

5
или git reset "HEAD@{1}"в определенных оболочках, таких как fish и powershell ... git reflogтакже может быть полезно для поиска правильной фиксации.
Стив Кук

1
Всегда используйте одинарные кавычки в командах оболочки, если вы явно не хотите, чтобы оболочка пыталась интерпретировать / расширять содержимое. Это особенно важно в таких случаях, когда цель состоит в том, чтобы предотвратить интерпретацию командным интерпретатором специальных символов. Таким образом, вам не нужно знать, содержит ли строка что-нибудь проблемное.
Крис Пейдж

Я сделал это, чтобы оглянуться назад во времени, потом я сделал, git reset HEADчтобы вернуться туда, где я был ... теперь я понятия не имею, в каком состоянии находится мой репозиторий, и все страшно. Что мне теперь делать?
theonlygusti

48

Я верю, что вы можете:

git reset HEAD@{1}

Сделать один коммит вперед во времени. Чтобы перейти к нескольким коммитам, используйте HEAD @ {2}, HEAD @ {3} и т. Д.


20

Это то, что я использую для навигации взад и вперед.

переход к следующей фиксации

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

переход к предыдущей фиксации

function p() {
    git checkout HEAD^1
}

Спасибо! Я использую это сейчас! Примечания для других новичков, таких как я : чтобы повторно подключить HEAD, git checkout <current branch>прикрепляется к последней фиксации. git checkout -b <new-branch-name>из текущего коммита позволяет вносить изменения в новую ветку.git rebase -iтоже работает. Кроме того , я назвал свою n()функцию, nx()чтобы избежать конфликта с диспетчером версий узлов "n". Обязательно проверьте псевдонимы!
Стивен Чой

function () {...} предназначена для создания файла сценария bash для Unix / Linux, я работаю в Windows, что сначала мне немного сложно понять
IcyBrk

9

Скажем, F - это последний коммит trunk(вставьте здесь свое собственное имя ветки) ... вы можете ссылаться на него как trunk~0(или просто trunk), E как trunk~1, D как trunk~2и т. Д.

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


1
~ идет назад, а не вперед, ствол ~ 2 - A
EmmanuelMess

Да. В этом ответе предполагается, что у вас есть ветка с именем trunk, на которую указывает F, и что вы знаете, куда в истории этой ветки вы хотите перейти. Он не пытается двигаться вперед относительно HEAD, но менее далеко назад относительно туловища.
Бесполезный

@theonlygusti Вы дважды возвращаетесь из HEAD.
EmmanuelMess

Вы все еще предполагаете, что ветка trunkи ваш ток HEADидентичны, что не показано в вопросе, что, как я сказал, не является тем, что я предполагаю, и что очень маловероятно на полпути черезbisect
Бесполезно

3

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

  function git_down
        git checkout HEAD^
  end

При перемещении вперед вы движетесь вверх по дереву, поэтому вам нужно четко указать, на какую ветку вы нацеливаетесь:

  function git_up 
        git log --reverse --pretty=%H $argv | grep -A 1 (git rev-parse HEAD) | tail -n1 | xargs git checkout
  end

Использование: git down,git up <branch-name>


Обратное движение тоже не совсем уникально, когда речь идет о слияниях. Хотя HEAD^обычно это разумное значение по умолчанию.
kdb

2

Если вы хотите заглянуть вперед, вы можете проделать этот трюк, поскольку в Git нет строгой команды для этого.

git log --reverse COMMIT_HASH..

пример

Список хэшей истории логов:

A
B
C -> put this
D

используя команду git log --reverse C.., на выходе вы увидите , B и A .


1

Возможно, не самый лучший способ, но вы можете использовать его git logдля просмотра списка коммитов, а затем использовать git checkout [sha1 of D]для перехода к D.


6
Я не понимаю, если он в C, то git log покажет ему только C, B и A.
Билтон,

Хорошо, понял, но вам придется сделать хитрый git-log, как указано в ссылке, предоставленной VonC
Bilthon

1

Я только что проверил это. скажем, например, вы находитесь в главной ветке Затем выполните:

git checkout HEAD@{3}

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

git checkout HEAD@{4}

Когда вы закончите осматриваться, вы можете вернуться в исходное состояние, просто зайдя в эту ветку. В моем примере: главная ветка

git checkout master

Если вы не хотите переходить в исходное состояние и хотите, чтобы одна из коммитов была вашей головой и продолжала оттуда, вам нужно оттуда разветвляться. например, после "git checkout HEAD @ {4}" вы можете ввести

git checkout -b MyNewBranch

0

В качестве обходного пути вы можете просто вернуться к HEAD с помощью

git checkout <branch>

А затем перейдите к желаемой фиксации с помощью

git checkout HEAD~<offset>

0

Если вы используете vs code, то история Git - отличный плагин, в котором вы можете эффективно видеть коммиты и проверять их содержимое в самом редакторе. проверьте ссылку


0
branchName=master; commitInOrder=1; git checkout $(git log --pretty=%H "${branchName}" | tac | head -n "${commitInOrder}" | tail -n 1)

где:

branchName равно имени ветки

commitInOrder равно фиксации в порядке от самой первой фиксации в выбранной ветке (так, 1 - самая первая фиксация, 2 - вторая фиксация в ветке и т. д.)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.