мерзавец, молись, люби

Что это за пост

  • Это учебное пособие от новичка до среднего или, возможно, легкое напыление продвинутых тем и практик git.
  • Это практично.

Чем не является этот пост

  • Это не философия или теория. (Я не буду обсуждать плюсы и минусы слияния и перебазирования. Вы можете сражаться в этой битве где угодно.)
  • Это не супер сложный или чрезмерно архаичный.
  • Это не проповедь (см. Первый пункт).
  • Это ни в коем случае не является исчерпывающим. Это список команд, советов, приемов и инструментов git, которые я лично считаю очень полезными и использую почти каждый день.

Это ряд вещей, с которыми я часто обнаруживаю, что люди борются, не знают, как это сделать или имеют странные способы получить эту информацию. Возможно, вы уже знаете некоторые или все из них. Но я решил, что напишу это и, надеюсь, завяжу разговор о мерзавце. Я надеюсь, что вы найдете здесь что-то полезное, и я надеюсь, что это сэкономит ваше время. ПРИМЕЧАНИЕ: я лично использую Fish Shell. Я передал в Bash любой специфический для Fish Shell синтаксис, так как 90% из вас, читающих это, вероятно, используют Bash.

Ярлык для создания новой ветки и перехода на нее

$ git branch foo && git checkout foo 
$ git checkout -b foo # same as above command

Измените свой редактор для сообщений фиксации

Предположим, у вас установлен инструмент командной строки Sublime или TextMate.

$ git config --global core.editor 'subl -w' # Sublime 
$ git config --global core.editor 'mate -w' # TextMate 
$ git config --global core.editor vim # The Lord's way
$ git config --global core.editor emacs # Insanity

Разница между удаленным и локальным

$ git status 
On branch test_branch 
Your branch is ahead of 'origin/test_branch' by 1 commit. (use "git push" to publish your local commits) 
nothing to commit, working directory clean 
$ git diff # returns nothing because there is nothing different between our locals 
$ git diff git-talk # same exact thing as above. git-talk here refers to your local 
$ git diff jsatk/git-talk # diffs between remote and current local branch 
diff --git a/foo.txt b/foo.txt 
index 257cc56..5716ca5 100644 
--- a/foo.txt 
+++ b/foo.txt 
@@ -1 +1 @@ 
-foo 
+bar 
$ git diff jsatk/git-talk git-talk # diffs between remote and specified local branch 
diff --git a/foo.txt b/foo.txt 
index 257cc56..5716ca5 100644 
--- a/foo.txt 
+++ b/foo.txt 
@@ -1 +1 @@ 
-foo 
+bar

Но, Джесси, в этом нет необходимости. В git status я ясно вижу, что у меня есть еще не продвинутая фиксация . Вы правы. Это не лучший пример использования в мире. Однако я использую это чаще всего, когда мне нужно посмотреть, какие изменения могут быть внесены, или чтобы различить мою ветку и главную. Если я был в функциональной ветке несколько дней и хочу увидеть разницу между моей функциональной веткой и основной, выполняющей git diff, master feature_branch будет различать только мою локальную копию master и мою feature_branch. Что я делаю в этих ситуациях, так это git fetch origin && git diff origin / master feature_branch. Выборка здесь важна. (Примечание: если вы не понимаете разницу между извлечением и извлечением, я настоятельно рекомендую вам потратить 15 минут, чтобы прочитать.)

Как извлечь файл из одной ветки в другую

$ git checkout -b baroness 
Switched to a new branch 'baroness' 
$ echo 'red album' > albums.txt 
$ cat albums.txt 
red album 
$ git add --all && git commit -m 'Added albums.txt' 
[baroness 728f16f] Added albums.txt 
1 file changed, 1 insertion(+) 
create mode 100644 albums.txt 
$ git checkout -b mastodon 
Switched to a new branch 'mastodon' 
$ echo 'once more round the sun' > albums.txt
$ cat albums.txt 
once more round the sun 
$ git add --all && git commit -m 'Added albums.txt' 
[mastodon 6fea3ec] Added albums.txt 
1 file changed, 1 insertion(+), 1 deletion(-) 
$ git show baroness:albums.txt # Prints the contents of albums.txt from branch baroness red album 
$ git checkout baroness -- albums.txt # Checks out baroness' version of albums.txt to branch mastodon # This is a perfect example of the insanity of git. You use : to show between branches but -- to checkout. 
$ cat albums.txt # now this branch's albums.txt is the same as baroness' red album

