Возврат определенных коммитов из git

У меня есть дерево git с большим количеством коммитов и большим количеством файлов. Теперь я хочу вернуть конкретные коммиты, которые касаются только файла. Объяснить:

 psankar@linux-9dni:~/specific> git init
Initialized empty Git repository in /home/psankar/specific/.git/
psankar@linux-9dni:~/specific> echo "File a" > a
psankar@linux-9dni:~/specific> git add a ; git commit -m "File a"
[master (root-commit) 5267c21] File a
 1 file changed, 1 insertion(+)
 create mode 100644 a
psankar@linux-9dni:~/specific> echo "File b" > b
psankar@linux-9dni:~/specific> git add b; git commit -m "File b"
[master 7b560ae] File b
 1 file changed, 1 insertion(+)
 create mode 100644 b
psankar@linux-9dni:~/specific> echo "File c" > c
psankar@linux-9dni:~/specific> git add c; git commit -m "File c"
[master fd6c132] File c
 1 file changed, 1 insertion(+)
 create mode 100644 c
psankar@linux-9dni:~/specific> echo "b and c modified" > b ; cp b c
psankar@linux-9dni:~/specific> git commit -a -m "b and c modified"
[master 1d8b062] b and c modified
 2 files changed, 2 insertions(+), 2 deletions(-)
psankar@linux-9dni:~/specific> echo "a modified" > a
psankar@linux-9dni:~/specific> git commit -a -m "a modified"
[master 5b7e0cd] a modified
 1 file changed, 1 insertion(+), 1 deletion(-)
psankar@linux-9dni:~/specific> echo "c modified" > c
psankar@linux-9dni:~/specific> git commit -a -m "c modified"
[master b49eb8e] c modified
 1 file changed, 1 insertion(+), 1 deletion(-)
psankar@linux-9dni:~/specific> git log --pretty=oneline c
psankar@linux-9dni:~/specific> git log --pretty=oneline c | cat
b49eb8e03af331bddf90342af7d076f831282bc9 c modified
1d8b062748f23d5b75a77f120930af6610b8ff98 b and c modified
fd6c13282ae887598d39bcd894c050878c53ccf1 File c
psankar@linux-9dni:~/specific>

Теперь я хочу вернуть только две коммиты b49eb8e03af331bddf90342af7d076f831282bc9 и 1d8b062748f23d5b75a77f120930af6610b8ff98, не возвращая изменения в a. IOW возвращает только коммиты в файле (не возвращая другие промежуточные коммиты (которые могут быть тысячи в числе) в разных файлах) Как это возможно?

41
задан Sankar P 02 дек. '13 в 12:17
источник поделиться

2 ответов

Вы можете использовать git revert с опцией --no-commit. В вашем примере:

$ git revert --no-commit b49eb8e 1d8b062
# Files that were modified in those 2 commits will be changed in your working directory
# If any of those 2 commits had changed 'a' then you could discard the revert for it:
$ git checkout a
$ git commit -a -m "Revert commits b49eb8e and 1d8b062"

Если вы не укажете сообщение фиксации, тогда готовое сообщение будет доступно при запуске редактора сообщений фиксации.

Если вы опустите параметр --no-commit, то изменения в объявленных вами коммандах будут отменены. Это достигается путем применения обратных изменений в указанных коммитах и ​​совершения этого. Это приведет к новой фиксации, и исходная, и реверсивная фиксация будут в истории вашего репозитория.

65
ответ дан mamapitufo 02 дек. '13 в 12:57
источник поделиться

Здесь два случая:

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

  • Если вы никогда не подталкивали ветку, что изменения включены, и вы можете изменить историю. В этом случае вы можете полностью удалить нежелательные коммиты. Это будет содержать историю и означает, что вы не подталкиваете неправильное обращение к своим коллегам или общественности.

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

git rebase -i 23def8231

или если вы начали с ветки origin/dev_branch и выполнили работу, которая включает в себя биты для удаления в вашей ветке с именем dev_branch, вы могли бы сделать

git rebase -i origin/dev_branch

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

Теперь проще всего удалить коммиты. Вы делаете это, удаляя строку или добавляя #, которая указывает комментарий к началу строки. (В файле уже есть некоторые комментарии, чтобы объяснить вам все это. Игнорирование этих или удаление их не имеет эффекта.)

Когда вы закончите, сохраните файл и выйдите из редактора. Перестановка происходит следующим образом: git возвращается к объявлению, которое вы назвали. Он просматривает список, который вы сохранили, и повторяет каждую фиксацию в этом списке. Затем он делает результат этого процесса новой версией ветки, из которой вы были первоначально.

Важные вещи для запоминания:

  • Если вы потерялись или удалите слишком много строк, вы можете отменить rebase, удалив каждую строку фиксации в файле и сохраните. Отмена будет отменена.
  • Возможно создание конфликтов. Например, если вы удаляете коммит, который редактирует файл, и оставляете в дальнейшем коммит, который редактирует одно и то же место. Позднее фиксация теперь будет неправильно применяться, и вам нужно будет вручную отредактировать или в инструменте слияния, чтобы получить нужную версию.

Вы также можете сделать много других манипуляций в git rebase -i. Например, изменение порядка коммитов, сложение нескольких вместе в один, добавление дополнительных изменений между фиксациями или изменение сообщений. Это очень полезно. Классический вариант использования - очистка вашей локальной ветки, прежде чем вы нажмете ее обратно туда, где другие люди будут смотреть на ваши изменения.

10
ответ дан jwg 11 окт. '15 в 2:14
источник поделиться

Другие вопросы по меткам