Статьи

Git — давайте сделаем ошибки (и научимся их исправлять)

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

Позвольте мне начать давать кредиты для моего источника: http://osteele.com/posts/2008/05/my-git-workflow и http://longair.net/blog/2009/04/16/git-fetch- и-слияние /. Я нашел эти статьи интересными и полезными, в первую очередь, в частности, но они уже говорят

слишком много вещей для упрощенной модели, которая мне нужна . Давайте предположим, что вы уже являетесь пользователем git . У вас есть локальное репо, удаленное, которое использовалось для работы. И вы также знаете о существовании филиалов и используете их. Но, тем не менее, благодаря этим базовым знаниям у вас возникает чувство неуверенности в своих действиях.

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

Мне нравится думать в промежуточной области (то место, где ваши изменения отслеживаются, когда вы выполняете операцию git add, как способ сделать ‘ более легкую фиксацию ‘). То, что я имею в виду при более легкой фиксации, это то, что вы не обязаны оставьте комментарий к этому действию, у вас меньше ограничений. И поскольку вы еще даже не сохраняете свое действие, вам явно рекомендуется выполнять добавление гораздо чаще, чем фиксировать . Давайте приведем сценарий для нашего варианта использования добавления: процесс добавления некоторые новые функциональные возможности для вашей кодовой базы, возможно, они связаны с созданием новых файлов и идей, которые просто приходят вам в голову неупорядоченным образом.

Чтобы привести пример, давайте представим, что вы создаете 2 файла со ссылкой друг на друга. Может быть, файл исходного кода и его файл конфигурации. Вы создаете первое и начинаете над ним работать. Когда вы закончите работу над ним, вы можете подумать о его фиксации , но поскольку ваша логическая единица работы не завершена, пока вы не создадите файл конфигурации, у вас есть возможность выполнить упомянутый «более легкий коммит», то есть простое добавление. , После того, как вы закончили работу с файлом конфигурации, вы должны добавить его в индекс, и теперь вы можете его зафиксировать. Или, если вы предпочитаете, вы можете выполнить git commit -a, чтобы получить тот же результат. Так как мы дали пример использования для промежуточной области, должно быть проще понять его роль в рабочем процессе git. Это логическое место между текущим неотслеживаемым каталогом и зафиксированным (и безопасным) хранилищем. Мы называем это «местом», поэтому можем предположить, что нам интересно взаимодействовать с ним. Уже хорошо известный способ поместить вещи в это — команда:

1
git add

и у него есть 2 сопутствующие команды, которые вы будете использовать очень часто:

1
git diff

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

1
2
3
4
5
touch test.txt
echo 'text' >> test.txt
git add test.txt
echo 'added1' >> test.txt
git diff

возвращает этот вывод:

1
2
3
4
5
6
7
8
9
gittest$ git diff
 
diff --git a/test.txt b/test.txt
index 8e27be7..2db9057 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
 text
+added1

Хорошо, теперь мы можем видеть различия между нашей рабочей папкой и контекстом отслеживания. Очевидно, что мы можем отследить новую модификацию с помощью команды добавления, но мы хотим также возможность выбросить нашу модификацию . Это получается с

1
git checkout .

Git checkout без параметров (отличных от ‘dot’, представляющих текущую папку) отбросит изменение ваших файлов и вернет статус к тому, который отслеживался в промежуточной области с помощью предыдущих команд добавления.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
gittest$ git status
 
# On branch master
# Changes to be committed:
#   (use 'git reset HEAD <file>...' to unstage)
#
#    new file:   test.txt
#
# Changes not staged for commit:
#   (use 'git add <file>...' to update what will be committed)
#   (use 'git checkout -- <file>...' to discard changes in working directory)
#
#    modified:   test.txt
#
 
gittest$ git checkout .
 
gittest$ git status
# On branch master
# Changes to be committed:
#   (use 'git reset HEAD <file>...' to unstage)
#
#    new file:   test.txt
#

