Am'm conversie totul la Git pentru uzul meu personal și am găsit niște vechi versiuni ale unui fișier deja în depozit. Cum am comis-o la istorie în ordinea corectă în funcție de fișier's "data modificat" deci am o istorie exacte de fișiere?
Mi s-a spus ceva de genul asta ar merge:
git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all
Sfaturile au fost date este eronată. Necondiționat stabilirea GIT_AUTHOR_DATE într-un --env-filtru
ar rescrie de fiecare data a comis-o. De asemenea, ar fi neobișnuit să utilizați git commit în interiorul --index-filtru
.
Ai de-a face cu mai multe, independent de problemele de aici.
Fiecare comiterea a două date: autorul, data și data comiter sau de altcineva. Puteți suprascrie fiecare, prin furnizarea de valori prin variabilele de mediu GIT_AUTHOR_DATE și GIT_COMMITTER_DATE pentru orice comanda care scrie un comis-o. A se vedea "Formate de Dată" în git commit(1) sau de mai jos:
Git internal format = <unix timestamp> <time zone offset>, e.g. 1112926393 +0200
RFC 2822 = e.g. Thu, 07 Apr 2005 22:13:13 +0200
ISO 8601 = e.g. 2005-04-07T22:13:13
Singura comanda pe care scrie un nou comite în timpul utilizării normale este git commit. Ea are, de asemenea, un --data opțiune care vă permite să specificați direct autor data. Anticipat de utilizare include
git filtru-sucursala-env-filtru` utilizează, de asemenea, variabilele de mediu menționate mai sus (acestea sunt o parte din "env", după care opțiunea este numit; a se vedea "Opțiuni" în git-filtru-ramură(1) și de fond al sistemului "sanitare" comanda git-comis-de-copac(1).
Dacă depozitul este foarte simplu (de exemplu, aveți doar o singură sucursală, fără tag-uri), atunci puteți folosi, probabil, git rebazare pentru a face munca.
În următoarele comenzi, de a folosi nume de obiect (SHA-1 hash) a comis-în loc de "O". Nu uitați să utilizați unul dintre "data suprascrie" metode, atunci când tu a alerga git commit.
---A---B---C---o---o---o master
git checkout master
git checkout A~0
git add path/to/file
git commit --date='whenever'
git tag ,new-commit -m'delete me later'
git checkout -
git rebase --onto ,new-commit A
git tag -d ,new-commit
---A---N (was ",new-commit", but we delete the tag)
\
B'---C'---o---o---o master
Dacă ai vrut să O actualizare pentru a include noul fișier (în loc de a crea un nou comite în cazul în care a fost adăugat), apoi utilizați git a comis-o ... amend "în loc de" git commit
. Rezultatul ar arata astfel:
---A'---B'---C'---o---o---o master
Cele de mai sus funcționează atâta timp cât poți numele comite care ar trebui să fie mamă de noua ta a comis-o. Daca vrei ca noul fișier să fie adăugate printr-o nouă rădăcină comite (fără părinți), atunci ai nevoie de ceva un pic diferit:
B---C---o---o---o master
git checkout master
git checkout --orphan new-root
git rm -rf .
git add path/to/file
GIT_AUTHOR_DATE='whenever' git commit
git checkout -
git rebase --root --onto new-root
git branch -d new-root
N (was new-root, but we deleted it)
\
B'---C'---o---o---o master
git checkout, orfan
este relativ nou (Git 1.7.2), dar există și alte modalități de a face același lucru](https://git.wiki.kernel.org/index.php/GitTips#How_to_create_a_new_branch_that_has_no_ancestor), care funcționează pe versiuni mai vechi de Git.
Dacă depozitul este mult mai complex (de exemplu, are mai mult de unul ref (sucursale, tag-uri, etc.)), atunci probabil că va trebui să utilizați git filtru-filiala. Înainte de a utiliza git filtru-filiala, tu ar trebui să facă o copie de rezervă a întregului depozit. Un simplu tar arhiva intreaga de lucru brad (inclusiv .git director) este suficientă. git filtru-filiala nu face backup arbitrii, dar este de multe ori mai ușor pentru a recupera de la un nu-chiar-chiar de filtrare doar prin ștergerea .git
director și restaurarea de backup.
Notă: exemplele De mai jos utilizarea la nivel inferior comanda git update-index-adăugați "în loc de" git add
. Ai putea folosi git add, dar ar trebui mai întâi să copiați fișiere din locații externe preconizate calea (--index-filtru
ruleaza comanda acestuia într-o temporar GIT_WORK_TREE care este gol).
Dacă doriți ca noul fișier să fie adăugate la fiecare existent se angajeze, atunci puteți face acest lucru:
new_file=$(git hash-object -w path/to/file)
git filter-branch \
--index-filter \
'git update-index --add --cacheinfo 100644 '"$new_file"' path/to/file' \
--tag-name-filter cat \
-- --all
git reset --hard
Eu nu prea văd nici un motiv pentru a modifica datele existente se angajează cu --env-filtru 'GIT_AUTHOR_DATE=...'
. Dacă ai folosi-o, ar fi condiționată, astfel că ar rescrie data pentru fiecare a comis-o.
Dacă doriți ca noul fișier să apară numai în se angajează ca, după unele existente se angajeze ("O"), atunci puteți face acest lucru:
file_path=path/to/file
before_commit=$(git rev-parse --verify A)
file_blob=$(git hash-object -w "$file_path")
git filter-branch \
--index-filter '
if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$before_commit"') &&
test -n "$x"; then
git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
fi
' \
--tag-name-filter cat \
-- --all
git reset --hard
Dacă doriți ca fișierul să fie adăugate printr-o nouă comite că este de a fi introdus în mijlocul de istorie, atunci veți avea nevoie pentru a genera noul comite înainte de a utiliza git filtru-filiala și adăugați - --părinte-filtru
de a git filtru-filiala:
file_path=path/to/file
before_commit=$(git rev-parse --verify A)
git checkout master
git checkout "$before_commit"
git add "$file_path"
git commit --date='whenever'
new_commit=$(git rev-parse --verify HEAD)
file_blob=$(git rev-parse --verify HEAD:"$file_path")
git checkout -
git filter-branch \
--parent-filter "sed -e s/$before_commit/$new_commit/g" \
--index-filter '
if x=$(git rev-list -1 "$GIT_COMMIT" --not '"$new_commit"') &&
test -n "$x"; then
git update-index --add --cacheinfo 100644 '"$file_blob $file_path"'
fi
' \
--tag-name-filter cat \
-- --all
git reset --hard
Ai putea aranja, de asemenea, pentru ca fișierul să fie în primul rând a adăugat într-o nouă rădăcină comite: a crea noua rădăcină comite prin intermediul "orfan" metoda de git rebazare secțiunea (captura în new_commit
), folosi necondiționată --index-filtru
, și --părinte-filtru " ca " "sed -e \ \ "s/^$/-p $new_commit/\""
.
Puteți crea comite, ca de obicei, dar atunci când ai comis-o, a seta variabilele de mediu GIT_AUTHOR_DATE " și " GIT_COMMITTER_DATE
a corespunzătoare datetimes.
Desigur, acest lucru va face comis la vârful filialei (de exemplu, în fața actualului ȘEF comite). Dacă doriți să-l împing mai departe în repo, trebuie să obțineți un pic de fantezie. Las's spune că ai această istorie:
o--o--o--o--o
Și nu vrei ca noua ta comite (marcat ca "X"), care să apară în al doilea rând**:
o--X--o--o--o--o
Cel mai simplu mod ar fi să sucursala din primul comite, adăuga noi comis-o, apoi rebazare toate celelalte se angajează pe partea de sus a unul nou. Astfel:
$ git checkout -b new_commit $desired_parent_of_new_commit
$ git add new_file
$ GIT_AUTHOR_DATE='your date' GIT_COMMITTER_DATE='your date' git commit -m 'new (old) files'
$ git checkout master
$ git rebase new_commit
$ git branch -d new_commit
În cazul meu, de-a lungul timpului am salvat o gramada de versiuni de myfile ca myfile_bak, myfile_old, myfile_2010, backup/myfile etc. Am vrut să pun myfile's istorie in git folosind modificarea lor întâlniri. Astfel redenumi mai vechi pentru a myfile, git add myfile
, apoi git commit-data=(modificarea datei de la ls-l) myfile
, redenumi lângă cel mai vechi la myfile, un alt git commit cu ... data, repet...
Pentru a automatiza acest lucru oarecum, puteți utiliza shell-foo pentru a obține timpul de modificare a fișierului. Am început cu ls-l
și taie
, dar imediat(1) este mai directă
git commit-data="`stat-c %y myfile`" myfile
Următoarele este ceea ce am folosi pentru a comite modificările pe foo
N =1
zile în trecut:
git add foo
git commit -m "Update foo"
git commit --amend --date="$(date -v-1d)"
Dacă doriți să se angajeze la o dată mai veche, sa zicem 3 zile, doar schimba "data" argument: data -v-3d
.
Ca's foarte util atunci când ai uitat să comită ceva ieri, de exemplu.
UPDATE: --data acceptă, de asemenea, expresii cum ar fi
- data "3 zile în urmă" "sau chiar" --data "ieri"`. Deci putem reduce la o linie de comandă:
git add foo ; git commit --date "yesterday" -m "Update"
În cazul meu, în timp ce folosind-data opțiune, mi git procesul s-a prăbușit. Poate am făcut ceva groaznic. Și, ca rezultat, unele index.fișierul de blocare a apărut. Așa că am șters manual .blocare fișiere .git dosar și executat, pentru toate fișierele modificate pentru a fi angajat în trecut datele și a mers de data asta. Multumesc pentru toate raspunsurile aici.
git commit --date="`date --date='2 day ago'`" -am "update"
Pentru a face o comite, care se pare că a fost făcut în trecut, trebuie să setați ambele GIT_AUTHOR_DATE " și " GIT_COMMITTER_DATE
:
GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '...'
unde data -d'...'
poate fi data exacta ca 2019-01-01 12:00:00
sau relativă ca acum 5 luni si 24 zile în urmă`.
Pentru a vedea ambele date in git log utilizare:
git log --pretty=fuller
Acest lucru, de asemenea, funcționează pentru îmbinare se angajează:
GIT_AUTHOR_DATE=$(date -d'...') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git merge <branchname> --no-ff