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
и раздавить, но когда возникают конфликты, мне становится сложно.