Сделать текущий коммит единственным (начальным) коммитом в Git-репозитории?

В настоящее время у меня есть локальный репозиторий Git, который я отправляю в репозиторий Github.

Локальный репозиторий имеет ~10 коммитов, а репозиторий Github является синхронизированным дубликатом этого.

Я хотел бы удалить ВСЕ историю версий из локального репозитория Git, чтобы текущее содержимое репозитория отображалось как единственная фиксация (и, следовательно, более старые версии файлов в репозитории не сохраняются).

Затем я хотел бы перенести эти изменения в Github.

Я исследовал Git ReBase, но это больше подходит для удаления определенных версий. Другим потенциальным решением является удаление локального репо и создание нового - хотя это, вероятно, создаст много работы!

ETA: Существуют определенные каталоги / файлы, которые не отслеживаются, - если возможно, я хотел бы сохранить отслеживание этих файлов.

20 ответов

Решение

Вот подход грубой силы. Также удаляет конфигурацию хранилища.

Примечание: это НЕ работает, если в хранилище есть субмодули! Если вы используете субмодули, вы должны использовать, например, интерактивный ребаз

Шаг 1: удалить всю историю (убедитесь, что у вас есть резервная копия, это не может быть восстановлено)

rm -rf .git

Шаг 2: реконструируйте репозиторий Git только с текущим контентом

git init
git add .
git commit -m "Initial commit"

Шаг 3: нажмите на GitHub.

git remote add origin <github-uri>
git push -u --force origin master

Единственное решение, которое работает для меня (и поддерживает работу подмодулей)

git checkout --orphan newBranch
git add -A  # Add all files and commit them
git commit
git branch -D master  # Deletes the master branch
git branch -m master  # Rename the current branch to master
git push -f origin master  # Force push master branch to github
git gc --aggressive --prune=all     # remove the old files

Удаление .git/ всегда вызывает огромные проблемы, когда у меня есть подмодули. С помощью git rebase --root как-то может вызвать конфликты для меня (и займет много времени, так как у меня было много истории).

Это мой любимый подход:

git branch new_branch_name $(echo "commit message" | git commit-tree HEAD^{tree})

Это создаст новую ветку с одним коммитом, который добавляет все в HEAD. Это ничего не меняет, так что это абсолютно безопасно.

Другой вариант, который может оказаться трудоемким, если у вас много коммитов, - это интерактивная перебазировка (при условии, что ваша версия git>=1.7.12):git rebase --root -i

Когда в вашем редакторе представлен список коммитов:

  • Измените "pick" на "reword" для первого коммита
  • Измените "pick" на "fixup" при каждом другом коммите

Сохрани и закрой. Git начнет перебазировать.

В конце у вас будет новый корневой коммит, представляющий собой комбинацию всех тех, что пришли после него.

Преимущество состоит в том, что вам не нужно удалять свой репозиторий, и если у вас есть мысли, у вас всегда есть запасной вариант.

Если вы действительно хотите уничтожить историю, сбросьте мастер до этого коммита и удалите все остальные ветви.

Вариант предложенного метода Ларсмана:

Сохраните свой список неотслеживаемых файлов:

git ls-files --others --exclude-standard > /tmp/my_untracked_files

Сохраните вашу конфигурацию git:

mv .git/config /tmp/

Затем выполните первые шаги Ларсмана:

rm -rf .git
git init
git add .

Восстановите ваш конфиг:

mv /tmp/config .git/

Удалите ваши неотслеженные файлы:

cat /tmp/my_untracked_files | xargs -0 git rm --cached

Затем совершите:

git commit -m "Initial commit"

И, наконец, нажмите на ваш репозиторий:

git push -u --force origin master

Удаление .gitпапка может вызвать проблемы в вашем репозитории git. Если вы хотите удалить всю историю коммитов, но сохранить код в его текущем состоянии, это очень безопасно сделать, как показано ниже:

  1. Проверить

    git checkout --orphan latest_branch

  2. Добавьте все файлы

    git add -A

  3. Зафиксируйте изменения

    git commit -am "commit message"

  4. Удалить ветку

    git branch -D master

  5. Переименовать текущую ветку в master

    git branch -m master

  6. Наконец, принудительно обновите свой репозиторий

    git push -f origin master

PS: это не сохранит вашу старую историю коммитов

Ниже приведен скрипт, адаптированный из ответа @Zeelot. Следует удалить историю из всех веток, а не только из основной ветки:

for BR in $(git branch); do   
  git checkout $BR
  git checkout --orphan ${BR}_temp
  git commit -m "Initial commit"
  git branch -D $BR
  git branch -m $BR
done;
git gc --aggressive --prune=all

Это сработало для моих целей (я не использую подмодули).

Создайте ветку, скопируйте в нее все содержимое, зафиксируйте ее и затем удалите основную ветку:

git checkout --orphan newBranch; git add -A ;git commit -am 'first commit' ;git branch -D master;git branch -m master; git push -f origin master; git gc --aggressive --prune=all

Это удаляет историю на master ветка (вы можете сделать резервную копию перед запуском команд):

git branch tmp_branch $(echo "commit message" | git commit-tree HEAD^{tree})
git checkout tmp_branch
git branch -D master
git branch -m master
git push -f --set-upstream origin master

Это основано на ответе @dan_waterworth.

