Standing and cleaning of Git tool series

Posted by Syranide on Sun, 19 Dec 2021 09:38:55 +0100

Often, our development work focuses on a certain part of the project, and all kinds of things are still in chaos. At this time, you want to switch branches to do other things. The problem is that the current work has not been completed and cannot be submitted to the local or remote warehouse. You have to switch back to this state and continue to work later. The solution to this problem is to use the "git stash" command.

Staging takes the dirty state of the working directory, that is, the modified tracked files and staged changes.

These unfinished changes are saved to a stack, which you can restore at any time, not limited to a specific branch.

Use this command to save the contents of the current working directory modification and index, and return to HEAD commit.

Therefore, the stash command has nothing to do with the commit ted content, whether it is a local or remote warehouse.

You can use the help option to view help information for git stash:

$git stash --help

Stashing Your Work

Let's demonstrate the staging operation. Now you need to enter a project, start working, modify some files, and then make a modification in the stage.

If you execute git status, you will see the current dirty state:

$ 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

Now that you want to switch branches but don't want to commit code, you can stash these changes. Push a new stack in the stack, and execute git stack or git stack push:

$ 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")

Now you can see that your working directory is clean:

$ git status

# On branch master

nothing to commit, working directory clean

Now you can switch branches to do other things. Your changes are saved in the stack. To see what changes you have saved, use git stash list:

$ 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 this example, two stashes have been saved previously. You can operate these three different saved changes.

You can use git stash apply to directly restore your latest stash changes.

If you want to restore the previous changes, you can specify one by name, such as git stash apply stash@{2}.

If you don't specify it, git will restore directly with the latest stash by default:

$ 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")

You will find that your saved changes are restored.

In this case, you perform the restore operation on the working directory of your clean, and this branch is the one you saved the changes before.

However, these two conditions are not necessary. The branch can be switched, and the working directory can also have modified and uncommitted files, which does not affect the execution of apply a stash.

Note that the git stash operation is essentially a temporary commit with a commit id number. Naturally, it also records the changes of the old and new file indexes of each file.

During Git stash apply, if a file in the stash is changed and the file in the working directory is also changed, stash apply or pop cannot be successful.

To git add the files in the working directory to the temporary storage area, or commit.

When git stage applies, the old File Index of a file in the stage should be consistent with the current File Index, so that it can be merge d directly. The File Index of the file should keep changing continuously.

If the old File Index of a file in the stage is consistent with the old File Index of the latest File Index change of the file, auto merge will be executed. It is equivalent to making two modifications based on the same File Index, and then merging the two modifications.

If the old File Index and the latest File Index of a file in the stage are also inconsistent with the previous File Index, Merge Conflict will appear, and you need to merge manually. The same file cannot be merged without an associated modification. At this time, git will display the contents of both versions of the file in the file and tell the user that conflict appears, which needs to be handled manually by the user.

When restoring a modification, if it is a staged modification, it will be rolled back. If you want to retain the staged modification, you need to add the -- index option. In this way, after git stash apply is executed, it will be consistent with the initial state.

In other words, the changes in the working directory and the changes in the index (after git add) will be restored to the changes in the working directory after they are stash, and then apply or pop. If you want to keep the changes in the index from falling back to the index, you need to add this option.

$ 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

Use the apply command to restore the work saved on the stack. The saved modification still exists. To delete the modification from the stack, execute git stack drop:

$ 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)

Another method is to execute git stash pop to restore the change, and then delete the change immediately.

If conflict occurs in git stash pop, the stash will not be deleted automatically. You should manually drop the stash yourself.

Modify the conflict that appears. After the conflict is resolved, perform relevant git operations, such as add, commit, push, etc.

Creative staging (multiple uses)

There are other useful ways to use stash.

The first common option is -- keep index, which is used when using the git stash command.

The purpose of this option is to tell git not to add the content in index to stash.

That is, if you git add (stage) a modified file and then execute git stash -- keep index, the modification will not be stash.

$ 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

Another common function is to include untraceable files when stash. By default, GIT stack only temporarily stores the modified and staged tracked files. If you add the option -- include untracked or - u, GIT stack will also temporarily store the untracked files. However, the ignored files are still not included. To include the ignored files, you need to use the option -- all (or - 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

$

Finally, if you use the -- patch tag, git stash will not temporarily store anything, but enter an interactive mode, allowing you to choose which changes to temporarily store and which changes to continue to be kept in the working directory.

$ 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

Creating a Branch from a Stash

After modifying the local stash, sometimes merge conflict will appear in pop, which is a bad news. In order to avoid this situation, we'd better restore to the environment when the stash was created.

You can use git stash branch < new branch name >, directly create a new branch according to the current state, and then automatically execute git stash pop.

$ git stash branch <branchname> [<stash>]

Create and check out a new branch based on the commit ID created by the specified stash. If you do not specify a stash, apply the latest stash and drop it.

And keep the current stash reflog, that is, other stash are still there, except that a specified or latest one is applied and drop ped.

$ 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)

