Чи можна перенести git скриньку у віддалений сховище?


205

Чи можна створити скриньку в git, перенести копію у віддалене сховище, отримати сховище на іншому комп’ютері та застосувати сховище?

Або мої варіанти:

  • Створіть патч та скопіюйте патч на інший комп'ютер, або
  • Створити другорядну філію і доручити їй незавершену роботу?

Відповіді:


68

Неможливо отримати це за допомогою витягування чи так, дзеркальний перегляд є fetch = +refs/*:refs/*, і навіть при тому, що приховування refs/stashйого не надсилається. Явний refs/stash:refs/stashтакож не має ефекту!

Це було б лише заплутано в будь-якому випадку, оскільки це не призвело б до всіх схованок, лише останніх; список сташів - це рефлектор посилання refs/stashes.


4
Ви можете отримати останню скриньку з віддаленого файлу git, але не в свою скриньку, лише в інший номер. Щось подібне git fetch some-remote +refs/stash:refs/remotes/some-remote/stashдо git stash apply some-remote/stash. Але ви не можете отримати старі скрині, тому що вони зберігаються в рефлогу, який неможливо придбати. Див stackoverflow.com/questions/2248680 / ...
sj26

75

Примітка. Я щойно переписав цю відповідь ще на 24 години більше гіт-фу під поясом :) У моїй історії оболонок весь шебанг зараз три одноразові. Однак я скасував їх для вашої зручності.

Таким чином, я сподіваюся, ви зможете побачити, як я робив речі, а не просто сліпо копіювати / вставляти речі.


Ось крок за кроком.

Припустимо, джерело в ~ / OLDREPO, що містить схованки. Створіть клон TEST, що не містить схованок:

cd ~/OLDREPO
git clone . /tmp/TEST

Просуньте всі скриньки як тимчасові гілки:

git send-pack /tmp/TEST $(for sha in $(git rev-list -g stash); \
    do echo $sha:refs/heads/stash_$sha; done)

Петля на приймальному кінці, щоб перетворитись назад у сховища:

cd /tmp/TEST/
for a in $(git rev-list --no-walk --glob='refs/heads/stash_*'); 
do 
    git checkout $a && 
    git reset HEAD^ && 
    git stash save "$(git log --format='%s' -1 HEAD@{1})"
done

Почистіть тимчасові гілки, якщо хочете

git branch -D $(git branch|cut -c3-|grep ^stash_)

Складіть список сховищ git, і вам сподобається щось подібне:

stash@{0}: On (no branch): On testing: openmp import
stash@{1}: On (no branch): On testing: zfsrc
stash@{2}: On (no branch): WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue
stash@{3}: On (no branch): WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{4}: On (no branch): WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{5}: On (no branch): WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{6}: On (no branch): WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{7}: On (no branch): WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{8}: On (no branch): WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{9}: On (no branch): WIP on emmanuel: bee6660 avoid unrelated changes

На оригінальному сховищі виглядало те саме

stash@{0}: WIP on emmanuel: bee6660 avoid unrelated changes
stash@{1}: WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{2}: WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{3}: WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{4}: WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{5}: WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{6}: WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{7}: WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue #57)
stash@{8}: On testing: zfsrc
stash@{9}: On testing: openmp import

1
Я багато навчаюсь за невеликий час, і я вважаю, що, мабуть, мені просто слід використовувати багато командних звичок у своєму попередньому підході, що я спробую зробити пізніше.
1111

9
Це добре працювало для мене, за винятком того, що мені потрібен був крок git add .перед git stash save ...кроком, оскільки git stashвідмовляється зберігати нові файли, якщо вони не ставились. Крім того , обжигающе результат git rev-list ...через tacЗмінює порядок в тайниках , щоб вони вийшли в тому ж порядку.
Алан Крюгер

1
@sehe Відмінний сценарій !! Дві пропозиції: 1) - повернути підсумковий перелік списків таким чином, щоб таємниці були в тому ж порядку в цільовому репо, як у оригіналі. 2) Закінчіть остаточний forцикл git branch -D stash_$a(очистіть, коли створюються скрипки), щоб, якщо щось пішло не так, і ми повторимо спробу, ми не повторно обробляємо, що вже успішно приховано.
Кіт Робертсон

1
Дуже дякую, що знайшли час, щоб пояснити, що ви зробили, а не "просто розміщувати рішення".
Мар'ян Венема

1
Рішення може бути поліпшена додатково: Якщо замінити git stash save "$(git log --format='%s' -1 HEAD@{1})"з git update-ref --create-reflog -m "$(git show -s --format=%B $rev)" refs/stash $revвами отримати оригінальне збирати повідомлення ( update-refце те , що git stash saveза кадром).
Себастьян Шрадер

31

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

Я працюю над функцією у власній галузі. Гілка не об'єднується в головну і не підштовхується до її закінчення, або якщо я не поклав на себе зобов’язання, які мені комфортно показувати публіці. Отже, що я роблю, коли хочу перенести нестадійні зміни на інший комп'ютер:

  • Візьміть на себе зобов’язання, надіславши повідомлення на зразок " [non-commit] FOR TRANSFER ONLY" із вмістом, який ви хочете передати.
  • Увійдіть на інший комп'ютер.
  • Потім зробіть:

    git pull ssh+git://<username>@<domain>/path/to/project/ rb:lb

    URL-адреса може відрізнятися для вас, якщо ви отримуєте доступ до свого сховища іншим чином. Це дозволить перетягнути зміни з цієї URL-адреси з віддаленої гілки "rb" в локальну гілку "lb". Зауважте, що у мене на власному комп’ютері працює ssh-сервер, і я маю змогу отримати доступ до сховища таким чином.

  • git reset HEAD^(мається на увазі --mixed)

    Це скидає HEAD, щоб вказати на стан перед "[не зобов'язанням]".

З git-reset (1): " --mixed: Скидає індекс, але не робоче дерево (тобто змінені файли зберігаються, але не позначаються для фіксації) [...]"

Таким чином, у вас з’являться зміни у файлах, врешті-решт, але жодних комісій не робиться для освоєння та не потрібно зберігати.

Однак це зажадає від вас git reset --hard HEAD^у сховищі, в якому ви зробили "[не зобов’язати]", оскільки ця фіксація є сміттям.


Це набагато брудніше, а потім просто створити нову гілку функції, а потім видалити її згодом ....
Taegost

@Taegost, можливо, залежить від вашого оточення. Це можуть бути деякі матеріали CI / CD, що запобігають простому поштовху гілки вгору за течією Але так, залежно від того, що ви віддаєте перевагу, ви можете просто створити гілку, щоб виконати те саме.
Віктор Заманян

22

Трохи пізно, але ця відповідь комусь може допомогти. Я хотів це знати, тому що я хотів мати можливість натиснути функцію / помилку / що завгодно та працювати з тієї ж точки на іншому комп'ютері.

Що для мене працює - це ввести свій незавершений код (у галузі, над якою я працюю один). Коли я дістаюсь до свого іншого комп’ютера, виконайте потяг, а потім скасуйте комісію за допомогою:

git reset --soft HEAD^

Продовжуйте роботу, як ви були, з усіма вашими незмінними змінами там, не видаленими та без змін.

Сподіваюся, це допомагає.


Коли я намагаюся це зробити, "Походження" все ще підтримує "Коміт", що не було передано. Близько, але сигари для мене немає.
rezwits

@rezwits Так, пульт зберігає його, але досить просто видалити тимчасову гілку з походження.
Сер Роберт

власне, саме цим я і займався!
rezwits

19

Здається, є дуже акуратний трюк для вирішення цього питання. ви можете використовувати git diff > file.diff(і ввести файл), а потім відновити зміни, використовуючи git apply file.diff(з будь-якого місця), щоб досягти однакового результату.

Це було пояснено і тут .


5
якщо у вас немає файлів, що відслідковуються: 1. git add. 2. git diff HEAD> file.diff
trickpatty

Повідомлення різниці для себе дозволяє взагалі не робити жодних зобов'язань / слідів! (наприклад: Примітка для самостійного використання через настільний додаток Signal) або електронною поштою.
Джон Мей

9

Я б пішов з другим підходом, хоча не маю ідеї, чому ви не можете скористатись ним майстерною / представленою галуззю. Можна також зайняти вишню.


27
Немає жодних технічних причин не брати на себе зобов’язання освоювати / показувати, просто я хочу сказати: "Це не справжнє зобов'язання, це просто збереження моєї роботи, щоб я міг її отримати на іншій машині".
Ендрю Грімм

4

AFAIK вся ідея приховування полягає в тому, щоб сховати щось не дуже важливе під місцевим килимом. Ніхто не повинен знати про ваше улюблене лайно ;-) Єдине "але" таке: але якщо я розвинусь на декількох робочих станціях? Тоді scpце краще.


9
Щось таке смішне повинно бути коментарем. ;-)
Ендрю Грімм

2
Тут всього git-ssh-newbie, але чи можете ви тоді використовувати scp з github?
Коен

Ні, gitub's git-ssh frontend запрограмований, щоб у вас ніколи не було оболонки / консолі ssh. Він може запускати лише процес git на стороні сервера.
argent_smith

1
Тож scp насправді не є варіантом для цього сценарію, якщо ваша головна гілка знаходиться на github? Будь-які інші пропозиції перенести скриньку в такому випадку?
Коен

1
Я намагався підкреслити, що передача приховування взагалі неможлива, AFAIK.
argent_smith

2

На даний момент прийнята відповідь технічно правильно, ви не можете безпосередньо сказати Git , щоб підштовхнути всі ваші кубла на пульті дистанційного керування, а потім тягнути все в ваших місцевих схованках на іншому комп'ютері.

І хоча відповідь, що наразі отримує все необхідне, має працювати, мені не сподобалось, що вона створює купу тимчасових гілок, і що для цього потрібно вручну перевірити скрийнш-скрипт і зберегти його як приховування, що може призвести до таких проблем, як цей коментар згаданий і веде до дубліката On (no branch): On testing:. Звичайно, має бути кращий шлях!

Тому, поки ви не можете безпосередньо натиснути скриньки, сховище - це лише зобов’язання (фактично два коміти), і на сторінці git pushman ви можете надсилати коміти:

<src>Часто назва галузі ви хотіли б, щоб штовхати, але він може бути будь-яким довільним «SHA-1 вираз» ...

Я вирішив підштовхнути скриньки, щоб refs/stashes/*я не захаращував свій пульт додатковими гілками. Тож я можу це зробити за допомогою:

git push origin stash@{0}:refs/stashes/$(git rev-parse --short stash@{0})

( rev-parseКоманда отримує короткий хеш скрипту, який буде унікальним для репо.)

Далі мені потрібно забрати сховище з іншого комп'ютера. Git отримує лише гілки за замовчуванням, тому мені потрібно отримати конкретні дані:

git fetch origin refs/stashes/*:refs/stashes/*

Тепер конвертувати приховану скриньку назад у фактичну сховку. Як уже згадувалося, хоча я можу просто перевірити приховану фіксацію, скидання та сховище як завжди, мені не подобається, що для цього потрібні додаткові кроки або що він може не підтримувати стан індексу для сховища. Я шукав в Інтернеті спосіб зробити це автоматично, але мій пошук-фу зірвав мене. Нарешті я переглянув сторінку чоловіка для git stash, де я знайшов це:

створити
Створити приховану скриньку (яка є звичайним об'єктом фіксації) і повернути її ім'я об'єкта, не зберігаючи його ніде в просторі імен ref. Це покликане бути корисним для сценаріїв. Це, мабуть, не команда, яку ви хочете використовувати; див. "Зберегти" вище.

store
Зберігати заданий скринь, створений за допомогою git stash create (який є звисаючим злиттям комісії) у скриньці ref, оновивши рефлектор скриньки. Це покликане бути корисним для сценаріїв. Це, мабуть, не команда, яку ви хочете використовувати; див. "Зберегти" вище.

Оскільки я вже маю на себе зобов’язання, це storeзвучить як те, що я хочу. Тож я можу зробити:

git stash store --message "$(git show --no-patch --format=format:%s <SHA>)" <SHA>

Заміна <SHA>щойно зібраного сховища.

( git showКоманда отримує повідомлення про фіксацію з комісії прихованої скриньки для використання в якості повідомлення для журналу зберігання.)

Сховище тепер відображається як нормальне в моїй місцевій репо:

$ git stash list
stash@{0}: On master: temp
...

Щоб очистити пульт, сховища можна видалити з пульта так:

git push origin :refs/stashes/<SHA>

Цей метод також має перевагу бути ідентичним: якщо ви pushзнову запустите команду, він звітує Everything up-to-date. fetchКоманда також може бути безпечно запустити повторно. Незважаючи на те, що stash storeзаповіт пропустить, зберігаючи сховище, якщо він такий самий, як останній, він не перешкоджає дублікатам старих даних. Це можна вирішити, хоча, як це я роблю в своєму git-rstashсценарії, див. Нижче.


Для завершення ви також можете легко натиснути всі скриньки (з ):

for i in $(seq 0 $(expr $(git rev-list --walk-reflogs --count stash) - 1))
do
  git push origin stash@{$i}:refs/stashes/$(git rev-parse --short stash@{$i})
done

або імпортувати всі отримані сховища:

for stash in $(ls .git/refs/stashes)
do
  git stash store --message "$(git show --no-patch --format=format:%s $stash)" $stash
done

Я створив скрипт, який можна назвати підкомандою (наприклад git rstash push 0), тому мені не потрібно пам’ятати все це. git-rstashможна знайти тут.


1

Далі не працює зі сховищем, а з несвідомими змінами робочого режиму. Він створює гілку, автоматично передає всі поточні зміни та натискає на пульт:

commit_and_push_ ( ) {
    # This will:
    #  1. checkout a new branch stash-XXX
    #  2. commit the current changes in that branch
    #  3. push the branch to the remote
    local locbr=${1:-autostash-XXX}
    git checkout -b $locbr
    git add .
    git commit -a -m "Automatically created commit"
    git push origin $locbr
    echo "Autocommitted changes in branch $locbr ..."
}

Використовуйте як:

commit_and_push_ my-temp-branch
commit_and_push_

0

Я просто створив би нову скриньку і видалити, коли ця гілка не потрібна.

git add . // Add work-in-progress job
git checkout -b stash-branch // Create and checkout to stash-branch
git commit -m 'WIP: job description' // Commit message
git push origin stash-branch // Push to remote
git pull origin stash-branch // Pull the stash-branch
git checkout master // Checkout to working branch
git rebase stash-branch // Rebase the stash-branch
git reset --soft // Equivalent to stash!!
git branch -d stash-branch // Delete when not needed from local
git push -d origin stash-branch // Delete when not needed from remote

-9

Просто використовуйте Dropbox, як це зробив цей хлопець. Таким чином, вам не доведеться турбуватися про натискання таємниці, оскільки весь ваш код буде створено резервну копію.

http://blog.sapegin.me/all/github-vs-dropbox


2
Перш ніж у когось буде реакція на коліна, я не говорю використовувати Dropbox замість Github, але зберігати в Dropbox код, який не готовий до вчинення, який все ще знаходиться під місцевим контролем версій.
Технічний інженер NYC

4
знадобиться занадто багато часу, щоб скопіювати весь проект у віддалену хмару.
Став Алфі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.