Вы можете использовать мелкие клоны (git > 1.9):

git clone --depth depth remote-url

Дополнительное чтение: http://blogs.atlassian.com/2014/05/handle-big-repositories-git/

Просто удалите репозиторий Github и создайте новый. Безусловно, самый быстрый, самый простой и безопасный подход. В конце концов, что вы должны получить, выполняя все эти команды в принятом решении, когда все, что вам нужно, - это основная ветка с одним коммитом?

Я хотел бы удалить ВСЕ историю версий из локального репозитория Git, чтобы текущее содержимое репозитория отображалось как единственная фиксация (и, следовательно, более старые версии файлов в репозитории не сохраняются).

Более концептуальный ответ:

git автоматически собирает старые коммиты, если на них нет тегов / веток / ссылок. Таким образом, вам просто нужно удалить все теги / ветви и создать новый бесхозный коммит, связанный с любой веткой - по соглашению вы разрешите ветку master указать на этот коммит.

Тогда старые, недоступные коммиты больше никогда не будут видны никому, если они не будут копаться с низкоуровневыми командами git. Если вам этого достаточно, я бы просто остановился на этом и позволил автоматическому GC выполнить свою работу, когда захочет. Если вы хотите избавиться от них сразу, вы можете использовать git gc (возможно с --aggressive --prune=all). Для удаленного репозитория git вы не можете заставить это сделать, если только у вас нет доступа оболочки к их файловой системе.

Все ответы потрясающие, но я хотел бы предложить другой подход с простыми командами.

      git clone --depth 1 <remote-url> .
git commit --amend -m <commit message you want>
git push --force
git for-each-ref --format='git update-ref -d %(refname)' \
        refs/{heads,tags} | sh -x
current=$(git commit-tree -m 'Initial commit' `git write-tree`)
git update-ref -m 'Initial commit' `git symbolic-ref HEAD` $current

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

Вот шаги, чтобы очистить историю репозитория Github

Сначала удалите историю из .git

      rm -rf .git

Теперь воссоздайте репозитории git только из текущего содержимого.

      git init
git add .
git commit -m "Initial commit"

Отправьте в удаленные репозитории Github, гарантируя перезапись истории

      
git remote add origin git@github.com:<YOUR ACCOUNT>/<YOUR REPOS>.git
git push -u --force origin master

Ну вот:

#!/bin/bash
#
# By Zibri (2019)
#
# Usage: gitclean username password giturl
#
gitclean () 
{ 
    odir=$PWD;
    if [ "$#" -ne 3 ]; then
        echo "Usage: gitclean username password giturl";
        return 1;
    fi;
    temp=$(mktemp -d 2>/dev/null /dev/shm/git.XXX || mktemp -d 2>/dev/null /tmp/git.XXX);
    cd "$temp";
    url=$(echo "$3" |sed -e "s/[^/]*\/\/\([^@]*@\)\?\.*/\1/");
    git clone "https://$1:$2@$url" && { 
        cd *;
        for BR in "$(git branch|tr " " "\n"|grep -v '*')";
        do
            echo working on branch $BR;
            git checkout $BR;
            git checkout --orphan $(basename "$temp"|tr -d .);
            git add -A;
            git commit -m "Initial Commit" && { 
                git branch -D $BR;
                git branch -m $BR;
                git push -f origin $BR;
                git gc --aggressive --prune=all
            };
        done
    };
    cd $odir;
    rm -rf "$temp"
}

Также размещено здесь: https://gist.github.com/Zibri/76614988478a076bbe105545a16ee743

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

git log -n1 --format=%H >.git/info/grafts
git filter-branch -f
rm .git/info/grafts

Если вы хотите очистить его, попробуйте этот скрипт:

http://sam.nipl.net/b/git-gc-all-ferocious

Я написал скрипт, который "убивает историю" для каждой ветви в хранилище:

http://sam.nipl.net/b/git-kill-history

см. также: http://sam.nipl.net/b/confirm

Чтобы удалить последний коммит из git, вы можете просто запустить

git reset --hard HEAD^ 

Если вы удаляете несколько коммитов сверху, вы можете запустить

git reset --hard HEAD~2 

удалить последние два коммита. Вы можете увеличить количество, чтобы удалить еще больше коммитов.

Больше информации здесь.

Git tutoturial предоставляет помощь по очистке репозитория:

Вы хотите удалить файл из истории и добавить его в.gitignore, чтобы он не был случайно повторно зафиксирован. Для наших примеров мы собираемся удалить Rakefile из репозитория GitHub.

git clone https://github.com/defunkt/github-gem.git

cd github-gem

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch Rakefile' \
  --prune-empty --tag-name-filter cat -- --all

Теперь, когда мы удалили файл из истории, давайте позаботимся о том, чтобы мы случайно не зафиксировали его снова.

echo "Rakefile" >> .gitignore

git add .gitignore

git commit -m "Add Rakefile to .gitignore"

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

git push origin master --force

Я решил похожую проблему, просто удалив .git папку из моего проекта и реинтеграции с контролем версий через IntelliJ. Обратите внимание .git папка скрыта Вы можете просмотреть его в терминале с ls -a, а затем удалите его, используя rm -rf .git,

Для этого используйте команду Shallow Clone git clone --depth 1 URL - она ​​будет клонировать только текущий заголовок хранилища.

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