Это на удивление часто всплывает для меня. Я гораздо больше использую функцию шоу. Вариант использования может быть, если я знаю моего коллегу и работаю над одним и тем же файлом. Он объединил свою ветку в главную, я нахожусь на feature_branch. Затем я выполню git fetch && git show origin / master: file / coworker / и / i / are / working / on.js. Затем это позволяет мне легко увидеть, повлияет ли его новая работа на мою текущую работу, и даст ли мне знать, нужно ли мне исправить курс.

Вы можете объединить несколько сокращенных флагов в один

$ git commit -n -m 'This is a commit message.' 
$ git commit --no-verify --message='This is a commit message.' 
$ git commit -nm 'This is a commit message.' # This is the same as the above two!

Вы можете комбинировать абзацы из командной строки с сообщением коммита git!

$ git commit -m Hello -m is -m it -m me -m you\'re -m looking -m for\? 
$ git log -1 # Using -Number limits the log to that number of commits. 
commit facbbb49d88182b50d8383323acae6696e33ff63 
Author: Jesse Atkinson <[email protected]> 
Date: Tue Apr 21 19:12:44 2015 -0700 
Hello 
is 
it 
me 
you're 
looking 
for?

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

Спрятать с сообщением и спрятать неотслеживаемые файлы

В начале я сказал, что не собираюсь проповедовать. Я врал. Всегда храните сообщение. Просто сделай это. Нет. Нет. Тише. Сделай это.

$ git checkout -b pikachu
Switched to a new branch 'pikachu'

$ echo 'lightning bolt' > attacks.txt

$ git status --short
?? attacks.txt

$ git stash save --include-untracked 'Creating attacks file for Pikachu.' # Shorthand for --include-untracked is -u
Saved working directory and index state On pikachu: Creating attacks file for Pikachu.
HEAD is now at 33b6d46 Bug fix for ad scrapers. Have to specify placement when inserting iPad and iPhone into iOS product.

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

$ git stash list
stash@{0}: On pikachu: Creating attacks file for Pikachu.

$ git stash show # In general this command isn't very useful. Just show's a diff of lines changed. But it's particularlly useless at this point. It doesn't show anything because attacks.txt isn't tracked by git. Git can only tell you information about things it has been told to track.

$ git stash pop && git add --all && git commit -m 'Initial commit of attacks.txt for Pikachu.'

$ echo 'shock' >> attacks.txt
$ git diff
diff --git a/attacks.txt b/attacks.txt
index e8eb403..4642b97 100644
--- a/attacks.txt
+++ b/attacks.txt
@@ -1 +1,2 @@
lightning bolt
+shock

$ git stash save 'added shock to the list of attacks'
Saved working directory and index state On pikachu: added shock to the list of attacks
HEAD is now at 97921a2 Initial commit of attacks.txt for Pikachu.

$ git stash show 'stash@{0}' -p # NOTE: the -p argument is short for --patch
diff --git a/attacks.txt b/attacks.txt
index e8eb403..4642b97 100644
--- a/attacks.txt
+++ b/attacks.txt
@@ -1 +1,2 @@
lightning bolt
+shock

По умолчанию git stash не хранит неотслеживаемые файлы. В конце добавьте -u. Кроме того, список git stash показывает ваши тайники, однако сообщение по умолчанию, которое он сохраняет с ним, - это сообщение о последней фиксации и ветке, в которой вы его спрятали. Это… супер бесполезно. Не забудьте добавить save в свою команду git stash и следовать за ней сообщением. Ты действительно умный. Вы также заняты и совершенно забудете, что, черт возьми, у вас в тайниках, если пройдет больше, чем, скажем, 15 минут. Я обещаю тебе. Затем, когда вы придете на следующий день и запустите git stash list и увидите список тайников с сообщениями о фиксации, которые не имеют ничего общего с работой в тайнике, вам захочется кричать.

Получите ваши спрятанные вещи!

git stash apply stash @ {3} применит четвертое (нулевое) содержимое тайника к вашей текущей ветке, и тайник останется в списке тайников. Однако git stash pop stash @ {3} удалит четвертый тайник из списка, перемещая все тайники после него вверх на единицу в индексе. Поп, вероятно, вы хотите чаще всего, но он также более опасен по понятным причинам. Если вы предпочитаете использовать apply, вы можете безопасно запустить git stash drop stash @ {3} после того, как освоитесь с избавлением от этого тайника.

С помощью git stash list тайники переиндексируются после того, как вы удалите тайник. Допустим, у вас есть три тайника. Если вы попытаетесь сделать что-то вроде этого git stash drop stash @ {1} && git drop stash @ {2}, это не удастся, потому что тайник с индексом 2 теперь находится в индексе 1 после удаления тайника в индексе 1. При удалении нескольких тайников удалите из индекса с самым высоким номером вниз или ... просто будьте очень осторожны.

Очистите себя с помощью git rebase - интерактивно

