Chapters ▾ 2nd Edition

7.3 Git Tools - Bêre en Skoonmaak (Stashing and Cleaning)

Bêre en Skoonmaak (Stashing and Cleaning)

Dikwels, wanneer jy aan 'n deel van jou projek gewerk het, is dinge in 'n morsige toestand en wil jy vir 'n rukkie takke wissel om aan iets anders te werk. Die probleem is, jy wil nie 'n vaslegging (commit) van halfklaar werk doen net sodat jy later na hierdie punt kan terugkeer nie. Die antwoord op hierdie probleem is die git stash opdrag.

Om te bêre (stashing) neem die vuil toestand van jou werkgids — dit is jou gewysigde opgespoorde lêers en voorbereide (staged) veranderings — en stoor dit op 'n stapel van onvoltooide veranderings wat jy te eniger tyd weer kan toepas (selfs op 'n ander tak).

Note
Migreer na git stash push

Vanaf laat Oktober 2017 was daar uitgebreide bespreking op die Git-poslys, waarin die opdrag git stash save uitgefaseer (deprecated) word ten gunste van die bestaande alternatief git stash push. Die hoofrede hiervoor is dat git stash push die opsie instel om geselekteerde padspesifikasies (pathspecs) te bêre, iets wat git stash save nie ondersteun nie.

git stash save gaan nie binnekort verdwyn nie, so moenie bekommerd wees dat dit skielik sal wegraak nie. Maar jy sal dalk wil begin oorskakel na die push alternatief vir die nuwe funksionaliteit.

Bêre van Jou Werk (Stashing Your Work)

Om stashing te demonstreer, sal jy in jou projek ingaan en aan 'n paar lêers begin werk en moontlik een van die veranderings voorberei (stage). As jy git status uitvoer, kan jy jou vuil toestand sien:

$ git status
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

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:   lib/simplegit.rb

Nou wil jy takke wissel, maar jy wil nog nie vaslê waaraan jy gewerk het nie, so jy sal die veranderings bêre. Om 'n nuwe stash op jou stapel te plaas (push), voer git stash of git stash push uit:

$ git stash
Saved working directory and index state \
  "WIP on master: 049d078 Create index file"
HEAD is now at 049d078 Create index file
(To restore them type "git stash apply")

Jy kan nou sien dat jou werkgids skoon is:

$ git status
# On branch master
nothing to commit, working directory clean

Op hierdie punt kan jy takke wissel en elders werk doen; jou veranderings word op jou stapel gestoor. Om te sien watter stashes jy gestoor het, kan jy git stash list gebruik:

$ git stash list
stash@{0}: WIP on master: 049d078 Create index file
stash@{1}: WIP on master: c264051 Revert "Add file_size"
stash@{2}: WIP on master: 21d80a5 Add number to log

In hierdie geval is twee stashes voorheen gestoor, so jy het toegang tot drie verskillende gebêrede werke. Jy kan die een wat jy so pas gebêre het weer toepas deur die opdrag te gebruik wat in die hulpafvoer van die oorspronklike stash-opdrag gewys word: git stash apply. As jy een van die ouer stashes wil toepas, kan jy dit spesifiseer deur dit te benoem, soos volg: git stash apply stash@{2}. As jy nie 'n stash spesifiseer nie, neem Git die mees onlangse stash aan en probeer dit toepas:

$ git stash apply
On branch master
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:   index.html
	modified:   lib/simplegit.rb

no changes added to commit (use "git add" and/or "git commit -a")

Jy kan sien dat Git die lêers wat jy teruggerol het toe jy die stash gestoor het, weer wysig. In hierdie geval het jy 'n skoon werkgids gehad toe jy die stash probeer toepas het, en jy het probeer om dit toe te pas op dieselfde tak waarvan jy dit gestoor het. Om 'n skoon werkgids te hê en dit op dieselfde tak toe te pas, is nie nodig om 'n stash suksesvol toe te pas nie. Jy kan 'n stash op een tak stoor, later na 'n ander tak oorskakel, en probeer om die veranderings weer toe te pas. Jy kan ook gewysigde en onvasgelegde lêers in jou werkgids hê wanneer jy 'n stash toepas — Git gee jou saamsmeltingskonflikte as enigiets nie meer skoon toepas nie.