Мы дали смысл области постановки. И мы также можем думать об этом как о самой первой «среде», с которой мы сталкиваемся, поскольку каждая команда без определенных параметров работает на стадии подготовки .

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

Параллельно с тем, что мы только что делали , отмена постановки выполняется с помощью:

1
git checkout HEAD .

Технически это означает, что мы возвращаемся к определенной точке фиксации , последней (HEAD).

Перед тестированием мы должны выполнить пару взаимодействий, поскольку противоречивое поведение git не позволяет нам выполнить тест сразу. Причина в том, что наш файл был «новым», а не «измененным». Это нарушает симметрию, но позвольте мне вернуться к этой концепции позже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@pantinor gittest$ git status
# On branch master
# Changes to be committed:
#   (use 'git reset HEAD <file>...' to unstage)
#
#    new file:   test.txt
#
pantinor@pantinor gittest$ git commit -m 'added new file'
[master f331e52] added new file
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)
pantinor@pantinor gittest$ echo 'added' >> test.txt
pantinor@pantinor gittest$ git status
# On branch master
# Changes not staged for commit:
#   (use 'git add <file>...' to update what will be committed)
#   (use 'git checkout -- <file>...' to discard changes in working directory)
#
#    modified:   test.txt
#
no changes added to commit (use 'git add' and/or 'git commit -a')
pantinor@pantinor gittest$ git add test.txt
pantinor@pantinor gittest$ git status
# On branch master
# Changes to be committed:
#   (use 'git reset HEAD <file>...' to unstage)
#
#    modified:   test.txt
#
pantinor@pantinor gittest$ git checkout HEAD .
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)

Мы только что узнали, как вернуться к чистой ситуации. Теперь мы гораздо меньше боимся места проведения. Но мы все еще плохие пользователи git. Мы всегда забываем выполнить ветвление, прежде чем начинать изменять рабочую папку, как предлагается здесь: http://nvie.com/posts/a-successful-git-branching-model/ В моем случае это часто происходит так: у меня стабильная ситуация чем я начинаю что-то подправлять. Но настройка не линейная, и через несколько минут у меня появилось много измененных файлов. Да, я мог бы поставить их всех и передать их, но я не доверяю себе и не хочу загрязнять основную ветвь. Было бы намного лучше, если бы я был на ветке разработки с самого начала моих модификаций . Что я мог сделать сейчас? Мы можем на лету создать ветку и переключиться на нее.

01
02
03
04
05
06
07
08
09
10
11
12
13
pantinor@pantinor gittest$ echo something >> test.txt
pantinor@pantinor gittest$ git status
# On branch master
# Changes not staged for commit:
#   (use 'git add <file>...' to update what will be committed)
#   (use 'git checkout -- <file>...' to discard changes in working directory)
#
#    modified:   test.txt
#
no changes added to commit (use 'git add' and/or 'git commit -a')
pantinor@pantinor gittest$ git checkout -b dev
M    test.txt
Switched to a new branch 'dev'

В этой новой ветке мы по-прежнему будем получать доступ к общей промежуточной области, как вы можете видеть из моего вывода:

1
2
3
4
5
6
7
8
9
pantinor@pantinor gittest$ git status
# On branch dev
# Changes not staged for commit:
#   (use 'git add <file>...' to update what will be committed)
#   (use 'git checkout -- <file>...' to discard changes in working directory)
#
#    modified:   test.txt
#
no changes added to commit (use 'git add' and/or 'git commit -a')

Что мы хотим сделать сейчас, это добавить рабочую ситуацию в промежуточную стадию и зафиксировать ее, чтобы иметь возможность очистить общую промежуточную область.

01
02
03
04
05
06
07
08
09
10
11
pantinor@pantinor gittest$ git add .
pantinor@pantinor gittest$ git commit -m unstable
[dev 5d597b2] unstable
 1 file changed, 1 insertion(+)