Я люблю совершать много и часто. В конце функциональной ветки у меня куча дерьмовых коммитов. Я просто так работаю. Они не будут никому полезны после того, как это будет объединено с мастером. И когда-нибудь, если они обнаружат ошибку и должны будут сделать git винить и увидят, что Джесси зафиксировал этот код шесть месяцев назад с сообщением коммита «WIP. Исправленное дерьмо ». они собираются (справедливо) проклясть мое имя. Не будем этим человеком. Давайте использовать интерактивную перестановку.

$ git rebase --interactive branch_you_want_to_rebase_against_typically_master # That's it! You can also use the shorthand -i flag.

Это очень, ну, интерактивный режим. Git действительно держит вас за руку и дает много приятных сообщений. Когда вы запустите этот git, откроется ваш текстовый редактор и будет список всех коммитов в вашей ветке, которых нет в той ветке, против которой вы выполняете ребазинг.

# Rebase c4758c3..c4758c3 onto c4758c3 (1 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

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

Интерактивно добавляйте свои изменения на этап фиксации

$ git add --patch

Примечание. Это работает только с файлами, которые уже отслеживаются git. Он не работает с неотслеживаемыми файлами. Сплит супер мощный и удобный. Если становится очень сложно, вы можете использовать e, чтобы вручную отредактировать кусок.

Из справки:

Stage this hunk [y,n,q,a,d,/,e,?]? 
y — stage this hunk 
n — do not stage this hunk 
q — quit; do not stage this hunk or any of the remaining ones a — stage this hunk and all later hunks in the file 
d — do not stage this hunk or any of the later hunks in the file 
g — select a hunk to go to / — search for a hunk matching the given regex 
j — leave this hunk undecided, see next undecided hunk 
J — leave this hunk undecided, see next hunk 
k — leave this hunk undecided, see previous undecided hunk 
K — leave this hunk undecided, see previous hunk 
s — split the current hunk into smaller hunks 
e — manually edit the current hunk 
? — print help

При сравнении убедитесь, что вы сравниваете с последней удаленной версией с помощью fetch

$ git diff master # diffs current branch against your local copy of master
$ git diff origin/master # will probably do the same thing as above in *most* scenarios.
$ git fetch origin && git diff origin/master # diffs current branch against what is *truly* on remote master

Сдавите коммит, если ветка действительно беспорядочная

Если история коммитов вашей ветки представляет собой полный беспорядок, но вы знаете, что хотите, чтобы сейчас была другая ветка (скорее всего, главная), сквош - ваш друг.

$ git commit -m 'ugh'
[new_branch bacb008] ugh
1 file changed, 10 insertions(+), 2 deletions(-)

$ git checkout master
Switched to branch 'master'

$ git merge new_branch --squash
Updating 051c56b..bacb008
Fast-forward
Squash commit -- not updating HEAD
README.md           | 20 ++++++++++++++++++--
awesometextfile.txt |  3 +++
2 files changed, 21 insertions(+), 2 deletions(-)

$ git branch --merged # To list local branches that have not been merged run --no-merged
* master

$ git branch -d new_branch
error: The branch 'new_branch' is not fully merged.
If you are sure you want to delete it, run 'git branch -D new_branch'.

$ git branch -D new_branch
Deleted branch new_branch (was bacb008).

Что, если мне нужен всего один коммит из одной ветки в другую?

$ git checkout branch_you_want_to_move_commit_to && git cherry-pick 240982d # You don't need the full sha, just enough that git understands it.

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

Джесси, а что, если я хочу понять, какой коммит сломал мою любимую фичу ?!

Bisect - твой друг! (Серьезно, документы стоит прочитать.)

$ git bisect start
$ git bisect bad # without passing a SHA it uses HEAD
$ git bisect good SHAofLastGoodKnownCommit
# At this point git takes over and tells you how many rivisions to test. Through a series of good and bad confirmations it will then tell you the bad commit.
# Shoot off an email or slack message to the author with the commit sha or fix yourself if you're confident of the intended change in the commit or if you're the author
$ git bisect reset # DO NOT FORGET TO DO THIS PLEASE. IF YOU FORGET YOU WILL BE VERY ANGRY LATER.

Больше различий!

$ git diff ref1:path/to/file1 ref2:path/to/file2 
$ git diff origin/master -- [path/to/file] # Much simpler if you're diffing the same file at the same path.

Сброс тоже может быть нежным, ты знаешь

Если есть фиксация, которую вы просто не хотите иметь и хотите ее исправить, и она не была отправлена ​​в удаленную ветвь, но используйте сброс - soft

$ git reset --soft HEAD~1

Ну наконец то

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

использованная литература

Первоначально опубликовано на jesseatkinson.org.