Столкнулся с этим впервые, другой проект нормально залился в репозиторий.
Вот порядок действий:
Захожу в локальную папку проектаcd ~/project
Инициализирую гитgit init
Фоловлю файлыgit add .
И тут он пишет мне:
warning: LF will be replaced by CRLF in *file_name*
The file will have its original line endings in your working directory.
После чего выполняю коммит и он пишет:
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
В гите новичок. Гуглил, способы решения не подошли.
-
Вопрос заданболее трёх лет назад
-
34783 просмотра
Пригласить эксперта
Инициализируем новый репозиторийgit init
Добавляем файлы (все)git add .
Если файлы не добавляются, то добавляем каждый вручнуюgit add README.md
Делаем коммитgit commit -m "First commit"
Пушимgit push -u origin master
warning: LF will be replaced by CRLF in *file_name*
The file will have its original line endings in your working directory.
Здесь всего-лишь говорится, что перенос строки будет дополнен возвратом каретки.
Связанно это с тем что переносы строк были в Unix-формате, так как дело происходило под Windows.
Простые решения:
Очень просто конвертировать переносы строк в Windows-формат помогает текстовый редактор Notepad++: Правка→EOL конверсия→Преобразовать в WIN-формат.
Подробнее.
Вручную преобразовать символы перевода строки из виндовых в линуксовые, открыть файл, еще раз визуально все проконтролировать и сохранить.
Быстро заменить CRLF на LF можно утилитой dos2unix, входящей в MINGW, с которым поставляется git для win32:
dos2unix.exe -f -D *file*
-
Показать ещё
Загружается…
09 февр. 2023, в 22:06
500 руб./за проект
09 февр. 2023, в 22:01
50000 руб./за проект
09 февр. 2023, в 22:00
1 руб./за проект
Минуточку внимания
Если вы хотите получше узнать те части Git, про которые раньше боялись спросить, то этот список для вас. Тут собраны наиболее типичные ситуации и способы их решения как из личного опыта автора, так и собранные по всему Интернету.
Ошибка в комментарии к коммиту
Если коммит ещё не был отправлен на сервер (push), то можно воспользоваться простой командой, позволяющей редактировать текст сообщения к последнему коммиту:
git commit —amend
Как отменить последний коммит?
Можно использовать git reset
, вот так:
git reset —hard HEAD~1
HEAD~1 означает один коммит до HEAD, т.е. до текущего положения. Стоит заметить, что это «ядерный» способ, который отменит все изменения. Если вам нужно сохранить всё, что вы сделали, но еще не успели закоммитить, используйте:
git reset —soft HEAD~1
Удалить ветку на сервере
git push origin —delete имя_ветки
В чём разница между «git pull» и «git fetch»?
git pull
— это, по сути, git fetch
, после которого сразу же следует git merge
. git fetch
получает изменения с сервера и сохраняет их в refs/remotes/
. Это никак не влияет на локальные ветки и текущие изменения. А git pull
вливает все эти изменения в локальную копию.
Как отменить «git add» до коммита?
Вы выполнили git add имя_файла
случайно и хотите отменить добавление файла. Если коммит ещё не был сделан, то поможет:
git reset имя_файла
Как разрешать конфликты слияния?
Используйте программу git mergetool
, которая предоставляет удобный интерфейс для разрешения конфликтов.
Осторожно! Лучше сделайте перед этим бэкап.
git clean -f -d
Клонировать все ветки с сервера
Скорее всего, вы это уже сделали, а ветки просто скрыты. Вот команда, чтобы показать их:
git branch -a
Можно использовать git checkout origin/имя_ветки
, чтобы посмотреть на нужную ветку. Или git checkout -b имя_ветки origin/имя_ветки
, чтобы создать локальную ветку, соответствующую удалённой.
Переименовать локальную ветку
git branch -m oldname newname
Вернуться к любому коммиту
Можно использовать git reset
, как показано ранее. Это будет означать, что вы хотите навсегда вернуться к тому состоянию, в котором вы были, а не просто посмотреть на него (для этого надо сделать checkout). Идентификатор коммита должен быть такой, какой прописан в выводе команды git log
.
git reset —hard идентификатор_коммита
Ещё раз повторим: команда отменит все текущие изменения, так что убедитесь, что вам это действительно нужно. Или используйте —soft вместо —hard.
Удалить подмодуль (submodule)
Создание подмодулей используется довольно редко, но иногда они всё-таки встречаются. Вот, что вам нужно:
git submodule deinit submodulename
git rm submodulename
git rm —cached submodulename
rm -rf .git/modules/submodulename
Перезаписать локальные файлы во время git pull
Вам снова поможет git reset
:
git fetch —all
git reset —hard origin/master
Как добавить пустую директорию в репозиторий?
Никак! Такая возможность просто не поддерживается, т.к. считается, что вам это не нужно. Но есть один трюк. Можно создать файл .gitignore
в нужной директории со следующим содержимым:
# Игнорируем всё в этой директории
*
# Кроме самого файла .gitignore
!.gitignore
Экспортирование исходников аналогично «svn export»
Используйте git archive
, например, так:
git archive —format zip —output /путь/к/файлу/файл.zip master
Отменить все изменения, кроме тех, что уже добавлены в планируемый коммит
git checkout — .
Создать новую ветку на сервере из текущей локальной ветки
git config —global push.default current
git push -u
Восстановить удалённый файл
Сначала нужно найти последний коммит, где файл ещё существует:
git rev-list -n 1 HEAD — имя_файла
Потом восстановить этот файл:
git checkout найденный_коммит^ — имя_файла
Вернуть один конкретный файл в состояние, в котором он был в каком-либо коммите
Почти как в прошлом примере, только чуть проще:
git checkout идентификатор_коммита имя_файла
Сделать так, чтобы Git игнорировал изменения прав файлов
git config core.fileMode false
Заставить Git помнить пароль при работе с https
Для запоминания на 15 минут:
git config —global credential.helper cache
Можно настроить и более долгий период:
git config —global credential.helper «cache —timeout=XXXX»
Перевод статьи «Most common git screwups/questions and solutions»
- →
В предыдущей статье мы прошли базовые команды Git, которые применяются в повседневной работе. В этой публикации продолжим изучение данного инструмента, рассмотрев типичные ошибки при его использовании, а также способы их исправления.
Данная статья не ставит перед собой цель быть энциклопедией решений на все случаи жизни. Было бы неверным давать ответы на вопросы, которые на данном этапе изучения Git просто не могут возникнуть. Любая информация должна соответствовать вашему текущему уровню.
1. Самое простое решение многих проблем
Вы «натворили делов» со своим репозиторием, и вам кажется, что все сломалось и ничего не работает. В качестве максимально быстрого решения этой проблемы можно удалить локальный репозиторий (скрытую папку .git в корне вашего проекта) и репозиторий на GitHub, а затем выполнить git init. При этом ваши файлы удалять не нужно.
Когда я изучал Git, то десятки раз создавал и удалял свои репозитории, сталкиваясь с неразрешимыми для меня на тот момент проблемами.
Этот вариант имеет право на существование для начинающих разработчиков, т. к. они не обладают еще нужным набором знаний для применения более технологичных решений. Но, как вы понимаете, данный способ хорош до поры до времени.
2. Как изменить URL удаленного репозитория?
Вы неверно назвали свой репозиторий, например, вместо StartJava почему-то написали Lesson1 или JavaOps. На что наставник вам сказал, что его нужно переименовать.
Или вы удалили свой репозиторий на GitHub, а у себя на компьютере — оставили. После этого создали новый удаленный репозиторий (УР), изменив его первоначальное имя.
Например, URL репозитория выглядел так:
https://github.com/ichimax/lesson1.git
А после изменений ссылка стала следующей:
https://github.com/ichimax/startjava.git
При этом в настройках локального репозитория (ЛР) адрес старого репозитория никуда не делся — его нужно обновить.
Свяжем ЛР с новым адресом УР:
> git remote set-url origin новый_url.git
> git remote -v
Когда вам в дальнейшем потребуется выполнить push, то необходимо будет написать полную версию команды git push -u origin master, чтобы заново связать ЛР с новым УР, а затем снова можете использовать сокращенный вариант.
3. Как удалить файл из репозитория?
3.1. Удаление файла из индекса
Представим, что вы забыли занести в .gitignore правило, которое позволяло бы игнорировать class-файлы. В итоге применив команду git add, добавили их случайно в индекс.
Это очень частая ошибка у начинающих, которая влечет за собой попадание мусорных файлов в УР.
Скомпилируем исходник, создав class-файл:
Внесем изменения в класс из предыдущих статей:
import java.util.Scanner;
public class MyFirstApp {
public static void main(String[] args) {
System.out.println("У какого языка программирования следующий слоган:");
System.out.print(""Написано однажды, ");
System.out.println("работает везде!"");
String answer = new Scanner(System.in).next();
if (answer.equalsIgnoreCase("Java")) {
System.out.println("Вы угадали");
} else System.out.println("Увы, но - это Java");
}
}
Далее введем привычные команды:
> git add . && git status
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: MyFirstApp.class
modified: MyFirstApp.java
MyFirstApp.class в итоге попал в индекс Git. Необходимо его оттуда удалить, т. к. отслеживание изменений у данного вида файлов не несет никакой практической пользы.
Воспользуемся командой, подсказанной Git:
> git restore --staged MyFirstApp.class && git status
Changes to be committed:
modified: MyFirstApp.java
Untracked files:
MyFirstApp.class
MyFirstApp.class снова стал неотслеживаемым, а измененный класс остался в индексе не тронутым.
Чтобы обезопасить себя, перед использованием команды git add, всегда нужно просматривать список файлов (git status), которые вы планируете добавить в индекс. Также обязательно добавьте шаблон *.class в .gitignore, чтобы больше не спотыкаться о class-файлы.
3.2. Удаление файла из коммита
Пойдем дальше и научимся удалять MyFirstApp.class из коммита.
> git status
Changes to be committed:
new file: MyFirstApp.class
modified: MyFirstApp.java
Добавим все изменения в коммит:
> git commit -m "Добавил quiz по слогану Java"
Перед тем, как запушить коммит, программист решил посмотреть, какие файлы в него входят:
> git log -1 --name-only --oneline
ead5167 (HEAD -> master) Добавил quiz по слогану Java
src/MyFirstApp.class
src/MyFirstApp.java
С командной git log мы уже сталкивались в предыдущей статье. Из нового — аргумент —name-only, который позволяет вывести только имена измененных файлов, находящихся в коммите.
Использование log позволило заметить, что MyFirstApp.class оказался в коммите. Его нужно оттуда убрать.
> git reset --soft HEAD~1
Разберем эту команду по частям:
- reset — отменяет коммиты
- —soft — позволяет выполнить отмену коммита без потери изменений
- HEAD — указатель на локальную ветку в которой мы находимся. В нашем случае HEAD~1 указывает на первый коммит в дереве коммитов ветки master
Более подробно про команду reset (1, 2).
Тут следует сказать, что HEAD указывает на ветку, в которой вы находитесь в данный момент. Благодаря ему мы можем перемещаться по дереву коммитов и откатываться к любому из них.
Получается следующая картина: HEAD указывает на ветку master, а master является указателем на вершину в дереве коммитов.
Отобразим, куда указывает HEAD:
* обозначается текущая ветка.
Если команду ввести с параметром -v, то кроме названия ветки отобразится информация о коммите, на который указывает master:
> git branch -v
* master b59d871 Изменил вывод текста, отображаемого в консоль
После отмены коммита отобразим список оставшихся коммитов:
> git log --oneline
b59d871 (HEAD -> master, origin/master) Изменил вывод текста, отображаемого в консоль
39ba195 Переименовал about.txt в README.md и внес в него описание проекта
1e36e0f Инициализация проекта
Видим, что благодаря reset последний коммит из него был исключен.
При этом log отображает ту же самую информацию, о которой мы говорили выше: HEAD указывает на master, а он — на вершину дерева коммитов (коммит b59d871).
Стоит отметить, что команду reset необходимо использовать только для отмены коммитов, которые находятся исключительно на вашем компьютере и еще не попали на УР. Т. к. эта команда меняет историю коммитов, то это может принести множество проблем для других людей, которые совместно с вами работают в одном репозитории, если вы отмените с ее помощью коммит, а затем запушите изменения на УР.
Посмотрим, в каком состоянии теперь находится ЛР:
> git status
Changes to be committed:
new file: MyFirstApp.class
modified: MyFirstApp.java
Что делать дальше, вы уже знаете: нужно убрать из индекса class-файл, и закоммитить java-класс.
Исключаем MyFirstApp.class:
> git restore --staged MyFirstApp.class
> git status
Changes to be committed:
modified: MyFirstApp.java
Untracked files:
MyFirstApp.class
И тут вы понимаете, что забыли, как у вас назывался отмененный коммит: изменения остались все те же, значит, придумывать описание к коммиту нет смысла — нужно воспользоваться тем, которое было раньше.
Есть одна волшебная команда git reflog, которая отобразит все, что вы когда-либо сделали в своем репозитории с коммитами. Это своего рода лог всех ваших операций. Приведу его малую часть, которая нам необходима:
> git reflog
b59d871 (HEAD -> master, origin/master) HEAD@{0}: reset: moving to HEAD~1
ead5167 HEAD@{1}: commit: Добавил quiz по слогану Java
Из вывода видно описание отмененного коммита. Используем его для нового:
> git commit -m "Добавил quiz по слогану Java"
Больше подробностей о reflog по ссылке.
Не забудьте добавить *.class в.gitignore.
3.3. Удаление файла с GitHub
Самый неприятный случай — это когда мусорный файл все же пробрался на GitHub, т. е. был запушен:
В этом случае наставник вам может написать замечание: «на GitHub не должно быть файлов с расширением *.class, только *.java. Необходимо удалить из УР все class-файлы».
Самый простой выход из этой ситуации — это удалить в ЛР class-файлы, добавить в .gitignore маску *.class и сделать новый пуш. После этих действий на GitHub class-файл удалится. Он также автоматически удалится и у всех людей, которые работают с вами в одном репозитории. Например, когда наставник перед проверкой вашего ДЗ сделает git pull, то удаленные вами class-файлы, удалятся автоматически и у него.
Выглядеть это может примерно так:
D:JavaStartJava (master -> origin)
> git rm src*.class
rm 'src/MyFirstApp.class'
> git status
On branch master
Changes to be committed:
new file: .gitignore
deleted: src/MyFirstApp.class
> git commit -m "Добавил .gitignore с маской *.class"
[master 4bf0ddd] Добавил .gitignore с маской *.class
2 files changed, 1 insertion(+)
create mode 100644 .gitignore
delete mode 100644 src/MyFirstApp.class
> git push
4. Как изменить описание коммита?
4.1. Коммит не был запушен
Вы сделали коммит, но еще его не запушили. Выясняется, что описание к нему содержит опечатку или это сообщение нужно изменить. Разберем данную ситуацию.
Внесем ряд изменений в файл MyFirstApp.java, добавив в него код, запрашивающий у участника квиза его имя, которое будет выводиться, если он ответит правильно на вопрос:
import java.util.Scanner;
public class MyFirstApp {
public static void main(String[] args) {
Scanner console = new Scanner(System.in, "cp866");
System.out.print("Введите, пожалуйста, свое имя: ");
String name = console.next();
System.out.println("У какого языка программирования следующий слоган:");
System.out.print(""Написано однажды, ");
System.out.println("работает везде!"");
String answer = console.next();
if (answer.equalsIgnoreCase("Java")) {
System.out.println(name + ", вы угадали!");
} else System.out.println("Увы, но - это Java");
}
}
> git add MyFirstApp.java
> git commit -m "Добавил ввод имени учасника"
Выясняется, что описание содержит опечатку в слове «учасника».
Для исправления воспользуемся двумя вариантами команды commit:
- в первом случае при вводе git commit —amend, откроется редактор для изменения сообщения:
Такой способ подходит для исправления многострочных комментариев. Нам же больше подходит второй способ.
- во втором случае команда ниже позволит внести изменение прямо из консоли:
> git commit --amend -m "Добавил ввод имени участника"
[master 96e2847] Добавил ввод имени участника
Убедимся, что описание к коммиту изменилось, а прежнее — не сохранилось, отобразив сокращенную информацию по последнему коммиту:
> git log --oneline -1
96e2847 (HEAD -> master) Добавил ввод имени участника
Следует обратить внимание на то, что данные способы позволяют внести изменение в описание только последнего коммита.
4.2.1. Принудительная перезапись истории
Что описание к коммиту нужно изменить, вы вспомнили, когда он был уже отправлен на GitHub.
Чтобы решить эту задачу, необходимо к команде из предыдущего пункта добавить git push -f, которая принудительно перезапишет коммит с ошибочным описанием — исправленным:
> git commit --amend -m "Добавил ввод имени участника"
> git push -f
Среди прочего, в консоли отобразится примерно следующая строка:
+ 5aa3d6d...ce3cf6f master -> master (forced update).
Она сообщает, что было сделано принудительное обновление репозитория.
У ваших коллег (или наставника) после ввода git pull отобразятся строки, тоже сообщающие о принудительном изменении и последующем успешном слиянии (merge):
+ 5aa3d6d...ce3cf6f master -> origin/master (forced update)
Merge made by the 'ort' strategy.
5. Как выполнить пуш, если Git не дает это сделать?
Представим, что на первых порах вы еще не до конца освоили Git и какое-то время вносили изменения в файлы прямо на GitHub. Но рано или поздно поняли, что для своего профессионального роста все же нужно изучить базовые команды Git, и применять их в консоли.
После этого у себя на компьютере начали писать код очередного домашнего задания, а затем решили его запушить на GitHub для проверки наставником. Но сделать пуш у вас в итоге не получилось, а в консоли отобразилась ошибка:
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
Возможна и другая ситуация, когда вы пушите в один репозиторий на GitHub с разных компьютеров. Например, днем, в свободное от работы время, порешали домашку, а затем запушили ее на удаленный репозиторий. Вечером, придя домой, продолжили писать код для следующего ДЗ. А про код, запушенный на GitHub, либо забыли, либо подумали, что из-за него проблем не будет. Но в действительности оказалось все иначе.
Или на GitHub случайно попали class-файлы и вы без задней мысли пошли на сайт и удалили их.
Во всех этих ситуациях пуш приведет к одной и той же ошибке, связанной с тем, что истории изменений на локальном и удаленном репозитории пошли разными путями: на GitHub есть коммит, которого нет в ЛР. В дереве коммитов на ЛР на какое-то количество коммитов меньше, чем на УР.
Научимся решать эту проблему.
5.1. Подтягивание изменений с GitHub
Зайдя в свой репозиторий на GitHub, я внес в README.md следующие мелкие изменения:
- добавил картинку в виде шапки
- пункт «Командная строка» заменил на конкретное название используемой программы — cmder
- добавил иконки к каждому пункту списка
В качестве описания к коммиту указал следующий текст:
При этом README.md содержит следующий код:
# [StartJava](https://topjava.ru/startjava) -- курс на Java для начинающих

## Используемые на курсе инструменты и технологии
:coffee: Java
:octocat: Git/GitHub
:pager: cmder
:bookmark_tabs: Sublime Text
:fire: Intellij IDEA
:gem: SQL
:elephant: PostgreSQL
:newspaper: psql
Проделанные только что изменения я благополучно забыл подтянуть на свой компьютер с помощью git pull. И продолжил работать над классом MyFirstApp.java в ЛР, добавив в него еще один квиз и немного мелких правок.
В итоге класс (у меня на компьютере, не в GitHub) стал выглядеть так:
import java.util.Scanner;
public class MyFirstApp {
public static void main(String[] args) {
Scanner console = new Scanner(System.in, "cp866");
System.out.print("Введите, пожалуйста, свое имя: ");
String name = console.nextLine();
System.out.println("n1. У какого языка программирования следующий слоган:");
System.out.print(""Написано однажды, ");
System.out.println("работает везде!"");
String answer = console.nextLine();
if (answer.equalsIgnoreCase("Java")) {
System.out.println(name + ", вы угадали!");
} else System.out.println("Увы, но - это Java");
System.out.println("n2. Какая фамилия у автора языка Java?");
answer = console.nextLine();
if (answer.equals("Гослинг") || answer.equals("Gosling")) {
System.out.println(name + ", вы угадали!");
} else System.out.println("Увы, но - это Гослинг (Gosling)");
}
}
Добавил изменения в коммит:
> git add MyFirstApp.java
> git commit -m "Добавил quiz по автору Java"
Отобразим полученный результат в консоли:
> git log --oneline -1
7106587 (HEAD -> master) Добавил quiz по автору Java
А теперь самое интересное: попробуем сделать push:
> git push
To https://github.com/ichimax/startjava2.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://github.com/ichimax/startjava2.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Отобразилась ошибка, означающая, что в локальном и удаленном репозитории истории изменений пошли разными путями и не соответствуют друг другу.
Для решения этой проблемы Git предлагает выполнить команду pull, которая подтянет коммиты с УР, а затем объединит их с локальными, чтобы выровнять историю:
> git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 1.16 KiB | 62.00 KiB/s, done.
From https://github.com/ichimax/startjava2
ce3cf6f..2bdecf7 master -> origin/master
Merge made by the 'ort' strategy.
README.md | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
В этом сообщении стоить обратить внимание на строку Merge made by the ‘ort’ strategy. Из нее мы можем сделать вывод, что произошло слияние (merge).
Слияние — это объединение истории коммитов из разных веток в одну. У нас ветка хоть и одна (master), но история коммитов на GitHub и в ЛР стала с какого-то момента различаться. Из-за этого и не удавалось сделать push. Когда мы выполнили git pull, то Git автоматически объединил (что бывает не всегда) последний коммит из УР с последним коммитом из ЛР, создав новый.
Не всегда Git может выполнить слияние автоматически, что вызывает конфликт слияния. Такое бывает, когда в разных ветках был изменен один и тот же фрагмент кода. Из-за этого Git не сможет определить, какую версию использовать. Для решения проблемы потребуется вмешательство пользователя. Более подробно об этом можно узнать по ссылке.
Для того, чтобы минимизировать возникновение подобных ситуаций (конфликтов), рекомендуется каждый раз перед началом работы с проектом делать git pull, чтобы синхронизировать историю коммитов ЛР с историей УР.
Отобразим 4 последних коммита:
> git log --oneline -4
1b4a7b7 (HEAD -> master) Merge branch 'master' of https://github.com/ichimax/startjava2
7106587 Добавил quiz по автору Java
2bdecf7 (origin/master) Обновил README.md
ce3cf6f Добавил ввод имени участника
Из этого списка видно, что:
2bdecf7 — был сделан на GitHub
7106587 — был сделан в ЛР
1b4a7b7 — получился автоматически после слияния двух предыдущих коммитов
Обратите внимание, что у коммита, сделанного на GitHub, ветка называется не master, а origin/master. Разница в том, что master — это имя локальной ветки, а origin/master является удаленной веткой с именем master.
Отобразим ветки, связанные с нашим репозиторием:
> git branch -a
* master
remotes/origin/master
Ветка master является текущей (помечена *) веткой ЛР. remotes/origin/master — это ветвь с именем master и псевдонимом origin на УР.
То, что это — разные ветки, можно убедиться визуально, введя следующую команду:
D:JavaStartJavasrc (master -> origin)
> git log --pretty=format:"%h - %s" --graph
* 1b4a7b7 - Merge branch 'master' of https://github.com/ichimax/startjava2
|
| * 2bdecf7 - Обновил README.md
* | 7106587 - Добавил quiz по автору Java
|/
* ce3cf6f - Добавил ввод имени участника
* 4bf0ddd - Добавил .gitignore с маской *.class
* 90ca67c - Добавил quiz по слогану Java
* b59d871 - Изменил вывод текста, отображаемого в консоль
* 39ba195 - Переименовал about.txt в README.md и внес в него описание проекта
* 1e36e0f - Инициализация проекта
Опция —graph позволяет вывести граф в формате ASCII, который показывает текущую ветку и историю слияний. Более подробно с разными опциями команды log можно ознакомиться по ссылке.
Давайте взглянем на различия в последних коммитах в удаленной и локальной master-ветках:
D:JavaStartJavasrc (master -> origin)
> git diff origin/master..master
diff --git a/src/MyFirstApp.java b/src/MyFirstApp.java
index 8e25560..08099ad 100644
--- a/src/MyFirstApp.java
+++ b/src/MyFirstApp.java
@@ -4,15 +4,22 @@ public class MyFirstApp {
public static void main(String[] args) {
Scanner console = new Scanner(System.in, "cp866");
System.out.print("Введите, пожалуйста, свое имя: ");
- String name = console.next();
+ String name = console.nextLine();
- System.out.println("У какого языка программирования следующий слоган:");
+ System.out.println("n1. У какого языка программирования следующий слоган:");
System.out.print(""Написано однажды, ");
System.out.println("работает везде!"");
- String answer = console.next();
+ String answer = console.nextLine();
if (answer.equalsIgnoreCase("Java")) {
System.out.println(name + ", вы угадали!");
} else System.out.println("Увы, но - это Java");
+
+ System.out.println("n2. Какая фамилия у автора языка Java?");
+
+ answer = console.nextLine();
+ if (answer.equals("Гослинг") || answer.equals("Gosling")) {
+ System.out.println(name + ", вы угадали!");
+ } else System.out.println("Увы, но - это Гослинг (Gosling)");
}
}
После всех манипуляций отобразим состояние репозитория:
> git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
Посмотрим, какие два коммита мы должны запушить:
> git log --branches --not --remotes --oneline
1b4a7b7 (HEAD -> master) Merge branch 'master' of https://github.com/ichimax/startjava2
7106587 Добавил quiz по автору Java
Выполним push и снова введем команду, отображающую список из 4 коммитов:
> git push
> git log --oneline -4
1b4a7b7 (HEAD -> master, origin/master) Merge branch 'master' of https://github.com/ichimax/startjava2
7106587 Добавил quiz по автору Java
2bdecf7 Обновил README.md
ce3cf6f Добавил ввод имени участника
Видим, что история коммитов выровнялась: HEAD в ЛР и УР указывают на самый последний коммит 1b4a7b7.
Список решений тех или иных задач с помощью Git, разобранных в статье, с кратким описанием.
В статье мы рассмотрели самые простые, но часто возникающие проблемы, которые могут появиться при работе с Git и GitHub. Это базовый минимум, который поможет вам на первых порах не чувствовать себя растерянным, столкнувшись лицом к лицу с описанными сложностями.
Оцените статью, если она вам понравилась!
I apologize if this is a newbie question, but I’ve been search around and I’m dumbfounded as to why this is.
I have some files I’d like to add and commit.
I run:
git add .
I also tried git add -A
, git add -f -A
git commit -m 'message'
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
(to make sure my master branch is on the latest commit)
git push origin master
Yet there are no changes. The push was successful. But the files are not being added to my repository. What could be the reason?
EDIT:
I should mention that Git doesn’t seem to be detecting new files. When I specify the exact file to add, such as git add myapp/newFile.html
. I get an error message fatal: pathspec 'myapp/newFile.html' did not match any files.
The file is clearly in the folder.
EDIT 2:
I tried re-making my folder with rm -rf .git
and then re-doing all the steps. But when I do git add -A
again, the new files are still not being added! My folder feels like it’s cursed or something.
EDIT 3:
Results from ls -la
drwxr-xr-x 0 valachio valachio 512 Jan 11 20:35 .
drwxr-xr-x 0 valachio valachio 512 Jan 11 20:17 ..
drwxr-xr-x 0 valachio valachio 512 Jan 11 19:43 bungol
drwxrwxrwx 0 valachio valachio 512 Jan 11 19:43 config
drwxrwxrwx 0 valachio valachio 512 Jan 11 20:41 .git
-rwxrwxrwx 1 valachio valachio 804 Jan 11 19:43 manage.py
drwxrwxrwx 0 valachio valachio 512 Jan 11 19:43 misc (non-coding related stuff)
-rwxrwxrwx 1 valachio valachio 327 Jan 11 19:15 Pipfile
-rwxrwxrwx 1 valachio valachio 13798 Jan 11 19:43 Pipfile.lock
-rwxrwxrwx 1 valachio valachio 38 Jan 11 19:15 Procfile
-rwxrwxrwx 1 valachio valachio 115 Jan 11 20:08 README.md
-rwxrwxrwx 1 valachio valachio 368 Jan 11 19:43 requirements.txt
-rwxrwxrwx 1 valachio valachio 12 Jan 11 19:43 runtime.txt
drwxr-xr-x 0 valachio valachio 512 Jan 11 19:43 staticfiles
Results from git ls-tree HEAD
100755 blob a0994e0c2c674f7964b97e73bf8b639e0bd15fa3 Pipfile
100755 blob 79baf37feb267b9479d4b8979623e9164d8d17c3 Pipfile.lock
100755 blob 2a05d1701bb03f8e565ccb53b5048a2ecbb8ea81 Procfile
100755 blob 0fa4a27c2e5a6e03c3edf2eb096766c20c0e9206 README.md
040000 tree c1179776614cf441fd04a5241b91869e3b24a776 bungol
040000 tree 8f0028f91df90b5124315f5e1cdd776c55fe2300 config
100755 blob 68141ee9e00d47db18f3598190234e8f8818dd5d manage.py
040000 tree 4209dc1c056f595660ebf39ed57dc5bf72841597 misc (non-coding related stuff)
100755 blob d108cb2bdc916228474253e8c014dd1944df27f2 requirements.txt
100755 blob 5f61493782f81ae7c642d97051a8be79da5b7dba runtime.txt
040000 tree a044a50441ede0a7718934b096f3c11ef4e5c2ae staticfiles
EDIT 4:
I found the problem. I am using Ubuntu and the new files did not have access permissions. I had to give the current user access permissions to those new files with chmod 755
and after that it works.
Sorry I didn’t mention this in the original question. Thank you to everyone that provided answers.
I apologize if this is a newbie question, but I’ve been search around and I’m dumbfounded as to why this is.
I have some files I’d like to add and commit.
I run:
git add .
I also tried git add -A
, git add -f -A
git commit -m 'message'
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
(to make sure my master branch is on the latest commit)
git push origin master
Yet there are no changes. The push was successful. But the files are not being added to my repository. What could be the reason?
EDIT:
I should mention that Git doesn’t seem to be detecting new files. When I specify the exact file to add, such as git add myapp/newFile.html
. I get an error message fatal: pathspec 'myapp/newFile.html' did not match any files.
The file is clearly in the folder.
EDIT 2:
I tried re-making my folder with rm -rf .git
and then re-doing all the steps. But when I do git add -A
again, the new files are still not being added! My folder feels like it’s cursed or something.
EDIT 3:
Results from ls -la
drwxr-xr-x 0 valachio valachio 512 Jan 11 20:35 .
drwxr-xr-x 0 valachio valachio 512 Jan 11 20:17 ..
drwxr-xr-x 0 valachio valachio 512 Jan 11 19:43 bungol
drwxrwxrwx 0 valachio valachio 512 Jan 11 19:43 config
drwxrwxrwx 0 valachio valachio 512 Jan 11 20:41 .git
-rwxrwxrwx 1 valachio valachio 804 Jan 11 19:43 manage.py
drwxrwxrwx 0 valachio valachio 512 Jan 11 19:43 misc (non-coding related stuff)
-rwxrwxrwx 1 valachio valachio 327 Jan 11 19:15 Pipfile
-rwxrwxrwx 1 valachio valachio 13798 Jan 11 19:43 Pipfile.lock
-rwxrwxrwx 1 valachio valachio 38 Jan 11 19:15 Procfile
-rwxrwxrwx 1 valachio valachio 115 Jan 11 20:08 README.md
-rwxrwxrwx 1 valachio valachio 368 Jan 11 19:43 requirements.txt
-rwxrwxrwx 1 valachio valachio 12 Jan 11 19:43 runtime.txt
drwxr-xr-x 0 valachio valachio 512 Jan 11 19:43 staticfiles
Results from git ls-tree HEAD
100755 blob a0994e0c2c674f7964b97e73bf8b639e0bd15fa3 Pipfile
100755 blob 79baf37feb267b9479d4b8979623e9164d8d17c3 Pipfile.lock
100755 blob 2a05d1701bb03f8e565ccb53b5048a2ecbb8ea81 Procfile
100755 blob 0fa4a27c2e5a6e03c3edf2eb096766c20c0e9206 README.md
040000 tree c1179776614cf441fd04a5241b91869e3b24a776 bungol
040000 tree 8f0028f91df90b5124315f5e1cdd776c55fe2300 config
100755 blob 68141ee9e00d47db18f3598190234e8f8818dd5d manage.py
040000 tree 4209dc1c056f595660ebf39ed57dc5bf72841597 misc (non-coding related stuff)
100755 blob d108cb2bdc916228474253e8c014dd1944df27f2 requirements.txt
100755 blob 5f61493782f81ae7c642d97051a8be79da5b7dba runtime.txt
040000 tree a044a50441ede0a7718934b096f3c11ef4e5c2ae staticfiles
EDIT 4:
I found the problem. I am using Ubuntu and the new files did not have access permissions. I had to give the current user access permissions to those new files with chmod 755
and after that it works.
Sorry I didn’t mention this in the original question. Thank you to everyone that provided answers.
To expand on both the accepted answer from Mario Zigliotto and Albert’s answer, the reason this occurs is because of submodules. Here is a simple way to re-create the problem:
$ mkdir empty-submodule && cd empty-submodule
$ git init
Initialized empty Git repository in [path ending in empty-submodule/.git]
$ mkdir sub && (cd sub && git init)
Initialized empty Git repository in ... [path ending in empty-submodule/sub/.git]
$ ls
sub
$ ls -a sub
. .. .git
$ git add .
error: 'sub/' does not have a commit checked out
fatal: adding files failed
Note that the subdirectory sub
is itself a Git repository, but no commit is checked out in this subdirectory. This is a simple statement of fact, true in this case because I created sub
, went into it, and created a new, empty Git repository there. So that Git repository has no commits at all.
To the above fact, we add one more: No Git repository can hold another Git repository inside it. The reason for this has to do with security, but for our purpose here, the important side effect of this fact is that an attempt to add a sub-repository to a repository (like the superproject in empty-submodule
) does not add the repository itself. Instead, it adds a reference to a commit within the repository. This is how submodules are implemented.1 But to refer to some commit within the submodule, the submodule itself has to have some commit checked out.
The way to fix this really depends on the result you want. See the next section for more information about this.
1Technically, submodules are implemented with two parts:
- Each commit in the superproject (the «outer» repository) has a reference to a commit within the submodule.
- In order to be able to run
git clone
on the submodule, the outer repository should also contain a.gitmodules
file. This file will hold the instructions that tell the superproject Git how togit clone
the submodule. Once the submodule repository exists, the superproject Git never needs to rungit clone
on it again. So it’s possible to accidentally, or on purpose, omit the.gitmodules
file entirely.
Doing this produces a superproject that is difficult to use. I like to call this a half-assed submodule. If it were fully-assed, the superproject would be able to clone the submodule, but since the .gitmodules
file is missing, it can’t.
Fixing the problem
There are multiple ways to fix the problem. Before you pick one, you should know whether you want to have a submodule. There’s no one correct answer here, as the question of should I use a submodule is a bit like which flavor of ice cream should I pick: different people have different preferences.
If you don’t want a submodule at all you will need to move or remove the .git
subdirectory within the subdirectory in question, e.g.:
rm -rf sub/.git
(see also Nissan’s answer if using PowerShell on Windows).
Before you do that, you should:
-
Determine whether you want to keep the other repository. If so, do not remove it! Just move it somewhere else, e.g.,
mkdir ../keep && mv sub/.git ../keep
. -
Determine whether you need to
git checkout
some commit or branch before moving or removing the repository (the.git
directory). If so, enter the submodule and check out the desired commit.
If you do want a submodule, you may need to make some commit(s) within the submodule, or check out some existing commit, just as in step 2 above. Once the submodule repository is on the correct commit, you can git add
it.
Here is an example of creating a commit in my submodule named sub
:
$ cd sub
$ echo this is the submodule > README.md
$ git add .
$ git commit -m initial
[master (root-commit) c834131] initial
1 file changed, 1 insertion(+)
create mode 100644 README.md
$ cd ..
Now that the submodule has a commit, I can add it to the superproject. There’s a bit of a hitch here though, as I should also create the .gitmodule
file mentioned in footnote 1 above. The git submodule add
command does everything for you, but you need to know where you’ll git push
this submodule repository. For instance:
$ git submodule add ssh://[email protected]/place/where/submodule/lives.git sub
Adding existing repo at 'sub' to the index
Everything is now ready to commit in the superproject:
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitmodules
new file: sub
$ cat .gitmodules
[submodule "sub"]
path = sub
url = ssh://[email protected]/place/where/submodule/lives.git
The submodule has not actually been sent to GitHub yet. Before anyone else will be able to use the superproject, I’d have to create this GitHub repository, giving it sufficient (e.g., public) access, and git push
the submodule commit to that GitHub repository. Then I can git push
my commit in my superproject to whatever location that repository should live at. Then you—the generic «you»—can git clone
the superproject, which now has a .gitmodules
file with instructions by which your Git will be able to run git clone ssh://[email protected]/place/where/submodule/lives.git sub
.
Submodules have a bunch of usability issues, with all of the above complications being one of them. Be sure you know what you’re getting into.
Операции отмены
В любой момент вам может потребоваться что-либо отменить.
Здесь мы рассмотрим несколько основных способов отмены сделанных изменений.
Будьте осторожны, не все операции отмены в свою очередь можно отменить!
Это одна из редких областей Git, где неверными действиями можно необратимо удалить результаты своей работы.
Отмена может потребоваться, если вы сделали коммит слишком рано, например, забыв добавить какие-то файлы или комментарий к коммиту.
Если вы хотите переделать коммит — внесите необходимые изменения, добавьте их в индекс и сделайте коммит ещё раз, указав параметр --amend
:
Эта команда использует область подготовки (индекс) для внесения правок в коммит.
Если вы ничего не меняли с момента последнего коммита (например, команда запущена сразу после предыдущего коммита), то снимок состояния останется в точности таким же, а всё что вы сможете изменить — это ваше сообщение к коммиту.
Запустится тот же редактор, только он уже будет содержать сообщение предыдущего коммита.
Вы можете редактировать сообщение как обычно, однако, оно заменит сообщение предыдущего коммита.
Например, если вы сделали коммит и поняли, что забыли проиндексировать изменения в файле, который хотели добавить в коммит, то можно сделать следующее:
$ git commit -m 'Initial commit'
$ git add forgotten_file
$ git commit --amend
В итоге получится единый коммит — второй коммит заменит результаты первого.
Примечание |
Очень важно понимать, что когда вы вносите правки в последний коммит, вы не столько исправляете его, сколько заменяете новым, который полностью его перезаписывает. Очевидно, смысл изменения коммитов в добавлении незначительных правок в последние коммиты и, при этом, в избежании засорения истории сообщениями вида «Ой, забыл добавить файл» или «Исправление грамматической ошибки». |
Отмена индексации файла
Следующие два раздела демонстрируют как работать с индексом и изменениями в рабочем каталоге.
Радует, что команда, которой вы определяете состояние этих областей, также подсказывает вам как отменять изменения в них.
Например, вы изменили два файла и хотите добавить их в разные коммиты, но случайно выполнили команду git add *
и добавили в индекс оба.
Как исключить из индекса один из них?
Команда git status
напомнит вам:
$ git add *
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
modified: CONTRIBUTING.md
Прямо под текстом «Changes to be committed» говорится: используйте git reset HEAD <file>…
для исключения из индекса.
Давайте последуем этому совету и отменим индексирование файла CONTRIBUTING.md
:
$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
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: CONTRIBUTING.md
Команда выглядит несколько странно, но — работает!
Файл CONTRIBUTING.md
изменен, но больше не добавлен в индекс.
Примечание |
Команда |
На текущий момент этот магический вызов — всё, что вам нужно знать о команде git reset
.
Мы рассмотрим в деталях что именно делает reset
и как с её помощью делать действительно интересные вещи в разделе Раскрытие тайн reset главы 7.
Отмена изменений в файле
Что делать, если вы поняли, что не хотите сохранять свои изменения файла CONTRIBUTING.md
?
Как можно просто отменить изменения в нём — вернуть к тому состоянию, которое было в последнем коммите (или к начальному после клонирования, или еще как-то полученному)?
Нам повезло, что git status
подсказывает и это тоже.
В выводе команды из последнего примера список изменений выглядит примерно так:
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: CONTRIBUTING.md
Здесь явно сказано как отменить существующие изменения.
Давайте так и сделаем:
$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
Как видите, откат изменений выполнен.
Важно |
Важно понимать, что |
Если вы хотите сохранить изменения в файле, но прямо сейчас их нужно отменить, то есть способы получше, такие как ветвление и припрятывание — мы рассмотрим их в главе Ветвление в Git.
Помните, все что попало в коммит почти всегда Git может восстановить.
Можно восстановить даже коммиты из веток, которые были удалены, или коммиты, перезаписанные параметром --amend
(см. Восстановление данных).
Но всё, что не было включено в коммит и потеряно — скорее всего, потеряно навсегда.
Отмена действий с помощью git restore
Git версии 2.23.0 представил новую команду: git restore
.
По сути, это альтернатива git reset, которую мы только что рассмотрели.
Начиная с версии 2.23.0, Git будет использовать git restore
вместо git reset
для многих операций отмены.
Давайте проследим наши шаги и отменим действия с помощью git restore
вместо git reset
.
Отмена индексации файла с помощью git restore
В следующих двух разделах показано, как работать с индексом и изменениями рабочей копии с помощью git restore
.
Приятно то, что команда, которую вы используете для определения состояния этих двух областей, также напоминает вам, как отменить изменения в них.
Например, предположим, что вы изменили два файла и хотите зафиксировать их как два отдельных изменения, но случайно набираете git add *
и индексируете их оба.
Как вы можете убрать из индекса один из двух?
Команда git status
напоминает вам:
$ git add *
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: CONTRIBUTING.md
renamed: README.md -> README
Прямо под текстом «Changes to be committed», написано использовать git restore --staged <file> …
для отмены индексации файла.
Итак, давайте воспользуемся этим советом, чтобы убрать из индекса файл CONTRIBUTING.md
:
$ git restore --staged CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: README.md -> README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
Файл CONTRIBUTING.md
изменен, но снова не индексирован.
Откат измененного файла с помощью git restore
Что, если вы поймете, что не хотите сохранять изменения в файле CONTRIBUTING.md
?
Как легко его откатить — вернуть обратно к тому, как он выглядел при последнем коммите (или изначально клонирован, или каким-либо образом помещён в рабочий каталог)?
К счастью, git status
тоже говорит, как это сделать.
В выводе последнего примера, неиндексированная область выглядит следующим образом:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
Он довольно недвусмысленно говорит, как отменить сделанные вами изменения.
Давайте сделаем то, что написано:
$ git restore CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: README.md -> README
Важно |
Важно понимать, что |