Git поддельные кабачки

Что-то не так с этим рабочим процессом для получения аналогичного результата от сквоша?

  • Оформить заказ на новую ветку от мастера под названием draft_feature_a
  • Сделайте кучу коммитов. Некоторые коммиты нарушают код. У некоторых есть небрежные сообщения о коммите.
  • Оформить заказ мастеру, а из мастер-кассы новая ветка называется feature_a
  • извлеките окончательные изменения из черновика, выполнив git checkout draft_feature_a $(git diff --name-only master draft_feature_a)

Теперь у вас есть только последние изменения, и вы можете зафиксировать их с красивым сообщением фиксации.

3 ответа

Решение

Он не будет захватывать удаления файлов, например:

$ git checkout draft_feature_a $(git diff --name-only master draft_feature_a)
error: pathspec 'ttt.py' did not match any file(s) known to git.

Вы можете сделать то же самое с реальными rebase-and-squash-etc (я использовал "fixup" ниже, почти то же самое, правда; оригинальные коммиты все еще можно просмотреть на draft_feature_a):

$ git checkout -b draft_feature_a
[work, commit, etc - I made two commits: add newfile and rm ttt.py]
$ git checkout master
Switched to branch 'master'
$ git checkout -b feature_a
Switched to a new branch 'feature_a'
$ git merge draft_feature_a
Updating 523bacb..3a486fc
Fast-forward
 newfile |  0
 ttt.py  | 14 --------------
 2 files changed, 14 deletions(-)
 create mode 100644 newfile
 delete mode 100644 ttt.py
git rebase -i master
[edit to make everything but the first a "fixup"]
...
 2 files changed, 14 deletions(-)
 create mode 100644 newfile
 delete mode 100644 ttt.py
Successfully rebased and updated refs/heads/feature_a.
$ git commit --amend
[edit commit message]

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

(во-первых, давайте очистим предыдущий пример)

$ git checkout master
Switched to branch 'master'
$ git branch -D draft_feature_a
Deleted branch draft_feature_a (was 3a486fc).
$ git branch -D feature_a
Deleted branch feature_a (was 0fc36f0).

(теперь новый пример)

$ git checkout -b feature_a
Switched to a new branch 'feature_a'
[work work work]
[time to clean up, let's stick a label on this version so I can find it easily:]
$ git branch messy_feature_a feature_a
$ git rebase -i master

После того, как ребаз сделан, все сжато, исправлено, переставлено, отредактировано сообщение (я) и т. Д., И если я решу, что я что-то испортил, все мои "черновые" (некачественные / грязные) работы все еще доступны по имени под "грязным" именем. Когда я удовлетворен и не хочу старого имени, я удаляю его вручную (git branch -D).

Хитрость в понимании этого состоит в том, что каждый раз, когда вы делаете что-то в git, вы только добавляете новые коммиты. Старые хранятся в вашем репо, пока (в конце концов) вы не сделаете что-то неявное или явное, чтобы "собрать мусор" их. Пока у них есть имя метки ветви (или другое "видимое" имя, например, тег), которое делает коммит доступным для имени чем-то другим, кроме 3a486fc стиль имен SHA1, они длятся "навсегда". Удаление ветки просто стирает метку. Через месяц или три немаркированные коммиты, наконец, собираются для сбора мусора. (Точнее, у него все еще есть имя в reflog, пока срок его действия не истечет: записи reflog имеют ограничение по времени. См. Документацию для git reflogособенно --expire=<time> параметр.)

Точно так же "rebase" делает новую серию коммитов, оставляя там все старые коммиты. Когда перебазирование закончено, git снимает метку с конца старой серии коммитов и вставляет ее в конец новой серии коммитов:

A -- B -- C          [label: master]
           \
            D -- E   [label: feature_a]

[rebase feature_a on master, and squash or fixup to make commit DE which is D+E]

A -- B -- C          [label: master]
          | \
          |  D -- E  [no label!]
          \
            DE       [label: feature_a]

Если вы добавите дополнительную метку перед выполнением ребазирования, то current-branch feature_a метка снимается и перемещается в новый коммит (ы), но другая метка (messy_feature_a) останавливается и дает вам легкий доступ для фиксации E и, следовательно, всей цепочки (D и E разветвляются от C).

Кажется, вы работаете в Linux-системе $(git..., Это должно работать и позаботится об удаленном файле:

git checkout -b feature_a master
git diff draft_feature_a | patch -p1 -R

Это мой новый рабочий процесс:

  • Оформить заказ на новую ветку от мастера под названием draft_feature_a
  • Сделайте кучу коммитов. Некоторые коммиты нарушают код. У некоторых есть небрежные сообщения о коммите.
  • сливаться master в draft_feature_aи разрешать любые конфликты.
  • от draft_feature_a оформить заказ на новую ветку final_feature_a (git checkout -b final_feature_a)
  • git reset --soft master
  • Теперь у вас есть только последние изменения, и вы можете зафиксировать их с красивым сообщением фиксации.

Я знаю, что могу сделать все это с git rebase -i master и раздавить, но когда возникают конфликты, мне становится сложно.

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