Die veranderings aan jou lêers is weer toegepas, maar die lêer wat jy vantevore voorberei (staged) het, is nie weer voorberei nie. Om dit te doen, moet jy die git stash apply opdrag met 'n --index opsie uitvoer om die opdrag te beveel om die voorbereide veranderings weer te probeer toepas. As jy dit in plaas daarvan uitgevoer het, sou jy terug by jou oorspronklike posisie gewees het:

$ git stash apply --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

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:   lib/simplegit.rb

Die apply opsie probeer slegs om die gebêrede werk toe te pas — jy behou dit steeds op jou stapel. Om dit te verwyder, kan jy git stash drop uitvoer met die naam van die stash om te verwyder:

$ git stash list
stash@{0}: WIP on master: 049d078 Create index file
stash@{1}: WIP on master: c264051 Revert "Add file_size"
stash@{2}: WIP on master: 21d80a5 Add number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

Jy kan ook git stash pop uitvoer om die stash toe te pas en dit dan dadelik van jou stapel af te gooi (drop).

Kreatiewe Stashing (Creative Stashing)

Daar is 'n paar stash-variante wat ook nuttig kan wees. Die eerste opsie wat redelik gewild is, is die --keep-index opsie van die git stash opdrag. Dit sê vir Git om nie net alle voorbereide inhoud in te sluit by die stash wat geskep word nie, maar dit terselfdertyd in die indeks te laat.

$ git status -s
M  index.html
 M lib/simplegit.rb

$ git stash --keep-index
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
M  index.html

Nog 'n algemene ding wat jy dalk met stash wil doen, is om sowel die onopgespoorde (untracked) lêers as die opgespoordes te bêre. By verstek sal git stash slegs gewysigde en voorbereide opgespoorde lêers bêre. As jy --include-untracked of -u spesifiseer, sal Git onopgespoorde lêers insluit in die stash wat geskep word. Die insluiting van onopgespoorde lêers in die stash sal egter steeds nie eksplisiet geïgnoreerde lêers insluit nie; om addisioneel geïgnoreerde lêers in te sluit, gebruik --all (of net -a).

$ git status -s
M  index.html
 M lib/simplegit.rb
?? new-file.txt

$ git stash -u
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
$

Laastens, as jy die --patch vlag spesifiseer, sal Git nie alles wat gewysig is bêre nie, maar sal jou in plaas daarvan interaktief vra watter van die veranderings jy wil bêre en watter jy in jou werkgids wil hou.

$ git stash --patch
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 66d332e..8bb5674 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -16,6 +16,10 @@ class SimpleGit
          return `#{git_cmd} 2>&1`.chomp
        end
      end
+
+    def show(treeish = 'master')
+      command("git show #{treeish}")
+    end

 end
 test
Stash this hunk [y,n,q,a,d,/,e,?]? y

Saved working directory and index state WIP on master: 1b65b17 added the index file

Skep van 'n Tak vanuit 'n Stash (Creating a Branch from a Stash)

As jy 'n bietjie werk bêre, dit vir 'n rukkie daar laat, en voortgaan op die tak waaruit jy die werk gebêre het, kan jy 'n probleem hê om die werk weer toe te pas. As die toepassing (apply) 'n lêer probeer wysig wat jy sedertdien gewysig het, sal jy 'n saamsmeltingskonflik kry en dit moet probeer oplos. As jy 'n makliker manier wil hê om die gebêrede veranderings weer te toets, kan jy git stash branch <nuwe taknaam> uitvoer, wat vir jou 'n nuwe tak skep met jou gekose taknaam, die vaslegging uittrek waarop jy was toe jy jou werk gebêre het, jou werk daar weer toepas, en dan die stash afgooi as dit suksesvol toepas:

$ git stash branch testchanges
M	index.html
M	lib/simplegit.rb
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

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:   lib/simplegit.rb

Dropped refs/stash@{0} (29d385a81d163dfd45a452a2ce816487a6b8b014)

Dit is 'n oulike kortpad om gebêrede werk maklik te herwin en daaraan in 'n nuwe tak te werk.

Skoonmaak van jou Werkgids (Cleaning your Working Directory)

Laastens wil jy dalk nie sekere werk of lêers in jou werkgids bêre nie, maar bloot daarvan ontslae raak; dit is waarvoor die git clean opdrag is.

Sommige algemene redes vir die skoonmaak van jou werkgids kan wees om rommel (cruft) te verwyder wat deur saamsmeltings of eksterne gereedskap gegenereer is, of om bou-artefakte te verwyder ten einde 'n skoon bou (clean build) te doen.

Jy sal redelik versigtig met hierdie opdrag wil wees, aangesien dit ontwerp is om lêers uit jou werkgids te verwyder wat nie opgespoor (tracked) word nie. As jy van plan verander, is daar dikwels geen manier om die inhoud van daardie lêers te herwin nie. 'n Veiliger opsie is om git stash --all uit te voer om alles te verwyder, maar dit in 'n stash te stoor.

As ons aanneem jy wil wel rommel-lêers verwyder of jou werkgids skoonmaak, kan jy dit doen met git clean. Om al die onopgespoorde lêers in jou werkgids te verwyder, kan jy git clean -f -d uitvoer, wat enige lêers sowel as enige subgidse wat gevolglik leeg word, verwyder. Die -f beteken 'force' of “doen dit regtig,” en word vereis as die Git konfigurasieveranderlike clean.requireForce nie eksplisiet op vals (false) gestel is nie.

As jy ooit wil sien wat dit sou doen, kan jy die opdrag met die --dry-run (of -n) opsie uitvoer, wat beteken “doen 'n droë loop (dry run) en vertel my wat jy sou verwyder het”.

$ git clean -d -n
Would remove test.o
Would remove tmp/

By verstek sal die git clean opdrag slegs onopgespoorde lêers verwyder wat nie geïgnoreer word nie. Enige lêer wat ooreenstem met 'n patroon in jou .gitignore of ander ignoreer-lêers, sal nie verwyder word nie. As jy daardie lêers ook wil verwyder, byvoorbeeld om alle .o lêers wat van 'n bou gegenereer is te verwyder sodat jy 'n ten volle skoon bou kan doen, kan jy 'n -x by die clean opdrag voeg.

$ git status -s
 M lib/simplegit.rb
?? build.TMP
?? tmp/

$ git clean -n -d
Would remove build.TMP
Would remove tmp/

$ git clean -n -d -x
Would remove build.TMP
Would remove test.o
Would remove tmp/

As jy nie weet wat die git clean opdrag gaan doen nie, voer dit altyd eers met 'n -n uit om dubbel seker te maak voordat jy die -n na 'n -f verander en dit vir regtig doen. Die ander manier waarop jy versigtig kan wees oor die proses, is om dit met die -i of “interactive” vlag uit te voer.

Dit sal die clean opdrag in 'n interaktiewe modus uitvoer.

$ git clean -x -i
Would remove the following items:
  build.TMP  test.o
*** Commands ***
    1: clean                2: filter by pattern    3: select by numbers    4: ask each             5: quit
    6: help
What now>

Op hierdie manier kan jy individueel deur elke lêer stap of patrone vir verwydering interaktief spesifiseer.

Note

Daar is 'n eienaardige situasie waar jy dalk ekstra kragdadig moet wees wanneer jy Git vra om jou werkgids skoon te maak. As jy toevallig in 'n werkgids is waaronder jy ander Git-bewaarplekke gekopieer of gekloon het (miskien as submodules), sal selfs git clean -fd weier om daardie gidse uit te vee. In sulke gevalle moet jy 'n tweede -f opsie vir klem byvoeg.