pantinor@pantinor gittest$ git status
# On branch dev
nothing to commit (working directory clean)
 
pantinor@pantinor gittest$ cat test.txt
text
something

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

1
2
3
4
5
6
7
pantinor@pantinor gittest$ git checkout master
Switched to branch 'master'
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)
pantinor@pantinor gittest$ echo test.txt
test.txt

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

Давайте теперь представим другой шаблон, чтобы справиться с другими нашими типичными ошибками . Ситуация похожа на только что описанную, но немного хуже. Опять же, мы не разветвлялись перед тем, как начать играть с кодом, но на этот раз мы также совершали пару раз, прежде чем осознали, что то, что мы сделали, не так хорошо, как мы думали. На этот раз мы хотим сохранить нестабильную ситуацию, но мы хотим убрать ее ( полная перезагрузка ) из текущей ветви. Давайте сделаем пару коммитов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)
pantinor@pantinor gittest$ cat test.txt
text
pantinor@pantinor gittest$ echo 'modification1' >> test.txt
pantinor@pantinor gittest$ git commit -a -m'first commit'
[master 9ad2aa8] first commit
 1 file changed, 1 insertion(+)
pantinor@pantinor gittest$ echo 'modification2' >> test.txt
pantinor@pantinor gittest$ git commit -a -m'second commit'
[master 7005a92] second commit
 1 file changed, 1 insertion(+)
pantinor@pantinor gittest$ cat test.txt
text
modification1
modification2
pantinor@pantinor gittest$ git log
commit 7005a92a3ceee37255dc7143239d55c7c3467551
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 21:05:48 2012 +0000
 
    second commit
 
commit 9ad2aa8fae1cbd844f34da2701e80d2c6e39320e
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 21:05:23 2012 +0000
 
    first commit
 
commit f331e52f41a862d727869b52e2e42787aa4cb57f
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 20:20:15 2012 +0000
 
    added new file

На данный момент мы хотим переместить последние 2 коммита в другую ветку:

1
git branch unstable

Мы создали новую ветку, но мы не переключились на нее. Очевидно, что только что созданная новая ветвь имеет все, что присутствовало на момент ее создания, то есть 2 коммита, которые мы хотим удалить. Таким образом, мы можем вернуть нашу текущую ветку к предыдущей фиксации, полностью отбросив последние, которые останутся доступными в нестабильной ветке . Чтобы увидеть, что это за коммит, к которому мы хотим вернуться:

1
git log

нам нужно прочитать хеш-код, связанный с фиксацией, чтобы иметь возможность выполнить откат ( полный сброс ):

1
2
pantinor@pantinor gittest$ git reset --hard f331e52f41a862d727869b52e2e42787aa4cb57f
HEAD is now at f331e52 added new file

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

1
2
3
4
5
6
7
8
pantinor@pantinor gittest$ cat test.txt
text
pantinor@pantinor gittest$ git log
commit f331e52f41a862d727869b52e2e42787aa4cb57f
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 20:20:15 2012 +0000
 
    added new file

По ветке:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
pantinor@pantinor gittest$ git checkout unstable
Switched to branch 'unstable'
pantinor@pantinor gittest$ cat test.txt
text
modification1
modification2
pantinor@pantinor gittest$ git log
commit 7005a92a3ceee37255dc7143239d55c7c3467551
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 21:05:48 2012 +0000
 
    second commit
 
commit 9ad2aa8fae1cbd844f34da2701e80d2c6e39320e
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 21:05:23 2012 +0000
 
    first commit
 
commit f331e52f41a862d727869b52e2e42787aa4cb57f
Author: Paolo Antinori <pantinor redhat.com='redhat.com'>
Date:   Sun Dec 16 20:20:15 2012 +0000
 
    added new file

Справка: Git — давайте сделаем ошибки (и узнаем, как их исправить) от нашего партнера JCG Паоло Антинори в блоге Someday Never Comes .