Cleaning your Working Directory

The git stash command explained above is used to save the changes you want to keep. But in another case, there is a possibility that you want to clear all changes and return to the HEAD state.

What should I do? Use git clean.

In Git warehouse, there may be various operations, such as code merge, external tools to modify files, and intermediate files generated during compilation.

Using Git clean, you can delete files that do not belong to Git warehouse and are not tracked.

$ git clean -f -d 

-The f option means "force", "really do this". If in git configuration, clean Requireforce. If this is true, git clean must bring - F to operate.

-The d option indicates traversal of the folder.

If you are not confident about the clean operation, you can also try to see which files will be deleted first. You can add the option -- dry run or - n.

$ git clean -d -n

Would remove test.o

Would remove tmp/

By default, git clean # only deletes untracked files, not ignored files.

If you want to delete these files that are not added to git, such as those in the compilation process o file, you need to add the - x option.

$ 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/

In addition to - f direct deletion, - n shows the deletion, and - i option, which is an interactive flag.

$ 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>

In this way, each file will be confirmed separately, and the user will confirm what operation to select.

other

Detailed description of stage push

Store the local changes in a new stash entry, and then roll back the current state to HEAD, including those in working tree and index.

$ git stash push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]

-p is hunk by hunk to confirm whether it is a stage. What are the tips for each letter? Can be displayed.

     Interactively,index state. Similar to git add --patch

-a is the file containing ingnore

--This is followed by the file or path that needs stash. The new stash entry records the modified states only for the files that match the pathspec.

-q

quiet,suppress feedback messages.

--pathspec-from-file=<file>

Specify a file as pathspec input. Use lf or CR/LF separation.

Stash storage:

After git stash, there is a commit id, and the latest one is stored in refs/stash

$ cat  .git/refs/stash

dbda2ec3a585c5be99500c021d8a0d564a1f3dce

If multiple stash operations are performed, the old stash exists in logs:

$ cat  .git/logs/refs/stash
0000000000000000000000000000000000000000 456a5762e3e30dba7604d7bf49ea7e36c88a6575 username <user@abc.com> 1616053132 +0800    WIP on lark_tmp: 7838a408c Change illumination to less bright
456a5762e3e30dba7604d7bf49ea7e36c88a6575 ce59c24b9fa358e5fc885333e7af64eed7f10177 username <user@abc.com> 1616053150 +0800    WIP on lark_tmp: 7838a408c Change illumination to less bright

A stash entry indicates a commit that records the state of the working tree. The commit tree records the status of the working directory.

see

You can use git stash show to view the details:

$ git stash show

CMakeLists.txt                                     |    5 +-

libs/BT_Stack/CMakeLists.txt                       |   14 -

libs/BT_Stack/ReleaseNote.txt                      |   96 --

libs/BT_Stack/include/addflags.h                   |  493 -------

libs/BT_Stack/include/blueapi.h                    | 1383 --------------------
$ git stash show [<diff-options>] [<stash>]

git stash show -p stash@{1}

diffstat is displayed by default. Several files have been modified and changed (including insertion and deletion).

Added - p to display specific content.

option is what the git diff command can use.

There are several stash entries:

$ git stash list [<log-options>]

You can use:

git stash list -2, Show the last two stash of entry. 

Meaning of Stash operation

Pulling into a dirty tree.

You are halfway through your work. When upstream changes, it may be related to what you do. When your local modifications do not conflict with the upstream, just pull directly, so you can move forward.

But in case of conflict, git pull will refuse to overwrite your changes. In this way, you can stage, then pull, and then un stash.

Interrupted workflow

You can save it halfway. Commit without switching branches.

Delete stash

$ git stash pop [--index] [-q|--quiet] [<stash>]

Delete a separate staging state and apply it to the current work tree state.

It is the reverse operation of git stash push.

--Index indicates that the file status in index is reserved.

The stash parameter is not specified. The default is stash@{0}. Use stash @ {< revision >}

If a conflict occurs during recovery, you need to manually handle the conflict, and then manually git stash drop to delete the stash.

$ git stash clear

Delete all stash.

$ git stash drop [-q|--quiet] [<stash>]

Remove a single stash entry from the list of stash entries. 

Delete a stash. If not specified, delete the latest.

Note:

1. git stash save is not recommended. It is recommended to use git stash push.

Because the push command can be followed by path / file parameters, which is not supported by the save command.

2. Git stash without parameters is equivalent to git stash push

3 . Restore a stash:

#git stash apply / / apply but not delete

#git stash pop / / apply and delete

However, the pop command can only use git stash temporary stash, but apply can use various commit s, such as git stash push and git stash create.

4. Stash's name: WIP on branchname

WIP: work-in-progress

5. stash@{0} is newly created, and 1 is the previous one.

Therefore, the serial number can be used to reference stash. For example, the serial number n is stash@{n}

reference resources:

https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning

https://git-scm.com/docs/git-stash

Topics: IDE